Merge branch 'topic/mm-fixes' of git://208.110.73.182/silc into silc.1.1.branch
[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) < 1 || strlen(host) < 1)
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     SILC_LOG_ERROR(("Malformed SILC public key header"));
328     return FALSE;
329   }
330   for (i = 0; i < len; i++) {
331     if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
332       SILC_LOG_ERROR(("Malformed SILC public key header"));
333       return FALSE;
334     }
335     filedata++;
336   }
337   filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
338                    strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
339
340   switch (encoding) {
341   case SILC_PKCS_FILE_BIN:
342     break;
343
344   case SILC_PKCS_FILE_BASE64:
345     data = silc_base64_decode(filedata, filedata_len, &filedata_len);
346     if (!data)
347       return FALSE;
348     filedata = data;
349     break;
350   }
351
352   ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
353                                          ret_public_key);
354   silc_free(data);
355
356   return ret ? TRUE : FALSE;
357 }
358
359 /* Imports SILC protocol style public key */
360
361 int silc_pkcs_silc_import_public_key(unsigned char *key,
362                                      SilcUInt32 key_len,
363                                      void **ret_public_key)
364 {
365   const SilcPKCSAlgorithm *pkcs;
366   SilcBufferStruct buf, alg_key;
367   SilcSILCPublicKey silc_pubkey = NULL;
368   SilcAsn1 asn1 = NULL;
369   SilcUInt32 totlen, keydata_len;
370   SilcUInt16 pkcs_len, identifier_len;
371   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
372   int ret;
373
374   SILC_LOG_DEBUG(("Parsing SILC public key"));
375
376   if (!ret_public_key)
377     return 0;
378
379   silc_buffer_set(&buf, key, key_len);
380
381   /* Get length */
382   ret = silc_buffer_unformat(&buf,
383                              SILC_STR_ADVANCE,
384                              SILC_STR_UI_INT(&totlen),
385                              SILC_STR_END);
386   if (ret == -1)
387     goto err;
388
389   /* Backwards compatibility */
390   if (totlen == key_len)
391     totlen -= 4;
392
393   if (totlen + 4 != key_len)
394     goto err;
395
396   /* Get algorithm name and identifier */
397   ret =
398     silc_buffer_unformat(&buf,
399                          SILC_STR_ADVANCE,
400                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
401                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
402                          SILC_STR_END);
403   if (ret == -1)
404     goto err;
405
406   if (pkcs_len < 1 || identifier_len < 3 ||
407       pkcs_len + identifier_len > totlen)
408     goto err;
409
410   /* Get key data */
411   keydata_len = silc_buffer_len(&buf);
412   ret = silc_buffer_unformat(&buf,
413                              SILC_STR_DATA(&key_data, keydata_len),
414                              SILC_STR_END);
415   if (ret == -1)
416     goto err;
417
418   /* Allocate SILC public key context */
419   silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
420   if (!silc_pubkey)
421     goto err;
422
423   /* Decode SILC identifier */
424   if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
425     goto err;
426
427   asn1 = silc_asn1_alloc();
428   if (!asn1)
429     goto err;
430
431   SILC_LOG_DEBUG(("Public key version %s",
432                   (!silc_pubkey->identifier.version ? "1" :
433                    silc_pubkey->identifier.version)));
434
435   if (!strcmp(pkcs_name, "rsa")) {
436     /* Parse the SILC RSA public key */
437     SilcUInt32 e_len, n_len;
438     SilcMPInt n, e;
439
440     /* Get PKCS object.  Different PKCS #1 scheme is used with different
441        versions. */
442     if (!silc_pubkey->identifier.version ||
443         atoi(silc_pubkey->identifier.version) <= 1) {
444       /* Version 1 */
445       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
446     } else {
447       /* Version 2 and newer */
448       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
449     }
450     if (!pkcs) {
451       SILC_LOG_DEBUG(("Unsupported PKCS algorithm: rsa"));
452       goto err;
453     }
454     silc_pubkey->pkcs = pkcs;
455
456     if (keydata_len < 4)
457       goto err;
458     SILC_GET32_MSB(e_len, key_data);
459     if (!e_len || e_len + 4 > keydata_len)
460       goto err;
461     silc_mp_init(&e);
462     silc_mp_bin2mp(key_data + 4, e_len, &e);
463     if (keydata_len < 4 + e_len + 4) {
464       silc_mp_uninit(&e);
465       goto err;
466     }
467     SILC_GET32_MSB(n_len, key_data + 4 + e_len);
468     if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
469       silc_mp_uninit(&e);
470       goto err;
471     }
472     silc_mp_init(&n);
473     silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
474
475     /* Encode to PKCS #1 format */
476     memset(&alg_key, 0, sizeof(alg_key));
477     if (!silc_asn1_encode(asn1, &alg_key,
478                           SILC_ASN1_SEQUENCE,
479                             SILC_ASN1_INT(&n),
480                             SILC_ASN1_INT(&e),
481                           SILC_ASN1_END, SILC_ASN1_END)) {
482       silc_mp_uninit(&e);
483       silc_mp_uninit(&n);
484       goto err;
485     }
486
487     silc_mp_uninit(&e);
488     silc_mp_uninit(&n);
489
490   } else if (!strcmp(pkcs_name, "dsa")) {
491     SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
492     goto err;
493
494   } else {
495     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
496     goto err;
497   }
498
499   /* Import PKCS algorithm public key */
500   if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
501                                &silc_pubkey->public_key))
502     goto err;
503
504   silc_free(pkcs_name);
505   silc_free(ident);
506   silc_asn1_free(asn1);
507
508   *ret_public_key = silc_pubkey;
509
510   return key_len;
511
512  err:
513   silc_free(pkcs_name);
514   silc_free(ident);
515   silc_free(silc_pubkey);
516   if (asn1)
517     silc_asn1_free(asn1);
518   return 0;
519 }
520
521 /* Exports public key as SILC protocol style public key file */
522
523 unsigned char *
524 silc_pkcs_silc_export_public_key_file(void *public_key,
525                                       SilcPKCSFileEncoding encoding,
526                                       SilcUInt32 *ret_len)
527 {
528   SilcBuffer buf;
529   unsigned char *key, *data;
530   SilcUInt32 key_len;
531
532   SILC_LOG_DEBUG(("Encoding SILC public key file"));
533
534   /* Export key */
535   key = silc_pkcs_silc_export_public_key(public_key, &key_len);
536   if (!key)
537     return NULL;
538
539   switch (encoding) {
540   case SILC_PKCS_FILE_BIN:
541     break;
542
543   case SILC_PKCS_FILE_BASE64:
544     data = silc_base64_encode_file(key, key_len);
545     if (!data)
546       return NULL;
547     silc_free(key);
548     key = data;
549     key_len = strlen(data);
550     break;
551   }
552
553   /* Encode SILC public key file */
554   buf = silc_buffer_alloc_size(key_len +
555                                (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
556                                 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
557   if (!buf) {
558     silc_free(key);
559     return NULL;
560   }
561
562   if (silc_buffer_format(buf,
563                          SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
564                          SILC_STR_UI_XNSTRING(key, key_len),
565                          SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
566                          SILC_STR_END) < 0) {
567     silc_buffer_free(buf);
568     silc_free(key);
569     return NULL;
570   }
571
572   silc_free(key);
573   key = silc_buffer_steal(buf, ret_len);
574   silc_buffer_free(buf);
575
576   return key;
577 }
578
579 /* Exports public key as SILC protocol style public key */
580
581 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
582                                                 SilcUInt32 *ret_len)
583 {
584   SilcSILCPublicKey silc_pubkey = public_key;
585   const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
586   SilcBufferStruct alg_key;
587   SilcBuffer buf = NULL;
588   SilcAsn1 asn1 = NULL;
589   unsigned char *pk = NULL, *key = NULL, *ret;
590   SilcUInt32 pk_len, key_len, totlen;
591   char *identifier;
592
593   SILC_LOG_DEBUG(("Encoding SILC public key"));
594
595   /* Export PKCS algorithm public key */
596   if (pkcs->export_public_key)
597     pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
598   if (!pk) {
599     SILC_LOG_ERROR(("Error exporting PKCS algorithm key"));
600     return NULL;
601   }
602   silc_buffer_set(&alg_key, pk, pk_len);
603
604   /* Encode identifier */
605   identifier =
606     silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
607                                      silc_pubkey->identifier.host,
608                                      silc_pubkey->identifier.realname,
609                                      silc_pubkey->identifier.email,
610                                      silc_pubkey->identifier.org,
611                                      silc_pubkey->identifier.country,
612                                      silc_pubkey->identifier.version);
613   if (!identifier) {
614     SILC_LOG_ERROR(("Error encoding SILC public key identifier"));
615     goto err;
616   }
617
618   asn1 = silc_asn1_alloc();
619   if (!asn1)
620     goto err;
621
622   if (!strcmp(pkcs->name, "rsa")) {
623     /* Parse the PKCS #1 public key */
624     SilcMPInt n, e;
625     SilcUInt32 n_len, e_len;
626     unsigned char *nb, *eb;
627
628     memset(&n, 0, sizeof(n));
629     memset(&e, 0, sizeof(e));
630     if (!silc_asn1_decode(asn1, &alg_key,
631                           SILC_ASN1_SEQUENCE,
632                             SILC_ASN1_INT(&n),
633                             SILC_ASN1_INT(&e),
634                           SILC_ASN1_END, SILC_ASN1_END))
635       goto err;
636
637     /* Encode to SILC RSA public key */
638     eb = silc_mp_mp2bin(&e, 0, &e_len);
639     if (!eb)
640       goto err;
641     nb = silc_mp_mp2bin(&n, 0, &n_len);
642     if (!nb)
643       goto err;
644     key_len = e_len + 4 + n_len + 4;
645     key = silc_calloc(key_len, sizeof(*key));
646     if (!key)
647       goto err;
648
649     /* Put e length and e */
650     SILC_PUT32_MSB(e_len, key);
651     memcpy(key + 4, eb, e_len);
652
653     /* Put n length and n. */
654     SILC_PUT32_MSB(n_len, key + 4 + e_len);
655     memcpy(key + 4 + e_len + 4, nb, n_len);
656
657     silc_free(nb);
658     silc_free(eb);
659
660   } else if (!strcmp(pkcs->name, "dsa")) {
661     SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
662     goto err;
663
664   } else {
665     SILC_LOG_ERROR(("Unsupported PKCS algorithm: %s", pkcs->name));
666     goto err;
667   }
668
669   /* Encode SILC Public Key */
670   totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
671   buf = silc_buffer_alloc_size(totlen + 4);
672   if (!buf)
673     goto err;
674   if (silc_buffer_format(buf,
675                          SILC_STR_UI_INT(totlen),
676                          SILC_STR_UI_SHORT(strlen(pkcs->name)),
677                          SILC_STR_UI32_STRING(pkcs->name),
678                          SILC_STR_UI_SHORT(strlen(identifier)),
679                          SILC_STR_UI32_STRING(identifier),
680                          SILC_STR_UI_XNSTRING(key, key_len),
681                          SILC_STR_END) < 0)
682     goto err;
683
684   ret = silc_buffer_steal(buf, ret_len);
685   silc_buffer_free(buf);
686   silc_free(key);
687   silc_free(identifier);
688   silc_buffer_purge(&alg_key);
689   silc_asn1_free(asn1);
690
691   return ret;
692
693  err:
694   silc_free(identifier);
695   silc_free(pk);
696   silc_free(key);
697   if (buf)
698     silc_buffer_free(buf);
699   if (asn1)
700     silc_asn1_free(asn1);
701   return NULL;
702 }
703
704 /* Return key length */
705
706 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
707 {
708   SilcSILCPublicKey silc_pubkey = public_key;
709   return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
710 }
711
712 /* Copy public key */
713
714 void *silc_pkcs_silc_public_key_copy(void *public_key)
715 {
716   SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
717   SilcPublicKeyIdentifier ident = &silc_pubkey->identifier;
718
719   new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
720   if (!new_pubkey)
721     return NULL;
722   new_pubkey->pkcs = silc_pubkey->pkcs;
723
724   new_pubkey->public_key =
725     silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
726   if (!new_pubkey->public_key) {
727     silc_free(new_pubkey);
728     return NULL;
729   }
730
731   if (ident->username)
732     new_pubkey->identifier.username =
733       silc_memdup(ident->username, strlen(ident->username));
734   if (ident->host)
735     new_pubkey->identifier.host =
736       silc_memdup(ident->host, strlen(ident->host));
737   if (ident->realname)
738     new_pubkey->identifier.realname =
739       silc_memdup(ident->realname, strlen(ident->realname));
740   if (ident->email)
741     new_pubkey->identifier.email =
742       silc_memdup(ident->email, strlen(ident->email));
743   if (ident->org)
744     new_pubkey->identifier.org =
745       silc_memdup(ident->org, strlen(ident->org));
746   if (ident->country)
747     new_pubkey->identifier.country =
748       silc_memdup(ident->country, strlen(ident->country));
749   if (ident->version)
750     new_pubkey->identifier.version =
751       silc_memdup(ident->version, strlen(ident->version));
752
753   return new_pubkey;
754 }
755
756 /* Compares public keys */
757
758 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
759 {
760   SilcSILCPublicKey k1 = key1, k2 = key2;
761
762   if (strcmp(k1->pkcs->name, k2->pkcs->name))
763     return FALSE;
764
765   if ((k1->identifier.username && !k2->identifier.username) ||
766       (!k1->identifier.username && k2->identifier.username) ||
767       (k1->identifier.username && k2->identifier.username &&
768        strcmp(k1->identifier.username, k2->identifier.username)))
769     return FALSE;
770
771   if ((k1->identifier.host && !k2->identifier.host) ||
772       (!k1->identifier.host && k2->identifier.host) ||
773       (k1->identifier.host && k2->identifier.host &&
774        strcmp(k1->identifier.host, k2->identifier.host)))
775     return FALSE;
776
777   if ((k1->identifier.realname && !k2->identifier.realname) ||
778       (!k1->identifier.realname && k2->identifier.realname) ||
779       (k1->identifier.realname && k2->identifier.realname &&
780        strcmp(k1->identifier.realname, k2->identifier.realname)))
781     return FALSE;
782
783   if ((k1->identifier.email && !k2->identifier.email) ||
784       (!k1->identifier.email && k2->identifier.email) ||
785       (k1->identifier.email && k2->identifier.email &&
786        strcmp(k1->identifier.email, k2->identifier.email)))
787     return FALSE;
788
789   if ((k1->identifier.org && !k2->identifier.org) ||
790       (!k1->identifier.org && k2->identifier.org) ||
791       (k1->identifier.org && k2->identifier.org &&
792        strcmp(k1->identifier.org, k2->identifier.org)))
793     return FALSE;
794
795   if ((k1->identifier.country && !k2->identifier.country) ||
796       (!k1->identifier.country && k2->identifier.country) ||
797       (k1->identifier.country && k2->identifier.country &&
798        strcmp(k1->identifier.country, k2->identifier.country)))
799     return FALSE;
800
801   if ((k1->identifier.version && !k2->identifier.version) ||
802       (!k1->identifier.version && k2->identifier.version) ||
803       (k1->identifier.version && k2->identifier.version &&
804        strcmp(k1->identifier.version, k2->identifier.version)))
805     return FALSE;
806
807   return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
808 }
809
810 /* Frees public key */
811
812 void silc_pkcs_silc_public_key_free(void *public_key)
813 {
814   SilcSILCPublicKey silc_pubkey = public_key;
815
816   silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
817
818   silc_free(silc_pubkey->identifier.username);
819   silc_free(silc_pubkey->identifier.host);
820   silc_free(silc_pubkey->identifier.realname);
821   silc_free(silc_pubkey->identifier.email);
822   silc_free(silc_pubkey->identifier.org);
823   silc_free(silc_pubkey->identifier.country);
824   silc_free(silc_pubkey->identifier.version);
825   silc_free(silc_pubkey);
826 }
827
828
829 /*************************** Private key routines ****************************/
830
831 /* Private key file magic */
832 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
833
834 /* Imports SILC implementation style private key file */
835
836 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
837                                                 SilcUInt32 filedata_len,
838                                                 const char *passphrase,
839                                                 SilcUInt32 passphrase_len,
840                                                 SilcPKCSFileEncoding encoding,
841                                                 void **ret_private_key)
842 {
843   SilcCipher aes;
844   SilcHash sha1;
845   SilcHmac sha1hmac;
846   SilcUInt32 blocklen;
847   unsigned char tmp[32], keymat[64], *data = NULL;
848   SilcUInt32 i, len, magic, mac_len;
849   int ret;
850
851   SILC_LOG_DEBUG(("Parsing SILC private key file"));
852
853   /* Check start of file and remove header from the data. */
854   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
855   if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)) {
856     SILC_LOG_ERROR(("Malformed SILC private key header"));
857     return FALSE;
858   }
859   for (i = 0; i < len; i++) {
860     if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
861       SILC_LOG_ERROR(("Malformed SILC private key header"));
862       return FALSE;
863     }
864     filedata++;
865   }
866
867   len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
868                         strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
869
870   switch (encoding) {
871   case SILC_PKCS_FILE_BIN:
872     break;
873
874   case SILC_PKCS_FILE_BASE64:
875     data = silc_base64_decode(filedata, filedata_len, &len);
876     if (!data)
877       return FALSE;
878     filedata = data;
879     break;
880   }
881
882   memset(tmp, 0, sizeof(tmp));
883   memset(keymat, 0, sizeof(keymat));
884
885   /* Check file magic */
886   SILC_GET32_MSB(magic, filedata);
887   if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
888     SILC_LOG_DEBUG(("Private key does not have correct magic"));
889     return FALSE;
890   }
891
892   /* Allocate the AES cipher */
893   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
894     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
895     return FALSE;
896   }
897   blocklen = silc_cipher_get_block_len(aes);
898   if (blocklen * 2 > sizeof(tmp)) {
899     silc_cipher_free(aes);
900     return FALSE;
901   }
902
903   /* Allocate SHA1 hash */
904   if (!silc_hash_alloc("sha1", &sha1)) {
905     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
906     silc_cipher_free(aes);
907     return FALSE;
908   }
909
910   /* Allocate HMAC */
911   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
912     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
913     silc_hash_free(sha1);
914     silc_cipher_free(aes);
915     return FALSE;
916   }
917
918   /* Derive the decryption key from the provided key material.  The key
919      is 256 bits length, and derived by taking hash of the data, then
920      re-hashing the data and the previous digest, and using the first and
921      second digest as the key. */
922   silc_hash_init(sha1);
923   silc_hash_update(sha1, passphrase, passphrase_len);
924   silc_hash_final(sha1, keymat);
925   silc_hash_init(sha1);
926   silc_hash_update(sha1, passphrase, passphrase_len);
927   silc_hash_update(sha1, keymat, 16);
928   silc_hash_final(sha1, keymat + 16);
929
930   /* Set the key to the cipher */
931   silc_cipher_set_key(aes, keymat, 256, FALSE);
932
933   /* First, verify the MAC of the private key data */
934   mac_len = silc_hmac_len(sha1hmac);
935   silc_hmac_init_with_key(sha1hmac, keymat, 16);
936   silc_hmac_update(sha1hmac, filedata, len - mac_len);
937   silc_hmac_final(sha1hmac, tmp, NULL);
938   if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
939     SILC_LOG_DEBUG(("Integrity check for private key failed"));
940     memset(keymat, 0, sizeof(keymat));
941     memset(tmp, 0, sizeof(tmp));
942     silc_hmac_free(sha1hmac);
943     silc_hash_free(sha1);
944     silc_cipher_free(aes);
945     return FALSE;
946   }
947   filedata += 4;
948   len -= 4;
949
950   /* Decrypt the private key buffer */
951   silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
952   SILC_GET32_MSB(i, filedata);
953   if (i > len) {
954     SILC_LOG_DEBUG(("Bad private key length in buffer!"));
955     memset(keymat, 0, sizeof(keymat));
956     memset(tmp, 0, sizeof(tmp));
957     silc_hmac_free(sha1hmac);
958     silc_hash_free(sha1);
959     silc_cipher_free(aes);
960     return FALSE;
961   }
962   filedata += 4;
963   len = i;
964
965   /* Cleanup */
966   memset(keymat, 0, sizeof(keymat));
967   memset(tmp, 0, sizeof(tmp));
968   silc_hmac_free(sha1hmac);
969   silc_hash_free(sha1);
970   silc_cipher_free(aes);
971
972   /* Import the private key */
973   ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
974
975   silc_free(data);
976
977   return ret ? TRUE : FALSE;
978 }
979
980 /* Private key version */
981 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
982 #define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
983
984 /* Imports SILC implementation style private key */
985
986 int silc_pkcs_silc_import_private_key(unsigned char *key,
987                                       SilcUInt32 key_len,
988                                       void **ret_private_key)
989 {
990   SilcBufferStruct buf;
991   const SilcPKCSAlgorithm *pkcs;
992   SilcBufferStruct alg_key;
993   SilcSILCPrivateKey silc_privkey = NULL;
994   SilcAsn1 asn1 = NULL;
995   SilcUInt16 pkcs_len;
996   SilcUInt32 keydata_len;
997   unsigned char *pkcs_name = NULL, *key_data;
998   int ret;
999
1000   SILC_LOG_DEBUG(("Parsing SILC private key"));
1001
1002   if (!ret_private_key)
1003     return 0;
1004
1005   silc_buffer_set(&buf, key, key_len);
1006
1007   /* Get algorithm name and identifier */
1008   ret =
1009     silc_buffer_unformat(&buf,
1010                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1011                          SILC_STR_END);
1012   if (ret == -1) {
1013     SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1014     goto err;
1015   }
1016
1017   if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
1018     SILC_LOG_DEBUG(("Malformed private key buffer"));
1019     goto err;
1020   }
1021
1022   /* Get key data. We assume that rest of the buffer is key data. */
1023   silc_buffer_pull(&buf, 2 + pkcs_len);
1024   keydata_len = silc_buffer_len(&buf);
1025   ret = silc_buffer_unformat(&buf,
1026                              SILC_STR_UI_XNSTRING(&key_data, keydata_len),
1027                              SILC_STR_END);
1028   if (ret == -1)
1029     goto err;
1030
1031   /* Allocate SILC private key context */
1032   silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
1033   if (!silc_privkey)
1034     goto err;
1035
1036   asn1 = silc_asn1_alloc();
1037   if (!asn1)
1038     goto err;
1039
1040   if (!strcmp(pkcs_name, "rsa")) {
1041     /* Parse the RSA SILC private key */
1042     SilcBufferStruct k;
1043     SilcMPInt n, e, d, dp, dq, qp, p, q;
1044     unsigned char *tmp;
1045     SilcUInt32 len, ver;
1046
1047     if (keydata_len < 4)
1048       goto err;
1049     silc_buffer_set(&k, key_data, keydata_len);
1050
1051     /* Get version.  Key without the version is old style private key
1052        and we need to do some computation to get it to correct format. */
1053     if (silc_buffer_unformat(&k,
1054                              SILC_STR_UI_INT(&ver),
1055                              SILC_STR_END) < 0)
1056       goto err;
1057     silc_buffer_pull(&k, 4);
1058
1059     if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1060         ver != SILC_PRIVATE_KEY_VERSION_2) {
1061       len = ver;
1062       ver = 0;
1063     } else {
1064       if (silc_buffer_unformat(&k,
1065                                SILC_STR_UI_INT(&len),
1066                                SILC_STR_END) < 0)
1067         goto err;
1068       silc_buffer_pull(&k, 4);
1069     }
1070
1071     /* Get PKCS object.  Different PKCS #1 scheme is used with different
1072        versions. */
1073     if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1074       /* Version 0 and 1 */
1075       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1076     } else {
1077       /* Version 2 and newer */
1078       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1079     }
1080     if (!pkcs) {
1081       SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1082       goto err;
1083     }
1084     silc_privkey->pkcs = pkcs;
1085
1086     SILC_LOG_DEBUG(("Private key version %s",
1087                     (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1088                      ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1089
1090     /* Get e */
1091     if (silc_buffer_unformat(&k,
1092                              SILC_STR_DATA(&tmp, len),
1093                              SILC_STR_END) < 0)
1094       goto err;
1095     silc_mp_init(&e);
1096     silc_mp_bin2mp(tmp, len, &e);
1097     silc_buffer_pull(&k, len);
1098
1099     /* Get n */
1100     if (silc_buffer_unformat(&k,
1101                              SILC_STR_UI_INT(&len),
1102                              SILC_STR_END) < 0)
1103       goto err;
1104     silc_buffer_pull(&k, 4);
1105     if (silc_buffer_unformat(&k,
1106                              SILC_STR_DATA(&tmp, len),
1107                              SILC_STR_END) < 0)
1108       goto err;
1109     silc_mp_init(&n);
1110     silc_mp_bin2mp(tmp, len, &n);
1111     silc_buffer_pull(&k, len);
1112
1113     /* Get d */
1114     if (silc_buffer_unformat(&k,
1115                              SILC_STR_UI_INT(&len),
1116                              SILC_STR_END) < 0)
1117       goto err;
1118     silc_buffer_pull(&k, 4);
1119     if (silc_buffer_unformat(&k,
1120                              SILC_STR_DATA(&tmp, len),
1121                              SILC_STR_END) < 0)
1122       goto err;
1123     silc_mp_init(&d);
1124     silc_mp_bin2mp(tmp, len, &d);
1125     silc_buffer_pull(&k, len);
1126
1127     /* Get dP */
1128     if (silc_buffer_unformat(&k,
1129                              SILC_STR_UI_INT(&len),
1130                              SILC_STR_END) < 0)
1131       goto err;
1132     silc_buffer_pull(&k, 4);
1133     if (silc_buffer_unformat(&k,
1134                              SILC_STR_DATA(&tmp, len),
1135                              SILC_STR_END) < 0)
1136       goto err;
1137     silc_mp_init(&dp);
1138     silc_mp_bin2mp(tmp, len, &dp);
1139     silc_buffer_pull(&k, len);
1140
1141     /* Get dQ */
1142     if (silc_buffer_unformat(&k,
1143                              SILC_STR_UI_INT(&len),
1144                              SILC_STR_END) < 0)
1145       goto err;
1146     silc_buffer_pull(&k, 4);
1147     if (silc_buffer_unformat(&k,
1148                              SILC_STR_DATA(&tmp, len),
1149                              SILC_STR_END) < 0)
1150       goto err;
1151     silc_mp_init(&dq);
1152     silc_mp_bin2mp(tmp, len, &dq);
1153     silc_buffer_pull(&k, len);
1154
1155     if (ver == 0) {
1156       /* Old version */
1157
1158       /* Get pQ len */
1159       if (silc_buffer_unformat(&k,
1160                                SILC_STR_UI_INT(&len),
1161                                SILC_STR_END) < 0)
1162         goto err;
1163       silc_buffer_pull(&k, 4);
1164       if (silc_buffer_len(&k) < len)
1165         goto err;
1166       silc_buffer_pull(&k, len);
1167
1168       /* Get qP len */
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_len(&k) < len)
1175         goto err;
1176       silc_buffer_pull(&k, len);
1177     } else {
1178       /* New version */
1179
1180       /* Get qP */
1181       if (silc_buffer_unformat(&k,
1182                                SILC_STR_UI_INT(&len),
1183                                SILC_STR_END) < 0)
1184         goto err;
1185       silc_buffer_pull(&k, 4);
1186       if (silc_buffer_unformat(&k,
1187                                SILC_STR_DATA(&tmp, len),
1188                                SILC_STR_END) < 0)
1189         goto err;
1190       silc_mp_init(&qp);
1191       silc_mp_bin2mp(tmp, len, &qp);
1192       silc_buffer_pull(&k, len);
1193     }
1194
1195     /* Get p */
1196     if (silc_buffer_unformat(&k,
1197                              SILC_STR_UI_INT(&len),
1198                              SILC_STR_END) < 0)
1199       goto err;
1200     silc_buffer_pull(&k, 4);
1201     if (silc_buffer_unformat(&k,
1202                              SILC_STR_DATA(&tmp, len),
1203                              SILC_STR_END) < 0)
1204       goto err;
1205     silc_mp_init(&p);
1206     silc_mp_bin2mp(tmp, len, &p);
1207     silc_buffer_pull(&k, len);
1208
1209     /* Get q */
1210     if (silc_buffer_unformat(&k,
1211                              SILC_STR_UI_INT(&len),
1212                              SILC_STR_END) < 0)
1213       goto err;
1214     silc_buffer_pull(&k, 4);
1215     if (silc_buffer_unformat(&k,
1216                              SILC_STR_DATA(&tmp, len),
1217                              SILC_STR_END) < 0)
1218       goto err;
1219     silc_mp_init(&q);
1220     silc_mp_bin2mp(tmp, len, &q);
1221     silc_buffer_pull(&k, len);
1222
1223     if (ver == 0) {
1224       /* Old version.  Compute to new version */
1225       SILC_LOG_DEBUG(("Old version private key"));
1226       silc_mp_init(&qp);
1227       silc_mp_modinv(&qp, &q, &p);
1228     }
1229
1230     /* Encode to PKCS #1 format */
1231     memset(&alg_key, 0, sizeof(alg_key));
1232     if (!silc_asn1_encode(asn1, &alg_key,
1233                           SILC_ASN1_SEQUENCE,
1234                             SILC_ASN1_SHORT_INT(0),
1235                             SILC_ASN1_INT(&n),
1236                             SILC_ASN1_INT(&e),
1237                             SILC_ASN1_INT(&d),
1238                             SILC_ASN1_INT(&p),
1239                             SILC_ASN1_INT(&q),
1240                             SILC_ASN1_INT(&dp),
1241                             SILC_ASN1_INT(&dq),
1242                             SILC_ASN1_INT(&qp),
1243                           SILC_ASN1_END, SILC_ASN1_END))
1244       goto err;
1245
1246     silc_mp_uninit(&n);
1247     silc_mp_uninit(&e);
1248     silc_mp_uninit(&e);
1249     silc_mp_uninit(&d);
1250     silc_mp_uninit(&p);
1251     silc_mp_uninit(&q);
1252     silc_mp_uninit(&dp);
1253     silc_mp_uninit(&dq);
1254     silc_mp_uninit(&qp);
1255
1256   } else if (!strcmp(pkcs_name, "dsa")) {
1257     SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1258     goto err;
1259
1260   } else {
1261     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1262     goto err;
1263   }
1264
1265   /* Import PKCS algorithm private key */
1266   if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1267                                 &silc_privkey->private_key))
1268     goto err;
1269
1270   silc_free(pkcs_name);
1271   silc_asn1_free(asn1);
1272
1273   *ret_private_key = silc_privkey;
1274
1275   return key_len;
1276
1277  err:
1278   silc_free(pkcs_name);
1279   silc_free(silc_privkey);
1280   if (asn1)
1281     silc_asn1_free(asn1);
1282   SILC_LOG_ERROR(("Malformed SILC private key "));
1283   return 0;
1284 }
1285
1286 /* Exports private key as SILC implementation style private key file */
1287
1288 unsigned char *
1289 silc_pkcs_silc_export_private_key_file(void *private_key,
1290                                        const char *passphrase,
1291                                        SilcUInt32 passphrase_len,
1292                                        SilcPKCSFileEncoding encoding,
1293                                        SilcRng rng,
1294                                        SilcUInt32 *ret_len)
1295 {
1296   SilcCipher aes;
1297   SilcHash sha1;
1298   SilcHmac sha1hmac;
1299   SilcBuffer buf, enc;
1300   SilcUInt32 len, blocklen, padlen, key_len;
1301   unsigned char *key, *data;
1302   unsigned char tmp[32], keymat[64];
1303   int i;
1304
1305   SILC_LOG_DEBUG(("Encoding SILC private key file"));
1306
1307   /* Export the private key */
1308   key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1309   if (!key)
1310     return NULL;
1311
1312   memset(tmp, 0, sizeof(tmp));
1313   memset(keymat, 0, sizeof(keymat));
1314
1315   /* Allocate the AES cipher */
1316   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1317     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1318     silc_free(key);
1319     return NULL;
1320   }
1321   blocklen = silc_cipher_get_block_len(aes);
1322   if (blocklen * 2 > sizeof(tmp)) {
1323     silc_cipher_free(aes);
1324     silc_free(key);
1325     return NULL;
1326   }
1327
1328   /* Allocate SHA1 hash */
1329   if (!silc_hash_alloc("sha1", &sha1)) {
1330     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1331     silc_cipher_free(aes);
1332     return NULL;
1333   }
1334
1335   /* Allocate HMAC */
1336   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1337     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1338     silc_hash_free(sha1);
1339     silc_cipher_free(aes);
1340     return NULL;
1341   }
1342
1343   /* Derive the encryption key from the provided key material.  The key
1344      is 256 bits length, and derived by taking hash of the data, then
1345      re-hashing the data and the previous digest, and using the first and
1346      second digest as the key. */
1347   silc_hash_init(sha1);
1348   silc_hash_update(sha1, passphrase, passphrase_len);
1349   silc_hash_final(sha1, keymat);
1350   silc_hash_init(sha1);
1351   silc_hash_update(sha1, passphrase, passphrase_len);
1352   silc_hash_update(sha1, keymat, 16);
1353   silc_hash_final(sha1, keymat + 16);
1354
1355   /* Set the key to the cipher */
1356   silc_cipher_set_key(aes, keymat, 256, TRUE);
1357
1358   /* Encode the buffer to be encrypted.  Add padding to it too, at least
1359      block size of the cipher. */
1360
1361   /* Allocate buffer for encryption */
1362   len = silc_hmac_len(sha1hmac);
1363   padlen = 16 + (16 - ((key_len + 4) % blocklen));
1364   enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1365   if (!enc) {
1366     silc_hmac_free(sha1hmac);
1367     silc_hash_free(sha1);
1368     silc_cipher_free(aes);
1369     return FALSE;
1370   }
1371
1372   /* Generate padding */
1373   for (i = 0; i < padlen; i++)
1374     tmp[i] = silc_rng_get_byte_fast(rng);
1375
1376   /* Put magic number */
1377   SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1378   silc_buffer_pull(enc, 4);
1379
1380   /* Encode the buffer */
1381   silc_buffer_format(enc,
1382                      SILC_STR_UI_INT(key_len),
1383                      SILC_STR_UI_XNSTRING(key, key_len),
1384                      SILC_STR_UI_XNSTRING(tmp, padlen),
1385                      SILC_STR_END);
1386   silc_free(key);
1387
1388   /* Encrypt. */
1389   silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1390                       silc_cipher_get_iv(aes));
1391
1392   silc_buffer_push(enc, 4);
1393
1394   /* Compute HMAC over the encrypted data and append the MAC to data.
1395      The key is the first digest of the original key material. */
1396   key_len = silc_buffer_len(enc) - len;
1397   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1398   silc_hmac_update(sha1hmac, enc->data, key_len);
1399   silc_buffer_pull(enc, key_len);
1400   silc_hmac_final(sha1hmac, enc->data, NULL);
1401   silc_buffer_push(enc, key_len);
1402
1403   /* Cleanup */
1404   memset(keymat, 0, sizeof(keymat));
1405   memset(tmp, 0, sizeof(tmp));
1406   silc_hmac_free(sha1hmac);
1407   silc_hash_free(sha1);
1408   silc_cipher_free(aes);
1409
1410   switch (encoding) {
1411   case SILC_PKCS_FILE_BIN:
1412     break;
1413
1414   case SILC_PKCS_FILE_BASE64:
1415     data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
1416     if (!data) {
1417       silc_buffer_clear(enc);
1418       silc_buffer_free(enc);
1419       return NULL;
1420     }
1421     silc_free(silc_buffer_steal(enc, NULL));
1422     silc_buffer_set(enc, data, strlen(data));
1423     break;
1424   }
1425
1426   key = enc->data;
1427   key_len = silc_buffer_len(enc);
1428
1429   /* Encode the data and save to file */
1430   len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1431                    strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1432   buf = silc_buffer_alloc_size(len);
1433   if (!buf) {
1434     silc_buffer_free(enc);
1435     return NULL;
1436   }
1437   silc_buffer_format(buf,
1438                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1439                      SILC_STR_UI_XNSTRING(key, key_len),
1440                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1441                      SILC_STR_END);
1442
1443   silc_buffer_free(enc);
1444   data = silc_buffer_steal(buf, ret_len);
1445   silc_buffer_free(buf);
1446
1447   return data;
1448 }
1449
1450 /* Exports private key as SILC implementation style private key */
1451
1452 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1453                                                  SilcUInt32 *ret_len)
1454 {
1455   SilcSILCPrivateKey silc_privkey = private_key;
1456   const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1457   SilcBufferStruct alg_key;
1458   SilcBuffer buf = NULL;
1459   SilcAsn1 asn1 = NULL;
1460   unsigned char *prv = NULL, *key = NULL, *ret;
1461   SilcUInt32 prv_len, key_len, totlen;
1462
1463   SILC_LOG_DEBUG(("Encoding SILC private key"));
1464
1465   /* Export PKCS algorithm private key */
1466   if (pkcs->export_private_key)
1467     prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1468   if (!prv)
1469     return NULL;
1470   silc_buffer_set(&alg_key, prv, prv_len);
1471
1472   asn1 = silc_asn1_alloc();
1473   if (!asn1)
1474     goto err;
1475
1476   if (!strcmp(pkcs->name, "rsa")) {
1477     /* Parse the PKCS #1 private key */
1478     SilcMPInt n, e, d, dp, dq, qp, p, q;
1479     SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1480       qp_len, p_len, q_len, len = 0;
1481     unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1482
1483     if (!silc_asn1_decode(asn1, &alg_key,
1484                           SILC_ASN1_SEQUENCE,
1485                             SILC_ASN1_INT(NULL),
1486                             SILC_ASN1_INT(&n),
1487                             SILC_ASN1_INT(&e),
1488                             SILC_ASN1_INT(&d),
1489                             SILC_ASN1_INT(&p),
1490                             SILC_ASN1_INT(&q),
1491                             SILC_ASN1_INT(&dp),
1492                             SILC_ASN1_INT(&dq),
1493                             SILC_ASN1_INT(&qp),
1494                           SILC_ASN1_END, SILC_ASN1_END))
1495       goto err;
1496
1497     /* Encode to SILC RSA private key */
1498     eb = silc_mp_mp2bin(&e, 0, &e_len);
1499     nb = silc_mp_mp2bin(&n, 0, &n_len);
1500     db = silc_mp_mp2bin(&d, 0, &d_len);
1501     dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1502     dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1503     qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1504     pb = silc_mp_mp2bin(&p, 0, &p_len);
1505     qb = silc_mp_mp2bin(&q, 0, &q_len);
1506     len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1507       dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1508
1509     buf = silc_buffer_alloc_size(len);
1510     if (!buf)
1511       goto err;
1512     if (silc_buffer_format(buf,
1513                            SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1514                            SILC_STR_UI_INT(e_len),
1515                            SILC_STR_UI_XNSTRING(eb, e_len),
1516                            SILC_STR_UI_INT(n_len),
1517                            SILC_STR_UI_XNSTRING(nb, n_len),
1518                            SILC_STR_UI_INT(d_len),
1519                            SILC_STR_UI_XNSTRING(db, d_len),
1520                            SILC_STR_UI_INT(dp_len),
1521                            SILC_STR_UI_XNSTRING(dpb, dp_len),
1522                            SILC_STR_UI_INT(dq_len),
1523                            SILC_STR_UI_XNSTRING(dqb, dq_len),
1524                            SILC_STR_UI_INT(qp_len),
1525                            SILC_STR_UI_XNSTRING(qpb, qp_len),
1526                            SILC_STR_UI_INT(p_len),
1527                            SILC_STR_UI_XNSTRING(pb, p_len),
1528                            SILC_STR_UI_INT(q_len),
1529                            SILC_STR_UI_XNSTRING(qb, q_len),
1530                            SILC_STR_END) < 0)
1531       goto err;
1532
1533     key = silc_buffer_steal(buf, &key_len);
1534     silc_buffer_free(buf);
1535     silc_free(nb);
1536     silc_free(eb);
1537     silc_free(db);
1538     silc_free(dpb);
1539     silc_free(dqb);
1540     silc_free(qpb);
1541     silc_free(pb);
1542     silc_free(qb);
1543
1544   } else if (!strcmp(pkcs->name, "dsa")) {
1545     SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1546     goto err;
1547
1548   } else {
1549     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1550     goto err;
1551   }
1552
1553   /* Encode SILC private key */
1554   totlen = 2 + strlen(pkcs->name) + key_len;
1555   buf = silc_buffer_alloc_size(totlen);
1556   if (!buf)
1557     goto err;
1558   if (silc_buffer_format(buf,
1559                          SILC_STR_UI_SHORT(strlen(pkcs->name)),
1560                          SILC_STR_UI32_STRING(pkcs->name),
1561                          SILC_STR_UI_XNSTRING(key, key_len),
1562                          SILC_STR_END) < 0)
1563     goto err;
1564
1565   ret = silc_buffer_steal(buf, ret_len);
1566   silc_buffer_free(buf);
1567   silc_free(prv);
1568   silc_free(key);
1569   silc_asn1_free(asn1);
1570
1571   return ret;
1572
1573  err:
1574   silc_free(prv);
1575   silc_free(key);
1576   if (buf)
1577     silc_buffer_free(buf);
1578   return NULL;
1579 }
1580
1581 /* Return key length */
1582
1583 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1584 {
1585   SilcSILCPrivateKey silc_privkey = private_key;
1586   return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1587 }
1588
1589 /* Frees private key */
1590
1591 void silc_pkcs_silc_private_key_free(void *private_key)
1592 {
1593   SilcSILCPrivateKey silc_privkey = private_key;
1594
1595   silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1596
1597   silc_free(silc_privkey);
1598 }
1599
1600
1601 /***************************** PKCS operations ******************************/
1602
1603 /* Encrypts as specified in SILC protocol specification */
1604
1605 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1606                                 unsigned char *src,
1607                                 SilcUInt32 src_len,
1608                                 unsigned char *dst,
1609                                 SilcUInt32 dst_size,
1610                                 SilcUInt32 *ret_dst_len,
1611                                 SilcRng rng)
1612 {
1613   SilcSILCPublicKey silc_pubkey = public_key;
1614
1615   if (!silc_pubkey->pkcs->encrypt)
1616     return FALSE;
1617
1618   return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1619                                     src, src_len,
1620                                     dst, dst_size, ret_dst_len, rng);
1621 }
1622
1623 /* Decrypts as specified in SILC protocol specification */
1624
1625 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1626                                 unsigned char *src,
1627                                 SilcUInt32 src_len,
1628                                 unsigned char *dst,
1629                                 SilcUInt32 dst_size,
1630                                 SilcUInt32 *ret_dst_len)
1631 {
1632   SilcSILCPrivateKey silc_privkey = private_key;
1633
1634   if (!silc_privkey->pkcs->decrypt)
1635     return FALSE;
1636
1637   return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1638                                      src, src_len,
1639                                      dst, dst_size, ret_dst_len);
1640 }
1641
1642 /* Signs as specified in SILC protocol specification */
1643
1644 SilcBool silc_pkcs_silc_sign(void *private_key,
1645                              unsigned char *src,
1646                              SilcUInt32 src_len,
1647                              unsigned char *signature,
1648                              SilcUInt32 signature_size,
1649                              SilcUInt32 *ret_signature_len,
1650                              SilcBool compute_hash,
1651                              SilcHash hash)
1652 {
1653   SilcSILCPrivateKey silc_privkey = private_key;
1654
1655   if (!silc_privkey->pkcs->sign)
1656     return FALSE;
1657
1658   return silc_privkey->pkcs->sign(silc_privkey->private_key,
1659                                   src, src_len,
1660                                   signature, signature_size,
1661                                   ret_signature_len, compute_hash, hash);
1662 }
1663
1664 /* Verifies as specified in SILC protocol specification */
1665
1666 SilcBool silc_pkcs_silc_verify(void *public_key,
1667                                unsigned char *signature,
1668                                SilcUInt32 signature_len,
1669                                unsigned char *data,
1670                                SilcUInt32 data_len,
1671                                SilcHash hash)
1672 {
1673   SilcSILCPublicKey silc_pubkey = public_key;
1674
1675   if (!silc_pubkey->pkcs->verify)
1676     return FALSE;
1677
1678   return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1679                                    signature, signature_len,
1680                                    data, data_len, hash);
1681 }