Added SILC Public Key version 2 support (V= identifier support).
[silc.git] / lib / silccrypt / silcpk.c
1 /*
2
3   silcpk.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silc.h"
21 #include "silcpk_i.h"
22
23 /****************************** Key generation *******************************/
24
25 /* Generate new SILC key pair. */
26
27 SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
28                                      SilcUInt32 bits_key_len,
29                                      const char *identifier,
30                                      SilcRng rng,
31                                      SilcPublicKey *ret_public_key,
32                                      SilcPrivateKey *ret_private_key)
33 {
34   SilcSILCPublicKey pubkey;
35   SilcSILCPrivateKey privkey;
36   const SilcPKCSAlgorithm *alg;
37   const SilcPKCSObject *pkcs;
38   SilcUInt32 version;
39
40   SILC_LOG_DEBUG(("Generating SILC %s key pair with key length %d bits",
41                   algorithm, bits_key_len));
42
43   if (!rng)
44     return FALSE;
45
46   pkcs = silc_pkcs_find_pkcs(SILC_PKCS_SILC);
47   if (!pkcs)
48     return FALSE;
49
50   /* Allocate SILC public key */
51   pubkey = silc_calloc(1, sizeof(*pubkey));
52   if (!pubkey)
53     return FALSE;
54
55   /* Decode identifier */
56   if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier))
57     return FALSE;
58
59   if (pubkey->identifier.version && atoi(pubkey->identifier.version) >= 2)
60     version = 2;
61   else
62     version = 1;
63
64   /* Allocate algorithm */
65   alg = silc_pkcs_find_algorithm(algorithm, (version == 1 ? "pkcs1-no-oid" :
66                                              "pkcs1"));
67   if (!alg) {
68     silc_free(pubkey);
69     return FALSE;
70   }
71   pubkey->pkcs = alg;
72
73   /* Allocate SILC private key */
74   privkey = silc_calloc(1, sizeof(*privkey));
75   if (!privkey) {
76     silc_free(pubkey);
77     return FALSE;
78   }
79   privkey->pkcs = alg;
80
81   /* Allocate public key */
82   *ret_public_key = silc_calloc(1, sizeof(**ret_public_key));
83   if (!(*ret_public_key)) {
84     silc_free(pubkey);
85     silc_free(privkey);
86     return FALSE;
87   }
88   (*ret_public_key)->pkcs = pkcs;
89   (*ret_public_key)->public_key = pubkey;
90
91   /* Allocate private key */
92   *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
93   if (!(*ret_private_key)) {
94     silc_free(pubkey);
95     silc_free(privkey);
96     silc_free(*ret_public_key);
97     return FALSE;
98   }
99   (*ret_private_key)->pkcs = pkcs;
100   (*ret_private_key)->private_key = privkey;
101
102   /* Generate the algorithm key pair */
103   if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key,
104                          &privkey->private_key)) {
105     silc_free(pubkey);
106     silc_free(privkey);
107     silc_free(*ret_public_key);
108     silc_free(*ret_private_key);
109     return FALSE;
110   }
111
112   return TRUE;
113 }
114
115
116 /**************************** Utility functions ******************************/
117
118 /* Decodes the provided `identifier' */
119
120 SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
121                                           SilcPublicKeyIdentifier ident)
122 {
123   char *cp, *item;
124   int len;
125
126   /* Protocol says that at least UN and HN must be provided as identifier */
127   if (!strstr(identifier, "UN=") && !strstr(identifier, "HN=")) {
128     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
129                     "identifiers"));
130     return FALSE;
131   }
132
133   cp = (char *)identifier;
134   while (cp) {
135     len = strcspn(cp, ",");
136     if (len < 1) {
137       cp = NULL;
138       break;
139     }
140     if (len - 1 >= 0 && cp[len - 1] == '\\') {
141       while (cp) {
142         if (len + 1 > strlen(cp)) {
143           cp = NULL;
144           break;
145         }
146         cp += len + 1;
147         len = strcspn(cp, ",") + len;
148         if (len < 1) {
149           cp = NULL;
150           break;
151         }
152         if (len - 1 >= 0 && cp[len - 1] != '\\')
153           break;
154       }
155     }
156
157     if (!cp)
158       break;
159
160     item = silc_calloc(len + 1, sizeof(char));
161     if (!item)
162       return FALSE;
163     if (len > strlen(cp))
164       break;
165     memcpy(item, cp, len);
166
167     if (strstr(item, "UN="))
168       ident->username = strdup(item + strcspn(cp, "=") + 1);
169     else if (strstr(item, "HN="))
170       ident->host = strdup(item + strcspn(cp, "=") + 1);
171     else if (strstr(item, "RN="))
172       ident->realname = strdup(item + strcspn(cp, "=") + 1);
173     else if (strstr(item, "E="))
174       ident->email = strdup(item + strcspn(cp, "=") + 1);
175     else if (strstr(item, "O="))
176       ident->org = strdup(item + strcspn(cp, "=") + 1);
177     else if (strstr(item, "C="))
178       ident->country = strdup(item + strcspn(cp, "=") + 1);
179     else if (strstr(item, "V="))
180       ident->version = strdup(item + strcspn(cp, "=") + 1);
181
182     cp += len;
183     if (strlen(cp) < 1)
184       cp = NULL;
185     else
186       cp += 1;
187
188     if (item)
189       silc_free(item);
190   }
191
192   return TRUE;
193 }
194
195 /* Encodes and returns SILC public key identifier.  If some of the
196    arguments is NULL those are not encoded into the identifier string.
197    Protocol says that at least username and host must be provided. */
198
199 char *silc_pkcs_silc_encode_identifier(char *username, char *host,
200                                        char *realname, char *email,
201                                        char *org, char *country,
202                                        char *version)
203 {
204   SilcBufferStruct buf;
205   char *identifier;
206
207   if (!username || !host)
208     return NULL;
209   if (strlen(username) < 3 || strlen(host) < 3)
210     return NULL;
211
212   memset(&buf, 0, sizeof(buf));
213
214   if (username)
215     silc_buffer_format(&buf,
216                        SILC_STR_ADVANCE,
217                        SILC_STR_UI32_STRING("UN="),
218                        SILC_STR_UI32_STRING(username),
219                        SILC_STR_END);
220
221   if (host)
222     silc_buffer_format(&buf,
223                        SILC_STR_ADVANCE,
224                        SILC_STR_UI32_STRING(", "),
225                        SILC_STR_UI32_STRING("HN="),
226                        SILC_STR_UI32_STRING(host),
227                        SILC_STR_END);
228
229   if (realname)
230     silc_buffer_format(&buf,
231                        SILC_STR_ADVANCE,
232                        SILC_STR_UI32_STRING(", "),
233                        SILC_STR_UI32_STRING("RN="),
234                        SILC_STR_UI32_STRING(realname),
235                        SILC_STR_END);
236
237   if (email)
238     silc_buffer_format(&buf,
239                        SILC_STR_ADVANCE,
240                        SILC_STR_UI32_STRING(", "),
241                        SILC_STR_UI32_STRING("E="),
242                        SILC_STR_UI32_STRING(email),
243                        SILC_STR_END);
244
245   if (org)
246     silc_buffer_format(&buf,
247                        SILC_STR_ADVANCE,
248                        SILC_STR_UI32_STRING(", "),
249                        SILC_STR_UI32_STRING("O="),
250                        SILC_STR_UI32_STRING(org),
251                        SILC_STR_END);
252
253   if (country)
254     silc_buffer_format(&buf,
255                        SILC_STR_ADVANCE,
256                        SILC_STR_UI32_STRING(", "),
257                        SILC_STR_UI32_STRING("C="),
258                        SILC_STR_UI32_STRING(country),
259                        SILC_STR_END);
260
261   if (version) {
262     if (strlen(version) > 1 || !isdigit(version[0])) {
263       silc_buffer_purge(&buf);
264       return NULL;
265     }
266     silc_buffer_format(&buf,
267                        SILC_STR_ADVANCE,
268                        SILC_STR_UI32_STRING(", "),
269                        SILC_STR_UI32_STRING("V="),
270                        SILC_STR_UI32_STRING(version),
271                        SILC_STR_END);
272   }
273
274   silc_buffer_format(&buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
275
276   identifier = silc_buffer_steal(&buf, NULL);
277   return identifier;
278 }
279
280 /* Return SILC public key version */
281
282 int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
283 {
284   SilcSILCPublicKey silc_pubkey;
285
286   if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
287     return -1;
288
289   silc_pubkey = public_key->public_key;
290
291   /* If version identifire is not present it is version 1. */
292   if (!silc_pubkey->identifier.version)
293     return 1;
294
295   return atoi(silc_pubkey->identifier.version);
296 }
297
298 /*************************** Public key routines *****************************/
299
300 /* Returns PKCS algorithm context */
301
302 const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
303 {
304   SilcSILCPublicKey silc_pubkey = public_key;
305   return silc_pubkey->pkcs;
306 }
307
308 /* Imports SILC protocol style public key from SILC public key file */
309
310 SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
311                                                SilcUInt32 filedata_len,
312                                                SilcPKCSFileEncoding encoding,
313                                                void **ret_public_key)
314 {
315   SilcUInt32 i, len;
316   unsigned char *data = NULL;
317   int ret;
318
319   SILC_LOG_DEBUG(("Parsing SILC public key file"));
320
321   if (!ret_public_key)
322     return FALSE;
323
324   /* Check start of file and remove header from the data. */
325   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
326   if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END))
327     return FALSE;
328   for (i = 0; i < len; i++) {
329     if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i])
330       return FALSE;
331     filedata++;
332   }
333   filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
334                    strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
335
336   switch (encoding) {
337   case SILC_PKCS_FILE_BIN:
338     break;
339
340   case SILC_PKCS_FILE_BASE64:
341     data = silc_base64_decode(filedata, filedata_len, &filedata_len);
342     if (!data)
343       return FALSE;
344     filedata = data;
345     break;
346   }
347
348   ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
349                                          ret_public_key);
350   silc_free(data);
351
352   return ret ? TRUE : FALSE;
353 }
354
355 /* Imports SILC protocol style public key */
356
357 int silc_pkcs_silc_import_public_key(unsigned char *key,
358                                      SilcUInt32 key_len,
359                                      void **ret_public_key)
360 {
361   const SilcPKCSAlgorithm *pkcs;
362   SilcBufferStruct buf, alg_key;
363   SilcSILCPublicKey silc_pubkey = NULL;
364   SilcAsn1 asn1 = NULL;
365   SilcUInt32 totlen, keydata_len;
366   SilcUInt16 pkcs_len, identifier_len;
367   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
368   int ret;
369
370   SILC_LOG_DEBUG(("Parsing SILC public key"));
371
372   if (!ret_public_key)
373     return 0;
374
375   silc_buffer_set(&buf, key, key_len);
376
377   /* Get length */
378   ret = silc_buffer_unformat(&buf,
379                              SILC_STR_ADVANCE,
380                              SILC_STR_UI_INT(&totlen),
381                              SILC_STR_END);
382   if (ret == -1)
383     goto err;
384
385   /* Backwards compatibility */
386   if (totlen == key_len)
387     totlen -= 4;
388
389   if (totlen + 4 != key_len)
390     goto err;
391
392   /* Get algorithm name and identifier */
393   ret =
394     silc_buffer_unformat(&buf,
395                          SILC_STR_ADVANCE,
396                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
397                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
398                          SILC_STR_END);
399   if (ret == -1)
400     goto err;
401
402   if (pkcs_len < 1 || identifier_len < 3 ||
403       pkcs_len + identifier_len > totlen)
404     goto err;
405
406   /* Get key data */
407   keydata_len = silc_buffer_len(&buf);
408   ret = silc_buffer_unformat(&buf,
409                              SILC_STR_DATA(&key_data, keydata_len),
410                              SILC_STR_END);
411   if (ret == -1)
412     goto err;
413
414   /* Allocate SILC public key context */
415   silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
416   if (!silc_pubkey)
417     goto err;
418
419   /* Decode SILC identifier */
420   if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
421     goto err;
422
423   asn1 = silc_asn1_alloc();
424   if (!asn1)
425     goto err;
426
427   SILC_LOG_DEBUG(("Public key version %s",
428                   (!silc_pubkey->identifier.version ? " 1" :
429                    silc_pubkey->identifier.version)));
430
431   if (!strcmp(pkcs_name, "rsa")) {
432     /* Parse the SILC RSA public key */
433     SilcUInt32 e_len, n_len;
434     SilcMPInt n, e;
435
436     /* Get PKCS object.  Different PKCS #1 scheme is used with different
437        versions. */
438     if (!silc_pubkey->identifier.version ||
439         atoi(silc_pubkey->identifier.version) <= 1) {
440       /* Version 1 */
441       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
442     } else {
443       /* Version 2 and newer */
444       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
445     }
446     if (!pkcs) {
447       SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
448       goto err;
449     }
450     silc_pubkey->pkcs = pkcs;
451
452     if (keydata_len < 4)
453       goto err;
454     SILC_GET32_MSB(e_len, key_data);
455     if (!e_len || e_len + 4 > keydata_len)
456       goto err;
457     silc_mp_init(&e);
458     silc_mp_bin2mp(key_data + 4, e_len, &e);
459     if (keydata_len < 4 + e_len + 4) {
460       silc_mp_uninit(&e);
461       goto err;
462     }
463     SILC_GET32_MSB(n_len, key_data + 4 + e_len);
464     if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
465       silc_mp_uninit(&e);
466       goto err;
467     }
468     silc_mp_init(&n);
469     silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
470
471     /* Encode to PKCS #1 format */
472     memset(&alg_key, 0, sizeof(alg_key));
473     if (!silc_asn1_encode(asn1, &alg_key,
474                           SILC_ASN1_SEQUENCE,
475                             SILC_ASN1_INT(&n),
476                             SILC_ASN1_INT(&e),
477                           SILC_ASN1_END, SILC_ASN1_END)) {
478       silc_mp_uninit(&e);
479       silc_mp_uninit(&n);
480       goto err;
481     }
482
483     silc_mp_uninit(&e);
484     silc_mp_uninit(&n);
485
486   } else if (!strcmp(pkcs_name, "dsa")) {
487     SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
488     goto err;
489
490   } else {
491     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
492     goto err;
493   }
494
495   /* Import PKCS algorithm public key */
496   if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
497                                &silc_pubkey->public_key))
498     goto err;
499
500   silc_free(pkcs_name);
501   silc_free(ident);
502   silc_asn1_free(asn1);
503
504   *ret_public_key = silc_pubkey;
505
506   return key_len;
507
508  err:
509   silc_free(pkcs_name);
510   silc_free(ident);
511   silc_free(silc_pubkey);
512   if (asn1)
513     silc_asn1_free(asn1);
514   return 0;
515 }
516
517 /* Exports public key as SILC protocol style public key file */
518
519 unsigned char *
520 silc_pkcs_silc_export_public_key_file(void *public_key,
521                                       SilcPKCSFileEncoding encoding,
522                                       SilcUInt32 *ret_len)
523 {
524   SilcBuffer buf;
525   unsigned char *key, *data;
526   SilcUInt32 key_len;
527
528   SILC_LOG_DEBUG(("Encoding SILC public key file"));
529
530   /* Export key */
531   key = silc_pkcs_silc_export_public_key(public_key, &key_len);
532   if (!key)
533     return NULL;
534
535   switch (encoding) {
536   case SILC_PKCS_FILE_BIN:
537     break;
538
539   case SILC_PKCS_FILE_BASE64:
540     data = silc_base64_encode_file(key, key_len);
541     if (!data)
542       return NULL;
543     silc_free(key);
544     key = data;
545     key_len = strlen(data);
546     break;
547   }
548
549   /* Encode SILC public key file */
550   buf = silc_buffer_alloc_size(key_len +
551                                (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
552                                 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
553   if (!buf) {
554     silc_free(key);
555     return NULL;
556   }
557
558   if (silc_buffer_format(buf,
559                          SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
560                          SILC_STR_UI_XNSTRING(key, key_len),
561                          SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
562                          SILC_STR_END) < 0) {
563     silc_buffer_free(buf);
564     silc_free(key);
565     return NULL;
566   }
567
568   silc_free(key);
569   key = silc_buffer_steal(buf, ret_len);
570   silc_buffer_free(buf);
571
572   return key;
573 }
574
575 /* Exports public key as SILC protocol style public key */
576
577 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
578                                                 SilcUInt32 *ret_len)
579 {
580   SilcSILCPublicKey silc_pubkey = public_key;
581   const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
582   SilcBufferStruct alg_key;
583   SilcBuffer buf = NULL;
584   SilcAsn1 asn1 = NULL;
585   unsigned char *pk = NULL, *key = NULL, *ret;
586   SilcUInt32 pk_len, key_len, totlen;
587   char *identifier;
588
589   SILC_LOG_DEBUG(("Encoding SILC public key"));
590
591   /* Export PKCS algorithm public key */
592   if (pkcs->export_public_key)
593     pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
594   if (!pk)
595     return NULL;
596   silc_buffer_set(&alg_key, pk, pk_len);
597
598   /* Encode identifier */
599   identifier =
600     silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
601                                      silc_pubkey->identifier.host,
602                                      silc_pubkey->identifier.realname,
603                                      silc_pubkey->identifier.email,
604                                      silc_pubkey->identifier.org,
605                                      silc_pubkey->identifier.country,
606                                      silc_pubkey->identifier.version);
607   if (!identifier)
608     goto err;
609
610   asn1 = silc_asn1_alloc();
611   if (!asn1)
612     goto err;
613
614   if (!strcmp(pkcs->name, "rsa")) {
615     /* Parse the PKCS #1 public key */
616     SilcMPInt n, e;
617     SilcUInt32 n_len, e_len;
618     unsigned char *nb, *eb;
619
620     memset(&n, 0, sizeof(n));
621     memset(&e, 0, sizeof(e));
622     if (!silc_asn1_decode(asn1, &alg_key,
623                           SILC_ASN1_SEQUENCE,
624                             SILC_ASN1_INT(&n),
625                             SILC_ASN1_INT(&e),
626                           SILC_ASN1_END, SILC_ASN1_END))
627       goto err;
628
629     /* Encode to SILC RSA public key */
630     eb = silc_mp_mp2bin(&e, 0, &e_len);
631     if (!eb)
632       goto err;
633     nb = silc_mp_mp2bin(&n, 0, &n_len);
634     if (!nb)
635       goto err;
636     key_len = e_len + 4 + n_len + 4;
637     key = silc_calloc(key_len, sizeof(*key));
638     if (!key)
639       goto err;
640
641     /* Put e length and e */
642     SILC_PUT32_MSB(e_len, key);
643     memcpy(key + 4, eb, e_len);
644
645     /* Put n length and n. */
646     SILC_PUT32_MSB(n_len, key + 4 + e_len);
647     memcpy(key + 4 + e_len + 4, nb, n_len);
648
649     silc_free(nb);
650     silc_free(eb);
651
652   } else if (!strcmp(pkcs->name, "dsa")) {
653     SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
654     goto err;
655
656   } else {
657     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
658     goto err;
659   }
660
661   /* Encode SILC Public Key */
662   totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
663   buf = silc_buffer_alloc_size(totlen + 4);
664   if (!buf)
665     goto err;
666   if (silc_buffer_format(buf,
667                          SILC_STR_UI_INT(totlen),
668                          SILC_STR_UI_SHORT(strlen(pkcs->name)),
669                          SILC_STR_UI32_STRING(pkcs->name),
670                          SILC_STR_UI_SHORT(strlen(identifier)),
671                          SILC_STR_UI32_STRING(identifier),
672                          SILC_STR_UI_XNSTRING(key, key_len),
673                          SILC_STR_END) < 0)
674     goto err;
675
676   ret = silc_buffer_steal(buf, ret_len);
677   silc_buffer_free(buf);
678   silc_free(key);
679   silc_free(identifier);
680   silc_asn1_free(asn1);
681
682   return ret;
683
684  err:
685   silc_free(identifier);
686   silc_free(pk);
687   silc_free(key);
688   if (buf)
689     silc_buffer_free(buf);
690   if (asn1)
691     silc_asn1_free(asn1);
692   return NULL;
693 }
694
695 /* Return key length */
696
697 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
698 {
699   SilcSILCPublicKey silc_pubkey = public_key;
700   return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
701 }
702
703 /* Copy public key */
704
705 void *silc_pkcs_silc_public_key_copy(void *public_key)
706 {
707   SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
708
709   new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
710   if (!new_pubkey)
711     return NULL;
712   new_pubkey->pkcs = silc_pubkey->pkcs;
713
714   new_pubkey->public_key =
715     silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
716   if (!new_pubkey->public_key) {
717     silc_free(new_pubkey);
718     return NULL;
719   }
720
721   return new_pubkey;
722 }
723
724 /* Compares public keys */
725
726 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
727 {
728   SilcSILCPublicKey k1 = key1, k2 = key2;
729
730   if (strcmp(k1->pkcs->name, k2->pkcs->name))
731     return FALSE;
732
733   if ((k1->identifier.username && !k2->identifier.username) ||
734       (!k1->identifier.username && k2->identifier.username) ||
735       (k1->identifier.username && k2->identifier.username &&
736        strcmp(k1->identifier.username, k2->identifier.username)))
737     return FALSE;
738
739   if ((k1->identifier.host && !k2->identifier.host) ||
740       (!k1->identifier.host && k2->identifier.host) ||
741       (k1->identifier.host && k2->identifier.host &&
742        strcmp(k1->identifier.host, k2->identifier.host)))
743     return FALSE;
744
745   if ((k1->identifier.realname && !k2->identifier.realname) ||
746       (!k1->identifier.realname && k2->identifier.realname) ||
747       (k1->identifier.realname && k2->identifier.realname &&
748        strcmp(k1->identifier.realname, k2->identifier.realname)))
749     return FALSE;
750
751   if ((k1->identifier.email && !k2->identifier.email) ||
752       (!k1->identifier.email && k2->identifier.email) ||
753       (k1->identifier.email && k2->identifier.email &&
754        strcmp(k1->identifier.email, k2->identifier.email)))
755     return FALSE;
756
757   if ((k1->identifier.org && !k2->identifier.org) ||
758       (!k1->identifier.org && k2->identifier.org) ||
759       (k1->identifier.org && k2->identifier.org &&
760        strcmp(k1->identifier.org, k2->identifier.org)))
761     return FALSE;
762
763   if ((k1->identifier.country && !k2->identifier.country) ||
764       (!k1->identifier.country && k2->identifier.country) ||
765       (k1->identifier.country && k2->identifier.country &&
766        strcmp(k1->identifier.country, k2->identifier.country)))
767     return FALSE;
768
769   if ((k1->identifier.version && !k2->identifier.version) ||
770       (!k1->identifier.version && k2->identifier.version) ||
771       (k1->identifier.version && k2->identifier.version &&
772        strcmp(k1->identifier.version, k2->identifier.version)))
773     return FALSE;
774
775   return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
776 }
777
778 /* Frees public key */
779
780 void silc_pkcs_silc_public_key_free(void *public_key)
781 {
782   SilcSILCPublicKey silc_pubkey = public_key;
783
784   silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
785
786   silc_free(silc_pubkey->identifier.username);
787   silc_free(silc_pubkey->identifier.host);
788   silc_free(silc_pubkey->identifier.realname);
789   silc_free(silc_pubkey->identifier.email);
790   silc_free(silc_pubkey->identifier.org);
791   silc_free(silc_pubkey->identifier.country);
792   silc_free(silc_pubkey->identifier.version);
793   silc_free(silc_pubkey);
794 }
795
796
797 /*************************** Private key routines ****************************/
798
799 /* Private key file magic */
800 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
801
802 /* Imports SILC implementation style private key file */
803
804 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
805                                                 SilcUInt32 filedata_len,
806                                                 const char *passphrase,
807                                                 SilcUInt32 passphrase_len,
808                                                 SilcPKCSFileEncoding encoding,
809                                                 void **ret_private_key)
810 {
811   SilcCipher aes;
812   SilcHash sha1;
813   SilcHmac sha1hmac;
814   SilcUInt32 blocklen;
815   unsigned char tmp[32], keymat[64], *data = NULL;
816   SilcUInt32 i, len, magic, mac_len;
817   int ret;
818
819   SILC_LOG_DEBUG(("Parsing SILC private key file"));
820
821   /* Check start of file and remove header from the data. */
822   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
823   if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
824     return FALSE;
825   for (i = 0; i < len; i++) {
826     if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
827       return FALSE;
828     filedata++;
829   }
830
831   len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
832                         strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
833
834   switch (encoding) {
835   case SILC_PKCS_FILE_BIN:
836     break;
837
838   case SILC_PKCS_FILE_BASE64:
839     data = silc_base64_decode(filedata, filedata_len, &len);
840     if (!data)
841       return FALSE;
842     filedata = data;
843     break;
844   }
845
846   memset(tmp, 0, sizeof(tmp));
847   memset(keymat, 0, sizeof(keymat));
848
849   /* Check file magic */
850   SILC_GET32_MSB(magic, filedata);
851   if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
852     SILC_LOG_DEBUG(("Private key does not have correct magic"));
853     return FALSE;
854   }
855
856   /* Allocate the AES cipher */
857   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
858     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
859     return FALSE;
860   }
861   blocklen = silc_cipher_get_block_len(aes);
862   if (blocklen * 2 > sizeof(tmp)) {
863     silc_cipher_free(aes);
864     return FALSE;
865   }
866
867   /* Allocate SHA1 hash */
868   if (!silc_hash_alloc("sha1", &sha1)) {
869     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
870     silc_cipher_free(aes);
871     return FALSE;
872   }
873
874   /* Allocate HMAC */
875   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
876     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
877     silc_hash_free(sha1);
878     silc_cipher_free(aes);
879     return FALSE;
880   }
881
882   /* Derive the decryption key from the provided key material.  The key
883      is 256 bits length, and derived by taking hash of the data, then
884      re-hashing the data and the previous digest, and using the first and
885      second digest as the key. */
886   silc_hash_init(sha1);
887   silc_hash_update(sha1, passphrase, passphrase_len);
888   silc_hash_final(sha1, keymat);
889   silc_hash_init(sha1);
890   silc_hash_update(sha1, passphrase, passphrase_len);
891   silc_hash_update(sha1, keymat, 16);
892   silc_hash_final(sha1, keymat + 16);
893
894   /* Set the key to the cipher */
895   silc_cipher_set_key(aes, keymat, 256, FALSE);
896
897   /* First, verify the MAC of the private key data */
898   mac_len = silc_hmac_len(sha1hmac);
899   silc_hmac_init_with_key(sha1hmac, keymat, 16);
900   silc_hmac_update(sha1hmac, filedata, len - mac_len);
901   silc_hmac_final(sha1hmac, tmp, NULL);
902   if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
903     SILC_LOG_DEBUG(("Integrity check for private key failed"));
904     memset(keymat, 0, sizeof(keymat));
905     memset(tmp, 0, sizeof(tmp));
906     silc_hmac_free(sha1hmac);
907     silc_hash_free(sha1);
908     silc_cipher_free(aes);
909     return FALSE;
910   }
911   filedata += 4;
912   len -= 4;
913
914   /* Decrypt the private key buffer */
915   silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
916   SILC_GET32_MSB(i, filedata);
917   if (i > len) {
918     SILC_LOG_DEBUG(("Bad private key length in buffer!"));
919     memset(keymat, 0, sizeof(keymat));
920     memset(tmp, 0, sizeof(tmp));
921     silc_hmac_free(sha1hmac);
922     silc_hash_free(sha1);
923     silc_cipher_free(aes);
924     return FALSE;
925   }
926   filedata += 4;
927   len = i;
928
929   /* Cleanup */
930   memset(keymat, 0, sizeof(keymat));
931   memset(tmp, 0, sizeof(tmp));
932   silc_hmac_free(sha1hmac);
933   silc_hash_free(sha1);
934   silc_cipher_free(aes);
935
936   /* Import the private key */
937   ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
938
939   silc_free(data);
940
941   return ret ? TRUE : FALSE;
942 }
943
944 /* Private key version */
945 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
946 #define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
947
948 /* Imports SILC implementation style private key */
949
950 int silc_pkcs_silc_import_private_key(unsigned char *key,
951                                       SilcUInt32 key_len,
952                                       void **ret_private_key)
953 {
954   SilcBufferStruct buf;
955   const SilcPKCSAlgorithm *pkcs;
956   SilcBufferStruct alg_key;
957   SilcSILCPrivateKey silc_privkey = NULL;
958   SilcAsn1 asn1 = NULL;
959   SilcUInt16 pkcs_len;
960   SilcUInt32 keydata_len;
961   unsigned char *pkcs_name = NULL, *key_data;
962   int ret;
963
964   SILC_LOG_DEBUG(("Parsing SILC private key"));
965
966   if (!ret_private_key)
967     return 0;
968
969   silc_buffer_set(&buf, key, key_len);
970
971   /* Get algorithm name and identifier */
972   ret =
973     silc_buffer_unformat(&buf,
974                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
975                          SILC_STR_END);
976   if (ret == -1) {
977     SILC_LOG_DEBUG(("Cannot decode private key buffer"));
978     goto err;
979   }
980
981   if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
982     SILC_LOG_DEBUG(("Malformed private key buffer"));
983     goto err;
984   }
985
986   /* Get key data. We assume that rest of the buffer is key data. */
987   silc_buffer_pull(&buf, 2 + pkcs_len);
988   keydata_len = silc_buffer_len(&buf);
989   ret = silc_buffer_unformat(&buf,
990                              SILC_STR_UI_XNSTRING(&key_data, keydata_len),
991                              SILC_STR_END);
992   if (ret == -1)
993     goto err;
994
995   /* Allocate SILC private key context */
996   silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
997   if (!silc_privkey)
998     goto err;
999
1000   asn1 = silc_asn1_alloc();
1001   if (!asn1)
1002     goto err;
1003
1004   if (!strcmp(pkcs_name, "rsa")) {
1005     /* Parse the RSA SILC private key */
1006     SilcBufferStruct k;
1007     SilcMPInt n, e, d, dp, dq, qp, p, q;
1008     unsigned char *tmp;
1009     SilcUInt32 len, ver;
1010
1011     if (keydata_len < 4)
1012       goto err;
1013     silc_buffer_set(&k, key_data, keydata_len);
1014
1015     /* Get version.  Key without the version is old style private key
1016        and we need to do some computation to get it to correct format. */
1017     if (silc_buffer_unformat(&k,
1018                              SILC_STR_UI_INT(&ver),
1019                              SILC_STR_END) < 0)
1020       goto err;
1021     silc_buffer_pull(&k, 4);
1022
1023     if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1024         ver != SILC_PRIVATE_KEY_VERSION_2) {
1025       len = ver;
1026       ver = 0;
1027     } else {
1028       if (silc_buffer_unformat(&k,
1029                                SILC_STR_UI_INT(&len),
1030                                SILC_STR_END) < 0)
1031         goto err;
1032       silc_buffer_pull(&k, 4);
1033     }
1034
1035     /* Get PKCS object.  Different PKCS #1 scheme is used with different
1036        versions. */
1037     if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1038       /* Version 0 and 1 */
1039       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1040     } else {
1041       /* Version 2 and newer */
1042       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1043     }
1044     if (!pkcs) {
1045       SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1046       goto err;
1047     }
1048     silc_privkey->pkcs = pkcs;
1049
1050     SILC_LOG_DEBUG(("Private key version %s",
1051                     (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1052                      ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1053
1054     /* Get e */
1055     if (silc_buffer_unformat(&k,
1056                              SILC_STR_DATA(&tmp, len),
1057                              SILC_STR_END) < 0)
1058       goto err;
1059     silc_mp_init(&e);
1060     silc_mp_bin2mp(tmp, len, &e);
1061     silc_buffer_pull(&k, len);
1062
1063     /* Get n */
1064     if (silc_buffer_unformat(&k,
1065                              SILC_STR_UI_INT(&len),
1066                              SILC_STR_END) < 0)
1067       goto err;
1068     silc_buffer_pull(&k, 4);
1069     if (silc_buffer_unformat(&k,
1070                              SILC_STR_DATA(&tmp, len),
1071                              SILC_STR_END) < 0)
1072       goto err;
1073     silc_mp_init(&n);
1074     silc_mp_bin2mp(tmp, len, &n);
1075     silc_buffer_pull(&k, len);
1076
1077     /* Get d */
1078     if (silc_buffer_unformat(&k,
1079                              SILC_STR_UI_INT(&len),
1080                              SILC_STR_END) < 0)
1081       goto err;
1082     silc_buffer_pull(&k, 4);
1083     if (silc_buffer_unformat(&k,
1084                              SILC_STR_DATA(&tmp, len),
1085                              SILC_STR_END) < 0)
1086       goto err;
1087     silc_mp_init(&d);
1088     silc_mp_bin2mp(tmp, len, &d);
1089     silc_buffer_pull(&k, len);
1090
1091     /* Get dP */
1092     if (silc_buffer_unformat(&k,
1093                              SILC_STR_UI_INT(&len),
1094                              SILC_STR_END) < 0)
1095       goto err;
1096     silc_buffer_pull(&k, 4);
1097     if (silc_buffer_unformat(&k,
1098                              SILC_STR_DATA(&tmp, len),
1099                              SILC_STR_END) < 0)
1100       goto err;
1101     silc_mp_init(&dp);
1102     silc_mp_bin2mp(tmp, len, &dp);
1103     silc_buffer_pull(&k, len);
1104
1105     /* Get dQ */
1106     if (silc_buffer_unformat(&k,
1107                              SILC_STR_UI_INT(&len),
1108                              SILC_STR_END) < 0)
1109       goto err;
1110     silc_buffer_pull(&k, 4);
1111     if (silc_buffer_unformat(&k,
1112                              SILC_STR_DATA(&tmp, len),
1113                              SILC_STR_END) < 0)
1114       goto err;
1115     silc_mp_init(&dq);
1116     silc_mp_bin2mp(tmp, len, &dq);
1117     silc_buffer_pull(&k, len);
1118
1119     if (ver == 0) {
1120       /* Old version */
1121
1122       /* Get pQ len */
1123       if (silc_buffer_unformat(&k,
1124                                SILC_STR_UI_INT(&len),
1125                                SILC_STR_END) < 0)
1126         goto err;
1127       silc_buffer_pull(&k, 4);
1128       if (silc_buffer_len(&k) < len)
1129         goto err;
1130       silc_buffer_pull(&k, len);
1131
1132       /* Get qP len */
1133       if (silc_buffer_unformat(&k,
1134                                SILC_STR_UI_INT(&len),
1135                                SILC_STR_END) < 0)
1136         goto err;
1137       silc_buffer_pull(&k, 4);
1138       if (silc_buffer_len(&k) < len)
1139         goto err;
1140       silc_buffer_pull(&k, len);
1141     } else {
1142       /* New version */
1143
1144       /* Get qP */
1145       if (silc_buffer_unformat(&k,
1146                                SILC_STR_UI_INT(&len),
1147                                SILC_STR_END) < 0)
1148         goto err;
1149       silc_buffer_pull(&k, 4);
1150       if (silc_buffer_unformat(&k,
1151                                SILC_STR_DATA(&tmp, len),
1152                                SILC_STR_END) < 0)
1153         goto err;
1154       silc_mp_init(&qp);
1155       silc_mp_bin2mp(tmp, len, &qp);
1156       silc_buffer_pull(&k, len);
1157     }
1158
1159     /* Get p */
1160     if (silc_buffer_unformat(&k,
1161                              SILC_STR_UI_INT(&len),
1162                              SILC_STR_END) < 0)
1163       goto err;
1164     silc_buffer_pull(&k, 4);
1165     if (silc_buffer_unformat(&k,
1166                              SILC_STR_DATA(&tmp, len),
1167                              SILC_STR_END) < 0)
1168       goto err;
1169     silc_mp_init(&p);
1170     silc_mp_bin2mp(tmp, len, &p);
1171     silc_buffer_pull(&k, len);
1172
1173     /* Get q */
1174     if (silc_buffer_unformat(&k,
1175                              SILC_STR_UI_INT(&len),
1176                              SILC_STR_END) < 0)
1177       goto err;
1178     silc_buffer_pull(&k, 4);
1179     if (silc_buffer_unformat(&k,
1180                              SILC_STR_DATA(&tmp, len),
1181                              SILC_STR_END) < 0)
1182       goto err;
1183     silc_mp_init(&q);
1184     silc_mp_bin2mp(tmp, len, &q);
1185     silc_buffer_pull(&k, len);
1186
1187     if (ver == 0) {
1188       /* Old version.  Compute to new version */
1189       SILC_LOG_DEBUG(("Old version private key"));
1190       silc_mp_init(&qp);
1191       silc_mp_modinv(&qp, &q, &p);
1192     }
1193
1194     /* Encode to PKCS #1 format */
1195     memset(&alg_key, 0, sizeof(alg_key));
1196     if (!silc_asn1_encode(asn1, &alg_key,
1197                           SILC_ASN1_SEQUENCE,
1198                             SILC_ASN1_SHORT_INT(0),
1199                             SILC_ASN1_INT(&n),
1200                             SILC_ASN1_INT(&e),
1201                             SILC_ASN1_INT(&d),
1202                             SILC_ASN1_INT(&p),
1203                             SILC_ASN1_INT(&q),
1204                             SILC_ASN1_INT(&dp),
1205                             SILC_ASN1_INT(&dq),
1206                             SILC_ASN1_INT(&qp),
1207                           SILC_ASN1_END, SILC_ASN1_END))
1208       goto err;
1209
1210     silc_mp_uninit(&n);
1211     silc_mp_uninit(&e);
1212     silc_mp_uninit(&e);
1213     silc_mp_uninit(&d);
1214     silc_mp_uninit(&p);
1215     silc_mp_uninit(&q);
1216     silc_mp_uninit(&dp);
1217     silc_mp_uninit(&dq);
1218     silc_mp_uninit(&qp);
1219
1220   } else if (!strcmp(pkcs_name, "dsa")) {
1221     SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1222     goto err;
1223
1224   } else {
1225     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1226     goto err;
1227   }
1228
1229   /* Import PKCS algorithm private key */
1230   if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1231                                 &silc_privkey->private_key))
1232     goto err;
1233
1234   silc_free(pkcs_name);
1235   silc_asn1_free(asn1);
1236
1237   *ret_private_key = silc_privkey;
1238
1239   return key_len;
1240
1241  err:
1242   silc_free(pkcs_name);
1243   silc_free(silc_privkey);
1244   if (asn1)
1245     silc_asn1_free(asn1);
1246   return 0;
1247 }
1248
1249 /* Exports private key as SILC implementation style private key file */
1250
1251 unsigned char *
1252 silc_pkcs_silc_export_private_key_file(void *private_key,
1253                                        const char *passphrase,
1254                                        SilcUInt32 passphrase_len,
1255                                        SilcPKCSFileEncoding encoding,
1256                                        SilcRng rng,
1257                                        SilcUInt32 *ret_len)
1258 {
1259   SilcCipher aes;
1260   SilcHash sha1;
1261   SilcHmac sha1hmac;
1262   SilcBuffer buf, enc;
1263   SilcUInt32 len, blocklen, padlen, key_len;
1264   unsigned char *key, *data;
1265   unsigned char tmp[32], keymat[64];
1266   int i;
1267
1268   SILC_LOG_DEBUG(("Encoding SILC private key file"));
1269
1270   /* Export the private key */
1271   key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1272   if (!key)
1273     return NULL;
1274
1275   memset(tmp, 0, sizeof(tmp));
1276   memset(keymat, 0, sizeof(keymat));
1277
1278   /* Allocate the AES cipher */
1279   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1280     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1281     silc_free(key);
1282     return NULL;
1283   }
1284   blocklen = silc_cipher_get_block_len(aes);
1285   if (blocklen * 2 > sizeof(tmp)) {
1286     silc_cipher_free(aes);
1287     silc_free(key);
1288     return NULL;
1289   }
1290
1291   /* Allocate SHA1 hash */
1292   if (!silc_hash_alloc("sha1", &sha1)) {
1293     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1294     silc_cipher_free(aes);
1295     return NULL;
1296   }
1297
1298   /* Allocate HMAC */
1299   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1300     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1301     silc_hash_free(sha1);
1302     silc_cipher_free(aes);
1303     return NULL;
1304   }
1305
1306   /* Derive the encryption key from the provided key material.  The key
1307      is 256 bits length, and derived by taking hash of the data, then
1308      re-hashing the data and the previous digest, and using the first and
1309      second digest as the key. */
1310   silc_hash_init(sha1);
1311   silc_hash_update(sha1, passphrase, passphrase_len);
1312   silc_hash_final(sha1, keymat);
1313   silc_hash_init(sha1);
1314   silc_hash_update(sha1, passphrase, passphrase_len);
1315   silc_hash_update(sha1, keymat, 16);
1316   silc_hash_final(sha1, keymat + 16);
1317
1318   /* Set the key to the cipher */
1319   silc_cipher_set_key(aes, keymat, 256, TRUE);
1320
1321   /* Encode the buffer to be encrypted.  Add padding to it too, at least
1322      block size of the cipher. */
1323
1324   /* Allocate buffer for encryption */
1325   len = silc_hmac_len(sha1hmac);
1326   padlen = 16 + (16 - ((key_len + 4) % blocklen));
1327   enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1328   if (!enc) {
1329     silc_hmac_free(sha1hmac);
1330     silc_hash_free(sha1);
1331     silc_cipher_free(aes);
1332     return FALSE;
1333   }
1334
1335   /* Generate padding */
1336   for (i = 0; i < padlen; i++)
1337     tmp[i] = silc_rng_get_byte_fast(rng);
1338
1339   /* Put magic number */
1340   SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1341   silc_buffer_pull(enc, 4);
1342
1343   /* Encode the buffer */
1344   silc_buffer_format(enc,
1345                      SILC_STR_UI_INT(key_len),
1346                      SILC_STR_UI_XNSTRING(key, key_len),
1347                      SILC_STR_UI_XNSTRING(tmp, padlen),
1348                      SILC_STR_END);
1349   silc_free(key);
1350
1351   /* Encrypt. */
1352   silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1353                       silc_cipher_get_iv(aes));
1354
1355   silc_buffer_push(enc, 4);
1356
1357   /* Compute HMAC over the encrypted data and append the MAC to data.
1358      The key is the first digest of the original key material. */
1359   key_len = silc_buffer_len(enc) - len;
1360   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1361   silc_hmac_update(sha1hmac, enc->data, key_len);
1362   silc_buffer_pull(enc, key_len);
1363   silc_hmac_final(sha1hmac, enc->data, NULL);
1364   silc_buffer_push(enc, key_len);
1365
1366   /* Cleanup */
1367   memset(keymat, 0, sizeof(keymat));
1368   memset(tmp, 0, sizeof(tmp));
1369   silc_hmac_free(sha1hmac);
1370   silc_hash_free(sha1);
1371   silc_cipher_free(aes);
1372
1373   switch (encoding) {
1374   case SILC_PKCS_FILE_BIN:
1375     break;
1376
1377   case SILC_PKCS_FILE_BASE64:
1378     data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
1379     if (!data) {
1380       silc_buffer_clear(enc);
1381       silc_buffer_free(enc);
1382       return NULL;
1383     }
1384     silc_free(silc_buffer_steal(enc, NULL));
1385     silc_buffer_set(enc, data, strlen(data));
1386     break;
1387   }
1388
1389   key = enc->data;
1390   key_len = silc_buffer_len(enc);
1391
1392   /* Encode the data and save to file */
1393   len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1394                    strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1395   buf = silc_buffer_alloc_size(len);
1396   if (!buf) {
1397     silc_buffer_free(enc);
1398     return NULL;
1399   }
1400   silc_buffer_format(buf,
1401                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1402                      SILC_STR_UI_XNSTRING(key, key_len),
1403                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1404                      SILC_STR_END);
1405
1406   silc_buffer_free(enc);
1407   data = silc_buffer_steal(buf, ret_len);
1408   silc_buffer_free(buf);
1409
1410   return data;
1411 }
1412
1413 /* Exports private key as SILC implementation style private key */
1414
1415 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1416                                                  SilcUInt32 *ret_len)
1417 {
1418   SilcSILCPrivateKey silc_privkey = private_key;
1419   const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1420   SilcBufferStruct alg_key;
1421   SilcBuffer buf = NULL;
1422   SilcAsn1 asn1 = NULL;
1423   unsigned char *prv = NULL, *key = NULL, *ret;
1424   SilcUInt32 prv_len, key_len, totlen;
1425
1426   SILC_LOG_DEBUG(("Encoding SILC private key"));
1427
1428   /* Export PKCS algorithm private key */
1429   if (pkcs->export_private_key)
1430     prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1431   if (!prv)
1432     return NULL;
1433   silc_buffer_set(&alg_key, prv, prv_len);
1434
1435   asn1 = silc_asn1_alloc();
1436   if (!asn1)
1437     goto err;
1438
1439   if (!strcmp(pkcs->name, "rsa")) {
1440     /* Parse the PKCS #1 private key */
1441     SilcMPInt n, e, d, dp, dq, qp, p, q;
1442     SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1443       qp_len, p_len, q_len, len = 0;
1444     unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1445
1446     if (!silc_asn1_decode(asn1, &alg_key,
1447                           SILC_ASN1_SEQUENCE,
1448                             SILC_ASN1_INT(NULL),
1449                             SILC_ASN1_INT(&n),
1450                             SILC_ASN1_INT(&e),
1451                             SILC_ASN1_INT(&d),
1452                             SILC_ASN1_INT(&p),
1453                             SILC_ASN1_INT(&q),
1454                             SILC_ASN1_INT(&dp),
1455                             SILC_ASN1_INT(&dq),
1456                             SILC_ASN1_INT(&qp),
1457                           SILC_ASN1_END, SILC_ASN1_END))
1458       goto err;
1459
1460     /* Encode to SILC RSA private key */
1461     eb = silc_mp_mp2bin(&e, 0, &e_len);
1462     nb = silc_mp_mp2bin(&n, 0, &n_len);
1463     db = silc_mp_mp2bin(&d, 0, &d_len);
1464     dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1465     dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1466     qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1467     pb = silc_mp_mp2bin(&p, 0, &p_len);
1468     qb = silc_mp_mp2bin(&q, 0, &q_len);
1469     len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1470       dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1471
1472     buf = silc_buffer_alloc_size(len);
1473     if (!buf)
1474       goto err;
1475     if (silc_buffer_format(buf,
1476                            SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1477                            SILC_STR_UI_INT(e_len),
1478                            SILC_STR_UI_XNSTRING(eb, e_len),
1479                            SILC_STR_UI_INT(n_len),
1480                            SILC_STR_UI_XNSTRING(nb, n_len),
1481                            SILC_STR_UI_INT(d_len),
1482                            SILC_STR_UI_XNSTRING(db, d_len),
1483                            SILC_STR_UI_INT(dp_len),
1484                            SILC_STR_UI_XNSTRING(dpb, dp_len),
1485                            SILC_STR_UI_INT(dq_len),
1486                            SILC_STR_UI_XNSTRING(dqb, dq_len),
1487                            SILC_STR_UI_INT(qp_len),
1488                            SILC_STR_UI_XNSTRING(qpb, qp_len),
1489                            SILC_STR_UI_INT(p_len),
1490                            SILC_STR_UI_XNSTRING(pb, p_len),
1491                            SILC_STR_UI_INT(q_len),
1492                            SILC_STR_UI_XNSTRING(qb, q_len),
1493                            SILC_STR_END) < 0)
1494       goto err;
1495
1496     key = silc_buffer_steal(buf, &key_len);
1497     silc_buffer_free(buf);
1498     silc_free(nb);
1499     silc_free(eb);
1500     silc_free(db);
1501     silc_free(dpb);
1502     silc_free(dqb);
1503     silc_free(qpb);
1504     silc_free(pb);
1505     silc_free(qb);
1506
1507   } else if (!strcmp(pkcs->name, "dsa")) {
1508     SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1509     goto err;
1510
1511   } else {
1512     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1513     goto err;
1514   }
1515
1516   /* Encode SILC private key */
1517   totlen = 2 + strlen(pkcs->name) + key_len;
1518   buf = silc_buffer_alloc_size(totlen);
1519   if (!buf)
1520     goto err;
1521   if (silc_buffer_format(buf,
1522                          SILC_STR_UI_SHORT(strlen(pkcs->name)),
1523                          SILC_STR_UI32_STRING(pkcs->name),
1524                          SILC_STR_UI_XNSTRING(key, key_len),
1525                          SILC_STR_END) < 0)
1526     goto err;
1527
1528   ret = silc_buffer_steal(buf, ret_len);
1529   silc_buffer_free(buf);
1530   silc_free(prv);
1531   silc_free(key);
1532   silc_asn1_free(asn1);
1533
1534   return ret;
1535
1536  err:
1537   silc_free(prv);
1538   silc_free(key);
1539   if (buf)
1540     silc_buffer_free(buf);
1541   return NULL;
1542 }
1543
1544 /* Return key length */
1545
1546 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1547 {
1548   SilcSILCPrivateKey silc_privkey = private_key;
1549   return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1550 }
1551
1552 /* Frees private key */
1553
1554 void silc_pkcs_silc_private_key_free(void *private_key)
1555 {
1556   SilcSILCPrivateKey silc_privkey = private_key;
1557
1558   silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1559
1560   silc_free(silc_privkey);
1561 }
1562
1563
1564 /***************************** PKCS operations ******************************/
1565
1566 /* Encrypts as specified in SILC protocol specification */
1567
1568 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1569                                 unsigned char *src,
1570                                 SilcUInt32 src_len,
1571                                 unsigned char *dst,
1572                                 SilcUInt32 dst_size,
1573                                 SilcUInt32 *ret_dst_len,
1574                                 SilcRng rng)
1575 {
1576   SilcSILCPublicKey silc_pubkey = public_key;
1577
1578   if (!silc_pubkey->pkcs->encrypt)
1579     return FALSE;
1580
1581   return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1582                                     src, src_len,
1583                                     dst, dst_size, ret_dst_len, rng);
1584 }
1585
1586 /* Decrypts as specified in SILC protocol specification */
1587
1588 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1589                                 unsigned char *src,
1590                                 SilcUInt32 src_len,
1591                                 unsigned char *dst,
1592                                 SilcUInt32 dst_size,
1593                                 SilcUInt32 *ret_dst_len)
1594 {
1595   SilcSILCPrivateKey silc_privkey = private_key;
1596
1597   if (!silc_privkey->pkcs->decrypt)
1598     return FALSE;
1599
1600   return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1601                                      src, src_len,
1602                                      dst, dst_size, ret_dst_len);
1603 }
1604
1605 /* Signs as specified in SILC protocol specification */
1606
1607 SilcBool silc_pkcs_silc_sign(void *private_key,
1608                              unsigned char *src,
1609                              SilcUInt32 src_len,
1610                              unsigned char *signature,
1611                              SilcUInt32 signature_size,
1612                              SilcUInt32 *ret_signature_len,
1613                              SilcBool compute_hash,
1614                              SilcHash hash)
1615 {
1616   SilcSILCPrivateKey silc_privkey = private_key;
1617
1618   if (!silc_privkey->pkcs->sign)
1619     return FALSE;
1620
1621   return silc_privkey->pkcs->sign(silc_privkey->private_key,
1622                                   src, src_len,
1623                                   signature, signature_size,
1624                                   ret_signature_len, compute_hash, hash);
1625 }
1626
1627 /* Verifies as specified in SILC protocol specification */
1628
1629 SilcBool silc_pkcs_silc_verify(void *public_key,
1630                                unsigned char *signature,
1631                                SilcUInt32 signature_len,
1632                                unsigned char *data,
1633                                SilcUInt32 data_len,
1634                                SilcHash hash)
1635 {
1636   SilcSILCPublicKey silc_pubkey = public_key;
1637
1638   if (!silc_pubkey->pkcs->verify)
1639     return FALSE;
1640
1641   return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1642                                    signature, signature_len,
1643                                    data, data_len, hash);
1644 }