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