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