Memory leak fixes.
[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_buffer_purge(&alg_key);
681   silc_asn1_free(asn1);
682
683   return ret;
684
685  err:
686   silc_free(identifier);
687   silc_free(pk);
688   silc_free(key);
689   if (buf)
690     silc_buffer_free(buf);
691   if (asn1)
692     silc_asn1_free(asn1);
693   return NULL;
694 }
695
696 /* Return key length */
697
698 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
699 {
700   SilcSILCPublicKey silc_pubkey = public_key;
701   return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
702 }
703
704 /* Copy public key */
705
706 void *silc_pkcs_silc_public_key_copy(void *public_key)
707 {
708   SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
709
710   new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
711   if (!new_pubkey)
712     return NULL;
713   new_pubkey->pkcs = silc_pubkey->pkcs;
714
715   new_pubkey->public_key =
716     silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
717   if (!new_pubkey->public_key) {
718     silc_free(new_pubkey);
719     return NULL;
720   }
721
722   return new_pubkey;
723 }
724
725 /* Compares public keys */
726
727 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
728 {
729   SilcSILCPublicKey k1 = key1, k2 = key2;
730
731   if (strcmp(k1->pkcs->name, k2->pkcs->name))
732     return FALSE;
733
734   if ((k1->identifier.username && !k2->identifier.username) ||
735       (!k1->identifier.username && k2->identifier.username) ||
736       (k1->identifier.username && k2->identifier.username &&
737        strcmp(k1->identifier.username, k2->identifier.username)))
738     return FALSE;
739
740   if ((k1->identifier.host && !k2->identifier.host) ||
741       (!k1->identifier.host && k2->identifier.host) ||
742       (k1->identifier.host && k2->identifier.host &&
743        strcmp(k1->identifier.host, k2->identifier.host)))
744     return FALSE;
745
746   if ((k1->identifier.realname && !k2->identifier.realname) ||
747       (!k1->identifier.realname && k2->identifier.realname) ||
748       (k1->identifier.realname && k2->identifier.realname &&
749        strcmp(k1->identifier.realname, k2->identifier.realname)))
750     return FALSE;
751
752   if ((k1->identifier.email && !k2->identifier.email) ||
753       (!k1->identifier.email && k2->identifier.email) ||
754       (k1->identifier.email && k2->identifier.email &&
755        strcmp(k1->identifier.email, k2->identifier.email)))
756     return FALSE;
757
758   if ((k1->identifier.org && !k2->identifier.org) ||
759       (!k1->identifier.org && k2->identifier.org) ||
760       (k1->identifier.org && k2->identifier.org &&
761        strcmp(k1->identifier.org, k2->identifier.org)))
762     return FALSE;
763
764   if ((k1->identifier.country && !k2->identifier.country) ||
765       (!k1->identifier.country && k2->identifier.country) ||
766       (k1->identifier.country && k2->identifier.country &&
767        strcmp(k1->identifier.country, k2->identifier.country)))
768     return FALSE;
769
770   if ((k1->identifier.version && !k2->identifier.version) ||
771       (!k1->identifier.version && k2->identifier.version) ||
772       (k1->identifier.version && k2->identifier.version &&
773        strcmp(k1->identifier.version, k2->identifier.version)))
774     return FALSE;
775
776   return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
777 }
778
779 /* Frees public key */
780
781 void silc_pkcs_silc_public_key_free(void *public_key)
782 {
783   SilcSILCPublicKey silc_pubkey = public_key;
784
785   silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
786
787   silc_free(silc_pubkey->identifier.username);
788   silc_free(silc_pubkey->identifier.host);
789   silc_free(silc_pubkey->identifier.realname);
790   silc_free(silc_pubkey->identifier.email);
791   silc_free(silc_pubkey->identifier.org);
792   silc_free(silc_pubkey->identifier.country);
793   silc_free(silc_pubkey->identifier.version);
794   silc_free(silc_pubkey);
795 }
796
797
798 /*************************** Private key routines ****************************/
799
800 /* Private key file magic */
801 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
802
803 /* Imports SILC implementation style private key file */
804
805 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
806                                                 SilcUInt32 filedata_len,
807                                                 const char *passphrase,
808                                                 SilcUInt32 passphrase_len,
809                                                 SilcPKCSFileEncoding encoding,
810                                                 void **ret_private_key)
811 {
812   SilcCipher aes;
813   SilcHash sha1;
814   SilcHmac sha1hmac;
815   SilcUInt32 blocklen;
816   unsigned char tmp[32], keymat[64], *data = NULL;
817   SilcUInt32 i, len, magic, mac_len;
818   int ret;
819
820   SILC_LOG_DEBUG(("Parsing SILC private key file"));
821
822   /* Check start of file and remove header from the data. */
823   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
824   if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
825     return FALSE;
826   for (i = 0; i < len; i++) {
827     if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
828       return FALSE;
829     filedata++;
830   }
831
832   len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
833                         strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
834
835   switch (encoding) {
836   case SILC_PKCS_FILE_BIN:
837     break;
838
839   case SILC_PKCS_FILE_BASE64:
840     data = silc_base64_decode(filedata, filedata_len, &len);
841     if (!data)
842       return FALSE;
843     filedata = data;
844     break;
845   }
846
847   memset(tmp, 0, sizeof(tmp));
848   memset(keymat, 0, sizeof(keymat));
849
850   /* Check file magic */
851   SILC_GET32_MSB(magic, filedata);
852   if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
853     SILC_LOG_DEBUG(("Private key does not have correct magic"));
854     return FALSE;
855   }
856
857   /* Allocate the AES cipher */
858   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
859     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
860     return FALSE;
861   }
862   blocklen = silc_cipher_get_block_len(aes);
863   if (blocklen * 2 > sizeof(tmp)) {
864     silc_cipher_free(aes);
865     return FALSE;
866   }
867
868   /* Allocate SHA1 hash */
869   if (!silc_hash_alloc("sha1", &sha1)) {
870     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
871     silc_cipher_free(aes);
872     return FALSE;
873   }
874
875   /* Allocate HMAC */
876   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
877     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
878     silc_hash_free(sha1);
879     silc_cipher_free(aes);
880     return FALSE;
881   }
882
883   /* Derive the decryption key from the provided key material.  The key
884      is 256 bits length, and derived by taking hash of the data, then
885      re-hashing the data and the previous digest, and using the first and
886      second digest as the key. */
887   silc_hash_init(sha1);
888   silc_hash_update(sha1, passphrase, passphrase_len);
889   silc_hash_final(sha1, keymat);
890   silc_hash_init(sha1);
891   silc_hash_update(sha1, passphrase, passphrase_len);
892   silc_hash_update(sha1, keymat, 16);
893   silc_hash_final(sha1, keymat + 16);
894
895   /* Set the key to the cipher */
896   silc_cipher_set_key(aes, keymat, 256, FALSE);
897
898   /* First, verify the MAC of the private key data */
899   mac_len = silc_hmac_len(sha1hmac);
900   silc_hmac_init_with_key(sha1hmac, keymat, 16);
901   silc_hmac_update(sha1hmac, filedata, len - mac_len);
902   silc_hmac_final(sha1hmac, tmp, NULL);
903   if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
904     SILC_LOG_DEBUG(("Integrity check for private key failed"));
905     memset(keymat, 0, sizeof(keymat));
906     memset(tmp, 0, sizeof(tmp));
907     silc_hmac_free(sha1hmac);
908     silc_hash_free(sha1);
909     silc_cipher_free(aes);
910     return FALSE;
911   }
912   filedata += 4;
913   len -= 4;
914
915   /* Decrypt the private key buffer */
916   silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
917   SILC_GET32_MSB(i, filedata);
918   if (i > len) {
919     SILC_LOG_DEBUG(("Bad private key length in buffer!"));
920     memset(keymat, 0, sizeof(keymat));
921     memset(tmp, 0, sizeof(tmp));
922     silc_hmac_free(sha1hmac);
923     silc_hash_free(sha1);
924     silc_cipher_free(aes);
925     return FALSE;
926   }
927   filedata += 4;
928   len = i;
929
930   /* Cleanup */
931   memset(keymat, 0, sizeof(keymat));
932   memset(tmp, 0, sizeof(tmp));
933   silc_hmac_free(sha1hmac);
934   silc_hash_free(sha1);
935   silc_cipher_free(aes);
936
937   /* Import the private key */
938   ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
939
940   silc_free(data);
941
942   return ret ? TRUE : FALSE;
943 }
944
945 /* Private key version */
946 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
947 #define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
948
949 /* Imports SILC implementation style private key */
950
951 int silc_pkcs_silc_import_private_key(unsigned char *key,
952                                       SilcUInt32 key_len,
953                                       void **ret_private_key)
954 {
955   SilcBufferStruct buf;
956   const SilcPKCSAlgorithm *pkcs;
957   SilcBufferStruct alg_key;
958   SilcSILCPrivateKey silc_privkey = NULL;
959   SilcAsn1 asn1 = NULL;
960   SilcUInt16 pkcs_len;
961   SilcUInt32 keydata_len;
962   unsigned char *pkcs_name = NULL, *key_data;
963   int ret;
964
965   SILC_LOG_DEBUG(("Parsing SILC private key"));
966
967   if (!ret_private_key)
968     return 0;
969
970   silc_buffer_set(&buf, key, key_len);
971
972   /* Get algorithm name and identifier */
973   ret =
974     silc_buffer_unformat(&buf,
975                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
976                          SILC_STR_END);
977   if (ret == -1) {
978     SILC_LOG_DEBUG(("Cannot decode private key buffer"));
979     goto err;
980   }
981
982   if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
983     SILC_LOG_DEBUG(("Malformed private key buffer"));
984     goto err;
985   }
986
987   /* Get key data. We assume that rest of the buffer is key data. */
988   silc_buffer_pull(&buf, 2 + pkcs_len);
989   keydata_len = silc_buffer_len(&buf);
990   ret = silc_buffer_unformat(&buf,
991                              SILC_STR_UI_XNSTRING(&key_data, keydata_len),
992                              SILC_STR_END);
993   if (ret == -1)
994     goto err;
995
996   /* Allocate SILC private key context */
997   silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
998   if (!silc_privkey)
999     goto err;
1000
1001   asn1 = silc_asn1_alloc();
1002   if (!asn1)
1003     goto err;
1004
1005   if (!strcmp(pkcs_name, "rsa")) {
1006     /* Parse the RSA SILC private key */
1007     SilcBufferStruct k;
1008     SilcMPInt n, e, d, dp, dq, qp, p, q;
1009     unsigned char *tmp;
1010     SilcUInt32 len, ver;
1011
1012     if (keydata_len < 4)
1013       goto err;
1014     silc_buffer_set(&k, key_data, keydata_len);
1015
1016     /* Get version.  Key without the version is old style private key
1017        and we need to do some computation to get it to correct format. */
1018     if (silc_buffer_unformat(&k,
1019                              SILC_STR_UI_INT(&ver),
1020                              SILC_STR_END) < 0)
1021       goto err;
1022     silc_buffer_pull(&k, 4);
1023
1024     if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1025         ver != SILC_PRIVATE_KEY_VERSION_2) {
1026       len = ver;
1027       ver = 0;
1028     } else {
1029       if (silc_buffer_unformat(&k,
1030                                SILC_STR_UI_INT(&len),
1031                                SILC_STR_END) < 0)
1032         goto err;
1033       silc_buffer_pull(&k, 4);
1034     }
1035
1036     /* Get PKCS object.  Different PKCS #1 scheme is used with different
1037        versions. */
1038     if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1039       /* Version 0 and 1 */
1040       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1041     } else {
1042       /* Version 2 and newer */
1043       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1044     }
1045     if (!pkcs) {
1046       SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1047       goto err;
1048     }
1049     silc_privkey->pkcs = pkcs;
1050
1051     SILC_LOG_DEBUG(("Private key version %s",
1052                     (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1053                      ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1054
1055     /* Get e */
1056     if (silc_buffer_unformat(&k,
1057                              SILC_STR_DATA(&tmp, len),
1058                              SILC_STR_END) < 0)
1059       goto err;
1060     silc_mp_init(&e);
1061     silc_mp_bin2mp(tmp, len, &e);
1062     silc_buffer_pull(&k, len);
1063
1064     /* Get n */
1065     if (silc_buffer_unformat(&k,
1066                              SILC_STR_UI_INT(&len),
1067                              SILC_STR_END) < 0)
1068       goto err;
1069     silc_buffer_pull(&k, 4);
1070     if (silc_buffer_unformat(&k,
1071                              SILC_STR_DATA(&tmp, len),
1072                              SILC_STR_END) < 0)
1073       goto err;
1074     silc_mp_init(&n);
1075     silc_mp_bin2mp(tmp, len, &n);
1076     silc_buffer_pull(&k, len);
1077
1078     /* Get d */
1079     if (silc_buffer_unformat(&k,
1080                              SILC_STR_UI_INT(&len),
1081                              SILC_STR_END) < 0)
1082       goto err;
1083     silc_buffer_pull(&k, 4);
1084     if (silc_buffer_unformat(&k,
1085                              SILC_STR_DATA(&tmp, len),
1086                              SILC_STR_END) < 0)
1087       goto err;
1088     silc_mp_init(&d);
1089     silc_mp_bin2mp(tmp, len, &d);
1090     silc_buffer_pull(&k, len);
1091
1092     /* Get dP */
1093     if (silc_buffer_unformat(&k,
1094                              SILC_STR_UI_INT(&len),
1095                              SILC_STR_END) < 0)
1096       goto err;
1097     silc_buffer_pull(&k, 4);
1098     if (silc_buffer_unformat(&k,
1099                              SILC_STR_DATA(&tmp, len),
1100                              SILC_STR_END) < 0)
1101       goto err;
1102     silc_mp_init(&dp);
1103     silc_mp_bin2mp(tmp, len, &dp);
1104     silc_buffer_pull(&k, len);
1105
1106     /* Get dQ */
1107     if (silc_buffer_unformat(&k,
1108                              SILC_STR_UI_INT(&len),
1109                              SILC_STR_END) < 0)
1110       goto err;
1111     silc_buffer_pull(&k, 4);
1112     if (silc_buffer_unformat(&k,
1113                              SILC_STR_DATA(&tmp, len),
1114                              SILC_STR_END) < 0)
1115       goto err;
1116     silc_mp_init(&dq);
1117     silc_mp_bin2mp(tmp, len, &dq);
1118     silc_buffer_pull(&k, len);
1119
1120     if (ver == 0) {
1121       /* Old version */
1122
1123       /* Get pQ len */
1124       if (silc_buffer_unformat(&k,
1125                                SILC_STR_UI_INT(&len),
1126                                SILC_STR_END) < 0)
1127         goto err;
1128       silc_buffer_pull(&k, 4);
1129       if (silc_buffer_len(&k) < len)
1130         goto err;
1131       silc_buffer_pull(&k, len);
1132
1133       /* Get qP len */
1134       if (silc_buffer_unformat(&k,
1135                                SILC_STR_UI_INT(&len),
1136                                SILC_STR_END) < 0)
1137         goto err;
1138       silc_buffer_pull(&k, 4);
1139       if (silc_buffer_len(&k) < len)
1140         goto err;
1141       silc_buffer_pull(&k, len);
1142     } else {
1143       /* New version */
1144
1145       /* Get qP */
1146       if (silc_buffer_unformat(&k,
1147                                SILC_STR_UI_INT(&len),
1148                                SILC_STR_END) < 0)
1149         goto err;
1150       silc_buffer_pull(&k, 4);
1151       if (silc_buffer_unformat(&k,
1152                                SILC_STR_DATA(&tmp, len),
1153                                SILC_STR_END) < 0)
1154         goto err;
1155       silc_mp_init(&qp);
1156       silc_mp_bin2mp(tmp, len, &qp);
1157       silc_buffer_pull(&k, len);
1158     }
1159
1160     /* Get p */
1161     if (silc_buffer_unformat(&k,
1162                              SILC_STR_UI_INT(&len),
1163                              SILC_STR_END) < 0)
1164       goto err;
1165     silc_buffer_pull(&k, 4);
1166     if (silc_buffer_unformat(&k,
1167                              SILC_STR_DATA(&tmp, len),
1168                              SILC_STR_END) < 0)
1169       goto err;
1170     silc_mp_init(&p);
1171     silc_mp_bin2mp(tmp, len, &p);
1172     silc_buffer_pull(&k, len);
1173
1174     /* Get q */
1175     if (silc_buffer_unformat(&k,
1176                              SILC_STR_UI_INT(&len),
1177                              SILC_STR_END) < 0)
1178       goto err;
1179     silc_buffer_pull(&k, 4);
1180     if (silc_buffer_unformat(&k,
1181                              SILC_STR_DATA(&tmp, len),
1182                              SILC_STR_END) < 0)
1183       goto err;
1184     silc_mp_init(&q);
1185     silc_mp_bin2mp(tmp, len, &q);
1186     silc_buffer_pull(&k, len);
1187
1188     if (ver == 0) {
1189       /* Old version.  Compute to new version */
1190       SILC_LOG_DEBUG(("Old version private key"));
1191       silc_mp_init(&qp);
1192       silc_mp_modinv(&qp, &q, &p);
1193     }
1194
1195     /* Encode to PKCS #1 format */
1196     memset(&alg_key, 0, sizeof(alg_key));
1197     if (!silc_asn1_encode(asn1, &alg_key,
1198                           SILC_ASN1_SEQUENCE,
1199                             SILC_ASN1_SHORT_INT(0),
1200                             SILC_ASN1_INT(&n),
1201                             SILC_ASN1_INT(&e),
1202                             SILC_ASN1_INT(&d),
1203                             SILC_ASN1_INT(&p),
1204                             SILC_ASN1_INT(&q),
1205                             SILC_ASN1_INT(&dp),
1206                             SILC_ASN1_INT(&dq),
1207                             SILC_ASN1_INT(&qp),
1208                           SILC_ASN1_END, SILC_ASN1_END))
1209       goto err;
1210
1211     silc_mp_uninit(&n);
1212     silc_mp_uninit(&e);
1213     silc_mp_uninit(&e);
1214     silc_mp_uninit(&d);
1215     silc_mp_uninit(&p);
1216     silc_mp_uninit(&q);
1217     silc_mp_uninit(&dp);
1218     silc_mp_uninit(&dq);
1219     silc_mp_uninit(&qp);
1220
1221   } else if (!strcmp(pkcs_name, "dsa")) {
1222     SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1223     goto err;
1224
1225   } else {
1226     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1227     goto err;
1228   }
1229
1230   /* Import PKCS algorithm private key */
1231   if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1232                                 &silc_privkey->private_key))
1233     goto err;
1234
1235   silc_free(pkcs_name);
1236   silc_asn1_free(asn1);
1237
1238   *ret_private_key = silc_privkey;
1239
1240   return key_len;
1241
1242  err:
1243   silc_free(pkcs_name);
1244   silc_free(silc_privkey);
1245   if (asn1)
1246     silc_asn1_free(asn1);
1247   return 0;
1248 }
1249
1250 /* Exports private key as SILC implementation style private key file */
1251
1252 unsigned char *
1253 silc_pkcs_silc_export_private_key_file(void *private_key,
1254                                        const char *passphrase,
1255                                        SilcUInt32 passphrase_len,
1256                                        SilcPKCSFileEncoding encoding,
1257                                        SilcRng rng,
1258                                        SilcUInt32 *ret_len)
1259 {
1260   SilcCipher aes;
1261   SilcHash sha1;
1262   SilcHmac sha1hmac;
1263   SilcBuffer buf, enc;
1264   SilcUInt32 len, blocklen, padlen, key_len;
1265   unsigned char *key, *data;
1266   unsigned char tmp[32], keymat[64];
1267   int i;
1268
1269   SILC_LOG_DEBUG(("Encoding SILC private key file"));
1270
1271   /* Export the private key */
1272   key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1273   if (!key)
1274     return NULL;
1275
1276   memset(tmp, 0, sizeof(tmp));
1277   memset(keymat, 0, sizeof(keymat));
1278
1279   /* Allocate the AES cipher */
1280   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1281     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1282     silc_free(key);
1283     return NULL;
1284   }
1285   blocklen = silc_cipher_get_block_len(aes);
1286   if (blocklen * 2 > sizeof(tmp)) {
1287     silc_cipher_free(aes);
1288     silc_free(key);
1289     return NULL;
1290   }
1291
1292   /* Allocate SHA1 hash */
1293   if (!silc_hash_alloc("sha1", &sha1)) {
1294     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1295     silc_cipher_free(aes);
1296     return NULL;
1297   }
1298
1299   /* Allocate HMAC */
1300   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1301     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1302     silc_hash_free(sha1);
1303     silc_cipher_free(aes);
1304     return NULL;
1305   }
1306
1307   /* Derive the encryption key from the provided key material.  The key
1308      is 256 bits length, and derived by taking hash of the data, then
1309      re-hashing the data and the previous digest, and using the first and
1310      second digest as the key. */
1311   silc_hash_init(sha1);
1312   silc_hash_update(sha1, passphrase, passphrase_len);
1313   silc_hash_final(sha1, keymat);
1314   silc_hash_init(sha1);
1315   silc_hash_update(sha1, passphrase, passphrase_len);
1316   silc_hash_update(sha1, keymat, 16);
1317   silc_hash_final(sha1, keymat + 16);
1318
1319   /* Set the key to the cipher */
1320   silc_cipher_set_key(aes, keymat, 256, TRUE);
1321
1322   /* Encode the buffer to be encrypted.  Add padding to it too, at least
1323      block size of the cipher. */
1324
1325   /* Allocate buffer for encryption */
1326   len = silc_hmac_len(sha1hmac);
1327   padlen = 16 + (16 - ((key_len + 4) % blocklen));
1328   enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1329   if (!enc) {
1330     silc_hmac_free(sha1hmac);
1331     silc_hash_free(sha1);
1332     silc_cipher_free(aes);
1333     return FALSE;
1334   }
1335
1336   /* Generate padding */
1337   for (i = 0; i < padlen; i++)
1338     tmp[i] = silc_rng_get_byte_fast(rng);
1339
1340   /* Put magic number */
1341   SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1342   silc_buffer_pull(enc, 4);
1343
1344   /* Encode the buffer */
1345   silc_buffer_format(enc,
1346                      SILC_STR_UI_INT(key_len),
1347                      SILC_STR_UI_XNSTRING(key, key_len),
1348                      SILC_STR_UI_XNSTRING(tmp, padlen),
1349                      SILC_STR_END);
1350   silc_free(key);
1351
1352   /* Encrypt. */
1353   silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1354                       silc_cipher_get_iv(aes));
1355
1356   silc_buffer_push(enc, 4);
1357
1358   /* Compute HMAC over the encrypted data and append the MAC to data.
1359      The key is the first digest of the original key material. */
1360   key_len = silc_buffer_len(enc) - len;
1361   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1362   silc_hmac_update(sha1hmac, enc->data, key_len);
1363   silc_buffer_pull(enc, key_len);
1364   silc_hmac_final(sha1hmac, enc->data, NULL);
1365   silc_buffer_push(enc, key_len);
1366
1367   /* Cleanup */
1368   memset(keymat, 0, sizeof(keymat));
1369   memset(tmp, 0, sizeof(tmp));
1370   silc_hmac_free(sha1hmac);
1371   silc_hash_free(sha1);
1372   silc_cipher_free(aes);
1373
1374   switch (encoding) {
1375   case SILC_PKCS_FILE_BIN:
1376     break;
1377
1378   case SILC_PKCS_FILE_BASE64:
1379     data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
1380     if (!data) {
1381       silc_buffer_clear(enc);
1382       silc_buffer_free(enc);
1383       return NULL;
1384     }
1385     silc_free(silc_buffer_steal(enc, NULL));
1386     silc_buffer_set(enc, data, strlen(data));
1387     break;
1388   }
1389
1390   key = enc->data;
1391   key_len = silc_buffer_len(enc);
1392
1393   /* Encode the data and save to file */
1394   len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1395                    strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1396   buf = silc_buffer_alloc_size(len);
1397   if (!buf) {
1398     silc_buffer_free(enc);
1399     return NULL;
1400   }
1401   silc_buffer_format(buf,
1402                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1403                      SILC_STR_UI_XNSTRING(key, key_len),
1404                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1405                      SILC_STR_END);
1406
1407   silc_buffer_free(enc);
1408   data = silc_buffer_steal(buf, ret_len);
1409   silc_buffer_free(buf);
1410
1411   return data;
1412 }
1413
1414 /* Exports private key as SILC implementation style private key */
1415
1416 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1417                                                  SilcUInt32 *ret_len)
1418 {
1419   SilcSILCPrivateKey silc_privkey = private_key;
1420   const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1421   SilcBufferStruct alg_key;
1422   SilcBuffer buf = NULL;
1423   SilcAsn1 asn1 = NULL;
1424   unsigned char *prv = NULL, *key = NULL, *ret;
1425   SilcUInt32 prv_len, key_len, totlen;
1426
1427   SILC_LOG_DEBUG(("Encoding SILC private key"));
1428
1429   /* Export PKCS algorithm private key */
1430   if (pkcs->export_private_key)
1431     prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1432   if (!prv)
1433     return NULL;
1434   silc_buffer_set(&alg_key, prv, prv_len);
1435
1436   asn1 = silc_asn1_alloc();
1437   if (!asn1)
1438     goto err;
1439
1440   if (!strcmp(pkcs->name, "rsa")) {
1441     /* Parse the PKCS #1 private key */
1442     SilcMPInt n, e, d, dp, dq, qp, p, q;
1443     SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1444       qp_len, p_len, q_len, len = 0;
1445     unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1446
1447     if (!silc_asn1_decode(asn1, &alg_key,
1448                           SILC_ASN1_SEQUENCE,
1449                             SILC_ASN1_INT(NULL),
1450                             SILC_ASN1_INT(&n),
1451                             SILC_ASN1_INT(&e),
1452                             SILC_ASN1_INT(&d),
1453                             SILC_ASN1_INT(&p),
1454                             SILC_ASN1_INT(&q),
1455                             SILC_ASN1_INT(&dp),
1456                             SILC_ASN1_INT(&dq),
1457                             SILC_ASN1_INT(&qp),
1458                           SILC_ASN1_END, SILC_ASN1_END))
1459       goto err;
1460
1461     /* Encode to SILC RSA private key */
1462     eb = silc_mp_mp2bin(&e, 0, &e_len);
1463     nb = silc_mp_mp2bin(&n, 0, &n_len);
1464     db = silc_mp_mp2bin(&d, 0, &d_len);
1465     dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1466     dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1467     qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1468     pb = silc_mp_mp2bin(&p, 0, &p_len);
1469     qb = silc_mp_mp2bin(&q, 0, &q_len);
1470     len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1471       dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1472
1473     buf = silc_buffer_alloc_size(len);
1474     if (!buf)
1475       goto err;
1476     if (silc_buffer_format(buf,
1477                            SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1478                            SILC_STR_UI_INT(e_len),
1479                            SILC_STR_UI_XNSTRING(eb, e_len),
1480                            SILC_STR_UI_INT(n_len),
1481                            SILC_STR_UI_XNSTRING(nb, n_len),
1482                            SILC_STR_UI_INT(d_len),
1483                            SILC_STR_UI_XNSTRING(db, d_len),
1484                            SILC_STR_UI_INT(dp_len),
1485                            SILC_STR_UI_XNSTRING(dpb, dp_len),
1486                            SILC_STR_UI_INT(dq_len),
1487                            SILC_STR_UI_XNSTRING(dqb, dq_len),
1488                            SILC_STR_UI_INT(qp_len),
1489                            SILC_STR_UI_XNSTRING(qpb, qp_len),
1490                            SILC_STR_UI_INT(p_len),
1491                            SILC_STR_UI_XNSTRING(pb, p_len),
1492                            SILC_STR_UI_INT(q_len),
1493                            SILC_STR_UI_XNSTRING(qb, q_len),
1494                            SILC_STR_END) < 0)
1495       goto err;
1496
1497     key = silc_buffer_steal(buf, &key_len);
1498     silc_buffer_free(buf);
1499     silc_free(nb);
1500     silc_free(eb);
1501     silc_free(db);
1502     silc_free(dpb);
1503     silc_free(dqb);
1504     silc_free(qpb);
1505     silc_free(pb);
1506     silc_free(qb);
1507
1508   } else if (!strcmp(pkcs->name, "dsa")) {
1509     SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1510     goto err;
1511
1512   } else {
1513     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1514     goto err;
1515   }
1516
1517   /* Encode SILC private key */
1518   totlen = 2 + strlen(pkcs->name) + key_len;
1519   buf = silc_buffer_alloc_size(totlen);
1520   if (!buf)
1521     goto err;
1522   if (silc_buffer_format(buf,
1523                          SILC_STR_UI_SHORT(strlen(pkcs->name)),
1524                          SILC_STR_UI32_STRING(pkcs->name),
1525                          SILC_STR_UI_XNSTRING(key, key_len),
1526                          SILC_STR_END) < 0)
1527     goto err;
1528
1529   ret = silc_buffer_steal(buf, ret_len);
1530   silc_buffer_free(buf);
1531   silc_free(prv);
1532   silc_free(key);
1533   silc_buffer_purge(&alg_key);
1534   silc_asn1_free(asn1);
1535
1536   return ret;
1537
1538  err:
1539   silc_free(prv);
1540   silc_free(key);
1541   if (buf)
1542     silc_buffer_free(buf);
1543   return NULL;
1544 }
1545
1546 /* Return key length */
1547
1548 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1549 {
1550   SilcSILCPrivateKey silc_privkey = private_key;
1551   return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1552 }
1553
1554 /* Frees private key */
1555
1556 void silc_pkcs_silc_private_key_free(void *private_key)
1557 {
1558   SilcSILCPrivateKey silc_privkey = private_key;
1559
1560   silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1561
1562   silc_free(silc_privkey);
1563 }
1564
1565
1566 /***************************** PKCS operations ******************************/
1567
1568 /* Encrypts as specified in SILC protocol specification */
1569
1570 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1571                                 unsigned char *src,
1572                                 SilcUInt32 src_len,
1573                                 unsigned char *dst,
1574                                 SilcUInt32 dst_size,
1575                                 SilcUInt32 *ret_dst_len,
1576                                 SilcRng rng)
1577 {
1578   SilcSILCPublicKey silc_pubkey = public_key;
1579
1580   if (!silc_pubkey->pkcs->encrypt)
1581     return FALSE;
1582
1583   return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1584                                     src, src_len,
1585                                     dst, dst_size, ret_dst_len, rng);
1586 }
1587
1588 /* Decrypts as specified in SILC protocol specification */
1589
1590 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1591                                 unsigned char *src,
1592                                 SilcUInt32 src_len,
1593                                 unsigned char *dst,
1594                                 SilcUInt32 dst_size,
1595                                 SilcUInt32 *ret_dst_len)
1596 {
1597   SilcSILCPrivateKey silc_privkey = private_key;
1598
1599   if (!silc_privkey->pkcs->decrypt)
1600     return FALSE;
1601
1602   return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1603                                      src, src_len,
1604                                      dst, dst_size, ret_dst_len);
1605 }
1606
1607 /* Signs as specified in SILC protocol specification */
1608
1609 SilcBool silc_pkcs_silc_sign(void *private_key,
1610                              unsigned char *src,
1611                              SilcUInt32 src_len,
1612                              unsigned char *signature,
1613                              SilcUInt32 signature_size,
1614                              SilcUInt32 *ret_signature_len,
1615                              SilcBool compute_hash,
1616                              SilcHash hash)
1617 {
1618   SilcSILCPrivateKey silc_privkey = private_key;
1619
1620   if (!silc_privkey->pkcs->sign)
1621     return FALSE;
1622
1623   return silc_privkey->pkcs->sign(silc_privkey->private_key,
1624                                   src, src_len,
1625                                   signature, signature_size,
1626                                   ret_signature_len, compute_hash, hash);
1627 }
1628
1629 /* Verifies as specified in SILC protocol specification */
1630
1631 SilcBool silc_pkcs_silc_verify(void *public_key,
1632                                unsigned char *signature,
1633                                SilcUInt32 signature_len,
1634                                unsigned char *data,
1635                                SilcUInt32 data_len,
1636                                SilcHash hash)
1637 {
1638   SilcSILCPublicKey silc_pubkey = public_key;
1639
1640   if (!silc_pubkey->pkcs->verify)
1641     return FALSE;
1642
1643   return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1644                                    signature, signature_len,
1645                                    data, data_len, hash);
1646 }