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