Added SILC Thread Queue API
[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 = (SilcPKCSObject *)pkcs;
89   (*ret_public_key)->alg = alg;
90   (*ret_public_key)->public_key = pubkey;
91
92   /* Allocate private key */
93   *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
94   if (!(*ret_private_key)) {
95     silc_free(pubkey);
96     silc_free(privkey);
97     silc_free(*ret_public_key);
98     return FALSE;
99   }
100   (*ret_private_key)->pkcs = (SilcPKCSObject *)pkcs;
101   (*ret_private_key)->alg = alg;
102   (*ret_private_key)->private_key = privkey;
103
104   /* Generate the algorithm key pair */
105   if (!alg->generate_key(alg, bits_key_len, rng, &pubkey->public_key,
106                          &privkey->private_key)) {
107     silc_free(pubkey);
108     silc_free(privkey);
109     silc_free(*ret_public_key);
110     silc_free(*ret_private_key);
111     return FALSE;
112   }
113
114   return TRUE;
115 }
116
117
118 /**************************** Utility functions ******************************/
119
120 /* Decodes the provided `identifier' */
121
122 SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
123                                           SilcPublicKeyIdentifier ident)
124 {
125   char *cp, *item;
126   int len;
127
128   /* Protocol says that at least UN and HN must be provided as identifier */
129   if (!strstr(identifier, "UN=") || !strstr(identifier, "HN=")) {
130     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
131                     "identifiers"));
132     return FALSE;
133   }
134
135   cp = (char *)identifier;
136   while (cp) {
137     len = strcspn(cp, ",");
138     if (len < 1) {
139       cp = NULL;
140       break;
141     }
142     if (len - 1 >= 0 && cp[len - 1] == '\\') {
143       while (cp) {
144         if (len + 1 > strlen(cp)) {
145           cp = NULL;
146           break;
147         }
148         cp += len + 1;
149         len = strcspn(cp, ",") + len;
150         if (len < 1) {
151           cp = NULL;
152           break;
153         }
154         if (len - 1 >= 0 && cp[len - 1] != '\\')
155           break;
156       }
157     }
158
159     if (!cp)
160       break;
161
162     item = silc_calloc(len + 1, sizeof(char));
163     if (!item)
164       return FALSE;
165     if (len > strlen(cp))
166       break;
167     memcpy(item, cp, len);
168
169     if (strstr(item, "UN="))
170       ident->username = strdup(item + strcspn(cp, "=") + 1);
171     else if (strstr(item, "HN="))
172       ident->host = strdup(item + strcspn(cp, "=") + 1);
173     else if (strstr(item, "RN="))
174       ident->realname = strdup(item + strcspn(cp, "=") + 1);
175     else if (strstr(item, "E="))
176       ident->email = strdup(item + strcspn(cp, "=") + 1);
177     else if (strstr(item, "O="))
178       ident->org = strdup(item + strcspn(cp, "=") + 1);
179     else if (strstr(item, "C="))
180       ident->country = strdup(item + strcspn(cp, "=") + 1);
181     else if (strstr(item, "V="))
182       ident->version = strdup(item + strcspn(cp, "=") + 1);
183
184     cp += len;
185     if (strlen(cp) < 1)
186       cp = NULL;
187     else
188       cp += 1;
189
190     if (item)
191       silc_free(item);
192   }
193
194   return TRUE;
195 }
196
197 /* Encodes and returns SILC public key identifier.  If some of the
198    arguments is NULL those are not encoded into the identifier string.
199    Protocol says that at least username and host must be provided. */
200
201 char *silc_pkcs_silc_encode_identifier(SilcStack stack,
202                                        char *username, char *host,
203                                        char *realname, char *email,
204                                        char *org, char *country,
205                                        char *version)
206 {
207   SilcBufferStruct buf;
208   char *identifier;
209
210   if (!username || !host) {
211     SILC_LOG_ERROR(("Public key identifier is missing UN and/or HN"));
212     return NULL;
213   }
214   if (strlen(username) < 1 || strlen(host) < 1)
215     return NULL;
216
217   memset(&buf, 0, sizeof(buf));
218
219   if (username)
220     silc_buffer_sformat(stack, &buf,
221                         SILC_STR_ADVANCE,
222                         SILC_STR_UI32_STRING("UN="),
223                         SILC_STR_UI32_STRING(username),
224                         SILC_STR_END);
225
226   if (host)
227     silc_buffer_sformat(stack, &buf,
228                         SILC_STR_ADVANCE,
229                         SILC_STR_UI32_STRING(", "),
230                         SILC_STR_UI32_STRING("HN="),
231                         SILC_STR_UI32_STRING(host),
232                         SILC_STR_END);
233
234   if (realname)
235     silc_buffer_sformat(stack, &buf,
236                         SILC_STR_ADVANCE,
237                         SILC_STR_UI32_STRING(", "),
238                         SILC_STR_UI32_STRING("RN="),
239                         SILC_STR_UI32_STRING(realname),
240                         SILC_STR_END);
241
242   if (email)
243     silc_buffer_sformat(stack, &buf,
244                         SILC_STR_ADVANCE,
245                         SILC_STR_UI32_STRING(", "),
246                         SILC_STR_UI32_STRING("E="),
247                         SILC_STR_UI32_STRING(email),
248                         SILC_STR_END);
249
250   if (org)
251     silc_buffer_sformat(stack, &buf,
252                         SILC_STR_ADVANCE,
253                         SILC_STR_UI32_STRING(", "),
254                         SILC_STR_UI32_STRING("O="),
255                         SILC_STR_UI32_STRING(org),
256                         SILC_STR_END);
257
258   if (country)
259     silc_buffer_sformat(stack, &buf,
260                         SILC_STR_ADVANCE,
261                         SILC_STR_UI32_STRING(", "),
262                         SILC_STR_UI32_STRING("C="),
263                         SILC_STR_UI32_STRING(country),
264                         SILC_STR_END);
265
266   if (version) {
267     if (strlen(version) > 1 || !isdigit(version[0])) {
268       silc_buffer_spurge(stack, &buf);
269       SILC_LOG_ERROR(("Public key identifier has invalid version (V)"));
270       return NULL;
271     }
272     silc_buffer_sformat(stack, &buf,
273                         SILC_STR_ADVANCE,
274                         SILC_STR_UI32_STRING(", "),
275                         SILC_STR_UI32_STRING("V="),
276                         SILC_STR_UI32_STRING(version),
277                         SILC_STR_END);
278   }
279
280   silc_buffer_sformat(stack, &buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
281
282   identifier = silc_buffer_steal(&buf, NULL);
283   return identifier;
284 }
285
286 /* Return SILC public key version */
287
288 int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
289 {
290   SilcSILCPublicKey silc_pubkey;
291
292   if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
293     return -1;
294
295   silc_pubkey = public_key->public_key;
296
297   /* If version identifire is not present it is version 1. */
298   if (!silc_pubkey->identifier.version)
299     return 1;
300
301   return atoi(silc_pubkey->identifier.version);
302 }
303
304 /*************************** Public key routines *****************************/
305
306 /* Returns PKCS algorithm context */
307
308 SILC_PKCS_GET_ALGORITHM(silc_pkcs_silc_get_algorithm)
309 {
310   SilcSILCPublicKey silc_pubkey = public_key;
311   return silc_pubkey->pkcs;
312 }
313
314 /* Imports SILC protocol style public key from SILC public key file */
315
316 SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_pkcs_silc_import_public_key_file)
317 {
318   SilcUInt32 i, len;
319   unsigned char *data = NULL;
320   int ret;
321
322   SILC_LOG_DEBUG(("Parsing SILC public key file"));
323
324   if (!ret_public_key)
325     return FALSE;
326
327   /* Check start of file and remove header from the data. */
328   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
329   if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END)) {
330     SILC_LOG_DEBUG(("Malformed SILC public key header"));
331     return FALSE;
332   }
333   for (i = 0; i < len; i++) {
334     if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
335       SILC_LOG_DEBUG(("Malformed SILC public key header"));
336       return FALSE;
337     }
338     filedata++;
339   }
340   filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
341                    strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
342
343   switch (encoding) {
344   case SILC_PKCS_FILE_BIN:
345     break;
346
347   case SILC_PKCS_FILE_BASE64:
348     data = silc_base64_decode(NULL, filedata, filedata_len, &filedata_len);
349     if (!data)
350       return FALSE;
351     filedata = data;
352     break;
353   }
354
355   ret = silc_pkcs_silc_import_public_key(pkcs, NULL, filedata, filedata_len,
356                                          ret_public_key, ret_alg);
357   silc_free(data);
358
359   return ret ? TRUE : FALSE;
360 }
361
362 /* Imports SILC protocol style public key */
363
364 SILC_PKCS_IMPORT_PUBLIC_KEY(silc_pkcs_silc_import_public_key)
365 {
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(NULL);
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       alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
446     } else {
447       /* Version 2 and newer */
448       alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
449     }
450     if (!alg) {
451       SILC_LOG_DEBUG(("Unsupported PKCS algorithm: rsa"));
452       goto err;
453     }
454     silc_pubkey->pkcs = alg;
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 (!alg->import_public_key(alg, 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   *ret_alg = alg;
510
511   return key_len;
512
513  err:
514   silc_free(pkcs_name);
515   silc_free(ident);
516   silc_free(silc_pubkey);
517   if (asn1)
518     silc_asn1_free(asn1);
519   return 0;
520 }
521
522 /* Exports public key as SILC protocol style public key file */
523
524 SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_pkcs_silc_export_public_key_file)
525 {
526   SilcBuffer buf;
527   unsigned char *key, *data;
528   SilcUInt32 key_len;
529
530   SILC_LOG_DEBUG(("Encoding SILC public key file"));
531
532   /* Export key */
533   key = silc_pkcs_silc_export_public_key(pkcs, stack, public_key, &key_len);
534   if (!key)
535     return NULL;
536
537   switch (encoding) {
538   case SILC_PKCS_FILE_BIN:
539     break;
540
541   case SILC_PKCS_FILE_BASE64:
542     data = silc_base64_encode_file(stack, key, key_len);
543     if (!data)
544       return NULL;
545     silc_sfree(stack, key);
546     key = data;
547     key_len = strlen(data);
548     break;
549   }
550
551   /* Encode SILC public key file */
552   buf = silc_buffer_salloc_size(stack, key_len +
553                                 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
554                                  strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
555   if (!buf) {
556     silc_sfree(stack, key);
557     return NULL;
558   }
559
560   if (silc_buffer_sformat(stack, buf,
561                           SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
562                           SILC_STR_UI_XNSTRING(key, key_len),
563                           SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
564                           SILC_STR_END) < 0) {
565     silc_buffer_sfree(stack, buf);
566     silc_sfree(stack, key);
567     return NULL;
568   }
569
570   silc_sfree(stack, key);
571   key = silc_buffer_steal(buf, ret_len);
572   silc_buffer_sfree(stack, buf);
573
574   return key;
575 }
576
577 /* Exports public key as SILC protocol style public key */
578
579 SILC_PKCS_EXPORT_PUBLIC_KEY(silc_pkcs_silc_export_public_key)
580 {
581   SilcSILCPublicKey silc_pubkey = public_key;
582   const SilcPKCSAlgorithm *alg = silc_pubkey->pkcs;
583   SilcBufferStruct alg_key;
584   SilcBuffer buf = NULL;
585   SilcAsn1 asn1 = NULL;
586   unsigned char *pk = NULL, *key = NULL, *ret;
587   SilcUInt32 pk_len, key_len, totlen;
588   char *identifier;
589
590   SILC_LOG_DEBUG(("Encoding SILC public key"));
591
592   /* Export PKCS algorithm public key */
593   if (alg->export_public_key)
594     pk = alg->export_public_key(alg, stack, silc_pubkey->public_key, &pk_len);
595   if (!pk) {
596     SILC_LOG_ERROR(("Error exporting PKCS algorithm key"));
597     return NULL;
598   }
599   silc_buffer_set(&alg_key, pk, pk_len);
600
601   /* Encode identifier */
602   identifier =
603     silc_pkcs_silc_encode_identifier(stack,
604                                      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     SILC_LOG_ERROR(("Error encoding SILC public key identifier"));
613     goto err;
614   }
615
616   asn1 = silc_asn1_alloc(stack);
617   if (!asn1)
618     goto err;
619
620   if (!strcmp(alg->name, "rsa")) {
621     /* Parse the PKCS #1 public key */
622     SilcMPInt n, e;
623     SilcUInt32 n_len, e_len;
624     unsigned char *nb, *eb;
625
626     memset(&n, 0, sizeof(n));
627     memset(&e, 0, sizeof(e));
628     if (!silc_asn1_decode(asn1, &alg_key,
629                           SILC_ASN1_SEQUENCE,
630                             SILC_ASN1_INT(&n),
631                             SILC_ASN1_INT(&e),
632                           SILC_ASN1_END, SILC_ASN1_END))
633       goto err;
634
635     /* Encode to SILC RSA public key */
636     eb = silc_mp_mp2bin(&e, 0, &e_len);
637     if (!eb)
638       goto err;
639     nb = silc_mp_mp2bin(&n, 0, &n_len);
640     if (!nb)
641       goto err;
642     key_len = e_len + 4 + n_len + 4;
643     key = silc_scalloc(stack, key_len, sizeof(*key));
644     if (!key)
645       goto err;
646
647     /* Put e length and e */
648     SILC_PUT32_MSB(e_len, key);
649     memcpy(key + 4, eb, e_len);
650
651     /* Put n length and n. */
652     SILC_PUT32_MSB(n_len, key + 4 + e_len);
653     memcpy(key + 4 + e_len + 4, nb, n_len);
654
655     silc_free(nb);
656     silc_free(eb);
657
658   } else if (!strcmp(alg->name, "dsa")) {
659     SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
660     goto err;
661
662   } else {
663     SILC_LOG_ERROR(("Unsupported PKCS algorithm: %s", alg->name));
664     goto err;
665   }
666
667   /* Encode SILC Public Key */
668   totlen = 2 + strlen(alg->name) + 2 + strlen(identifier) + key_len;
669   buf = silc_buffer_salloc_size(stack, totlen + 4);
670   if (!buf)
671     goto err;
672   if (silc_buffer_sformat(stack, buf,
673                           SILC_STR_UI_INT(totlen),
674                           SILC_STR_UI_SHORT(strlen(alg->name)),
675                           SILC_STR_UI32_STRING(alg->name),
676                           SILC_STR_UI_SHORT(strlen(identifier)),
677                           SILC_STR_UI32_STRING(identifier),
678                           SILC_STR_UI_XNSTRING(key, key_len),
679                           SILC_STR_END) < 0)
680     goto err;
681
682   ret = silc_buffer_steal(buf, ret_len);
683   silc_buffer_sfree(stack, buf);
684   silc_sfree(stack, key);
685   silc_sfree(stack, identifier);
686   silc_buffer_spurge(stack, &alg_key);
687   silc_asn1_free(asn1);
688
689   return ret;
690
691  err:
692   silc_sfree(stack, identifier);
693   silc_sfree(stack, pk);
694   silc_sfree(stack, key);
695   silc_buffer_sfree(stack, buf);
696   if (asn1)
697     silc_asn1_free(asn1);
698   return NULL;
699 }
700
701 /* Return key length */
702
703 SILC_PKCS_PUBLIC_KEY_BITLEN(silc_pkcs_silc_public_key_bitlen)
704 {
705   SilcSILCPublicKey silc_pubkey = public_key;
706   return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->pkcs,
707                                               silc_pubkey->public_key);
708 }
709
710 /* Copy public key */
711
712 SILC_PKCS_PUBLIC_KEY_COPY(silc_pkcs_silc_public_key_copy)
713 {
714   SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
715   SilcPublicKeyIdentifier ident = &silc_pubkey->identifier;
716
717   new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
718   if (!new_pubkey)
719     return NULL;
720   new_pubkey->pkcs = silc_pubkey->pkcs;
721
722   new_pubkey->public_key =
723     silc_pubkey->pkcs->public_key_copy(silc_pubkey->pkcs,
724                                        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 SILC_PKCS_PUBLIC_KEY_COMPARE(silc_pkcs_silc_public_key_compare)
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->pkcs, k1->public_key, k2->public_key);
807 }
808
809 /* Frees public key */
810
811 SILC_PKCS_PUBLIC_KEY_FREE(silc_pkcs_silc_public_key_free)
812 {
813   SilcSILCPublicKey silc_pubkey = public_key;
814
815   silc_pubkey->pkcs->public_key_free(silc_pubkey->pkcs,
816                                      silc_pubkey->public_key);
817
818   silc_free(silc_pubkey->identifier.username);
819   silc_free(silc_pubkey->identifier.host);
820   silc_free(silc_pubkey->identifier.realname);
821   silc_free(silc_pubkey->identifier.email);
822   silc_free(silc_pubkey->identifier.org);
823   silc_free(silc_pubkey->identifier.country);
824   silc_free(silc_pubkey->identifier.version);
825   silc_free(silc_pubkey);
826 }
827
828
829 /*************************** Private key routines ****************************/
830
831 /* Private key file magic */
832 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
833
834 /* Imports SILC implementation style private key file */
835
836 SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_pkcs_silc_import_private_key_file)
837 {
838   SilcCipher aes;
839   SilcHash sha1;
840   SilcHmac sha1hmac;
841   SilcUInt32 blocklen;
842   unsigned char tmp[32], keymat[64], *data = NULL;
843   SilcUInt32 i, len, magic, mac_len;
844   int ret;
845
846   SILC_LOG_DEBUG(("Parsing SILC private key file"));
847
848   /* Check start of file and remove header from the data. */
849   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
850   if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)) {
851     SILC_LOG_DEBUG(("Malformed SILC private key header"));
852     return FALSE;
853   }
854   for (i = 0; i < len; i++) {
855     if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
856       SILC_LOG_DEBUG(("Malformed SILC private key header"));
857       return FALSE;
858     }
859     filedata++;
860   }
861
862   len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
863                         strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
864
865   switch (encoding) {
866   case SILC_PKCS_FILE_BIN:
867     break;
868
869   case SILC_PKCS_FILE_BASE64:
870     data = silc_base64_decode(NULL, filedata, filedata_len, &len);
871     if (!data)
872       return FALSE;
873     filedata = data;
874     break;
875   }
876
877   memset(tmp, 0, sizeof(tmp));
878   memset(keymat, 0, sizeof(keymat));
879
880   /* Check file magic */
881   SILC_GET32_MSB(magic, filedata);
882   if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
883     SILC_LOG_DEBUG(("Private key does not have correct magic"));
884     return FALSE;
885   }
886
887   /* Allocate the AES cipher */
888   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
889     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
890     return FALSE;
891   }
892   blocklen = silc_cipher_get_block_len(aes);
893   if (blocklen * 2 > sizeof(tmp)) {
894     silc_cipher_free(aes);
895     return FALSE;
896   }
897
898   /* Allocate SHA1 hash */
899   if (!silc_hash_alloc("sha1", &sha1)) {
900     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
901     silc_cipher_free(aes);
902     return FALSE;
903   }
904
905   /* Allocate HMAC */
906   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
907     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
908     silc_hash_free(sha1);
909     silc_cipher_free(aes);
910     return FALSE;
911   }
912
913   /* Derive the decryption key from the provided key material.  The key
914      is 256 bits length, and derived by taking hash of the data, then
915      re-hashing the data and the previous digest, and using the first and
916      second digest as the key. */
917   silc_hash_init(sha1);
918   silc_hash_update(sha1, passphrase, passphrase_len);
919   silc_hash_final(sha1, keymat);
920   silc_hash_init(sha1);
921   silc_hash_update(sha1, passphrase, passphrase_len);
922   silc_hash_update(sha1, keymat, 16);
923   silc_hash_final(sha1, keymat + 16);
924
925   /* Set the key to the cipher */
926   silc_cipher_set_key(aes, keymat, 256, FALSE);
927
928   /* First, verify the MAC of the private key data */
929   mac_len = silc_hmac_len(sha1hmac);
930   silc_hmac_init_with_key(sha1hmac, keymat, 16);
931   silc_hmac_update(sha1hmac, filedata, len - mac_len);
932   silc_hmac_final(sha1hmac, tmp, NULL);
933   if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
934     SILC_LOG_DEBUG(("Integrity check for private key failed"));
935     memset(keymat, 0, sizeof(keymat));
936     memset(tmp, 0, sizeof(tmp));
937     silc_hmac_free(sha1hmac);
938     silc_hash_free(sha1);
939     silc_cipher_free(aes);
940     return FALSE;
941   }
942   filedata += 4;
943   len -= 4;
944
945   /* Decrypt the private key buffer */
946   silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
947   SILC_GET32_MSB(i, filedata);
948   if (i > len) {
949     SILC_LOG_DEBUG(("Bad private key length in buffer!"));
950     memset(keymat, 0, sizeof(keymat));
951     memset(tmp, 0, sizeof(tmp));
952     silc_hmac_free(sha1hmac);
953     silc_hash_free(sha1);
954     silc_cipher_free(aes);
955     return FALSE;
956   }
957   filedata += 4;
958   len = i;
959
960   /* Cleanup */
961   memset(keymat, 0, sizeof(keymat));
962   memset(tmp, 0, sizeof(tmp));
963   silc_hmac_free(sha1hmac);
964   silc_hash_free(sha1);
965   silc_cipher_free(aes);
966
967   /* Import the private key */
968   ret = silc_pkcs_silc_import_private_key(pkcs, NULL, filedata,
969                                           len, ret_private_key, ret_alg);
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 SILC_PKCS_IMPORT_PRIVATE_KEY(silc_pkcs_silc_import_private_key)
983 {
984   SilcBufferStruct buf;
985   SilcBufferStruct alg_key;
986   SilcSILCPrivateKey silc_privkey = NULL;
987   SilcAsn1 asn1 = NULL;
988   SilcUInt16 pkcs_len;
989   SilcUInt32 keydata_len;
990   unsigned char *pkcs_name = NULL, *key_data;
991   int ret;
992
993   SILC_LOG_DEBUG(("Parsing SILC private key"));
994
995   if (!ret_private_key)
996     return 0;
997
998   silc_buffer_set(&buf, (unsigned char *)key, key_len);
999
1000   /* Get algorithm name and identifier */
1001   ret =
1002     silc_buffer_unformat(&buf,
1003                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1004                          SILC_STR_END);
1005   if (ret == -1) {
1006     SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1007     goto err;
1008   }
1009
1010   if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
1011     SILC_LOG_DEBUG(("Malformed private key buffer"));
1012     goto err;
1013   }
1014
1015   /* Get key data. We assume that rest of the buffer is key data. */
1016   silc_buffer_pull(&buf, 2 + pkcs_len);
1017   keydata_len = silc_buffer_len(&buf);
1018   ret = silc_buffer_unformat(&buf,
1019                              SILC_STR_UI_XNSTRING(&key_data, keydata_len),
1020                              SILC_STR_END);
1021   if (ret == -1)
1022     goto err;
1023
1024   /* Allocate SILC private key context */
1025   silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
1026   if (!silc_privkey)
1027     goto err;
1028
1029   asn1 = silc_asn1_alloc(NULL);
1030   if (!asn1)
1031     goto err;
1032
1033   if (!strcmp(pkcs_name, "rsa")) {
1034     /* Parse the RSA SILC private key */
1035     SilcBufferStruct k;
1036     SilcMPInt n, e, d, dp, dq, qp, p, q;
1037     unsigned char *tmp;
1038     SilcUInt32 len, ver;
1039
1040     if (keydata_len < 4)
1041       goto err;
1042     silc_buffer_set(&k, key_data, keydata_len);
1043
1044     /* Get version.  Key without the version is old style private key
1045        and we need to do some computation to get it to correct format. */
1046     if (silc_buffer_unformat(&k,
1047                              SILC_STR_UI_INT(&ver),
1048                              SILC_STR_END) < 0)
1049       goto err;
1050     silc_buffer_pull(&k, 4);
1051
1052     if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1053         ver != SILC_PRIVATE_KEY_VERSION_2) {
1054       len = ver;
1055       ver = 0;
1056     } else {
1057       if (silc_buffer_unformat(&k,
1058                                SILC_STR_UI_INT(&len),
1059                                SILC_STR_END) < 0)
1060         goto err;
1061       silc_buffer_pull(&k, 4);
1062     }
1063
1064     /* Get PKCS object.  Different PKCS #1 scheme is used with different
1065        versions. */
1066     if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1067       /* Version 0 and 1 */
1068       alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1069     } else {
1070       /* Version 2 and newer */
1071       alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1072     }
1073     if (!alg) {
1074       SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1075       goto err;
1076     }
1077     silc_privkey->pkcs = alg;
1078
1079     SILC_LOG_DEBUG(("Private key version %s",
1080                     (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1081                      ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1082
1083     /* Get e */
1084     if (silc_buffer_unformat(&k,
1085                              SILC_STR_DATA(&tmp, len),
1086                              SILC_STR_END) < 0)
1087       goto err;
1088     silc_mp_init(&e);
1089     silc_mp_bin2mp(tmp, len, &e);
1090     silc_buffer_pull(&k, len);
1091
1092     /* Get n */
1093     if (silc_buffer_unformat(&k,
1094                              SILC_STR_UI_INT(&len),
1095                              SILC_STR_END) < 0)
1096       goto err;
1097     silc_buffer_pull(&k, 4);
1098     if (silc_buffer_unformat(&k,
1099                              SILC_STR_DATA(&tmp, len),
1100                              SILC_STR_END) < 0)
1101       goto err;
1102     silc_mp_init(&n);
1103     silc_mp_bin2mp(tmp, len, &n);
1104     silc_buffer_pull(&k, len);
1105
1106     /* Get d */
1107     if (silc_buffer_unformat(&k,
1108                              SILC_STR_UI_INT(&len),
1109                              SILC_STR_END) < 0)
1110       goto err;
1111     silc_buffer_pull(&k, 4);
1112     if (silc_buffer_unformat(&k,
1113                              SILC_STR_DATA(&tmp, len),
1114                              SILC_STR_END) < 0)
1115       goto err;
1116     silc_mp_init(&d);
1117     silc_mp_bin2mp(tmp, len, &d);
1118     silc_buffer_pull(&k, len);
1119
1120     /* Get dP */
1121     if (silc_buffer_unformat(&k,
1122                              SILC_STR_UI_INT(&len),
1123                              SILC_STR_END) < 0)
1124       goto err;
1125     silc_buffer_pull(&k, 4);
1126     if (silc_buffer_unformat(&k,
1127                              SILC_STR_DATA(&tmp, len),
1128                              SILC_STR_END) < 0)
1129       goto err;
1130     silc_mp_init(&dp);
1131     silc_mp_bin2mp(tmp, len, &dp);
1132     silc_buffer_pull(&k, len);
1133
1134     /* Get dQ */
1135     if (silc_buffer_unformat(&k,
1136                              SILC_STR_UI_INT(&len),
1137                              SILC_STR_END) < 0)
1138       goto err;
1139     silc_buffer_pull(&k, 4);
1140     if (silc_buffer_unformat(&k,
1141                              SILC_STR_DATA(&tmp, len),
1142                              SILC_STR_END) < 0)
1143       goto err;
1144     silc_mp_init(&dq);
1145     silc_mp_bin2mp(tmp, len, &dq);
1146     silc_buffer_pull(&k, len);
1147
1148     if (ver == 0) {
1149       /* Old version */
1150
1151       /* Get pQ len */
1152       if (silc_buffer_unformat(&k,
1153                                SILC_STR_UI_INT(&len),
1154                                SILC_STR_END) < 0)
1155         goto err;
1156       silc_buffer_pull(&k, 4);
1157       if (silc_buffer_len(&k) < len)
1158         goto err;
1159       silc_buffer_pull(&k, len);
1160
1161       /* Get qP len */
1162       if (silc_buffer_unformat(&k,
1163                                SILC_STR_UI_INT(&len),
1164                                SILC_STR_END) < 0)
1165         goto err;
1166       silc_buffer_pull(&k, 4);
1167       if (silc_buffer_len(&k) < len)
1168         goto err;
1169       silc_buffer_pull(&k, len);
1170     } else {
1171       /* New version */
1172
1173       /* Get qP */
1174       if (silc_buffer_unformat(&k,
1175                                SILC_STR_UI_INT(&len),
1176                                SILC_STR_END) < 0)
1177         goto err;
1178       silc_buffer_pull(&k, 4);
1179       if (silc_buffer_unformat(&k,
1180                                SILC_STR_DATA(&tmp, len),
1181                                SILC_STR_END) < 0)
1182         goto err;
1183       silc_mp_init(&qp);
1184       silc_mp_bin2mp(tmp, len, &qp);
1185       silc_buffer_pull(&k, len);
1186     }
1187
1188     /* Get p */
1189     if (silc_buffer_unformat(&k,
1190                              SILC_STR_UI_INT(&len),
1191                              SILC_STR_END) < 0)
1192       goto err;
1193     silc_buffer_pull(&k, 4);
1194     if (silc_buffer_unformat(&k,
1195                              SILC_STR_DATA(&tmp, len),
1196                              SILC_STR_END) < 0)
1197       goto err;
1198     silc_mp_init(&p);
1199     silc_mp_bin2mp(tmp, len, &p);
1200     silc_buffer_pull(&k, len);
1201
1202     /* Get q */
1203     if (silc_buffer_unformat(&k,
1204                              SILC_STR_UI_INT(&len),
1205                              SILC_STR_END) < 0)
1206       goto err;
1207     silc_buffer_pull(&k, 4);
1208     if (silc_buffer_unformat(&k,
1209                              SILC_STR_DATA(&tmp, len),
1210                              SILC_STR_END) < 0)
1211       goto err;
1212     silc_mp_init(&q);
1213     silc_mp_bin2mp(tmp, len, &q);
1214     silc_buffer_pull(&k, len);
1215
1216     if (ver == 0) {
1217       /* Old version.  Compute to new version */
1218       SILC_LOG_DEBUG(("Old version private key"));
1219       silc_mp_init(&qp);
1220       silc_mp_modinv(&qp, &q, &p);
1221     }
1222
1223     /* Encode to PKCS #1 format */
1224     memset(&alg_key, 0, sizeof(alg_key));
1225     if (!silc_asn1_encode(asn1, &alg_key,
1226                           SILC_ASN1_SEQUENCE,
1227                             SILC_ASN1_SHORT_INT(0),
1228                             SILC_ASN1_INT(&n),
1229                             SILC_ASN1_INT(&e),
1230                             SILC_ASN1_INT(&d),
1231                             SILC_ASN1_INT(&p),
1232                             SILC_ASN1_INT(&q),
1233                             SILC_ASN1_INT(&dp),
1234                             SILC_ASN1_INT(&dq),
1235                             SILC_ASN1_INT(&qp),
1236                           SILC_ASN1_END, SILC_ASN1_END))
1237       goto err;
1238
1239     silc_mp_uninit(&n);
1240     silc_mp_uninit(&e);
1241     silc_mp_uninit(&e);
1242     silc_mp_uninit(&d);
1243     silc_mp_uninit(&p);
1244     silc_mp_uninit(&q);
1245     silc_mp_uninit(&dp);
1246     silc_mp_uninit(&dq);
1247     silc_mp_uninit(&qp);
1248
1249   } else if (!strcmp(pkcs_name, "dsa")) {
1250     SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1251     goto err;
1252
1253   } else {
1254     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1255     goto err;
1256   }
1257
1258   /* Import PKCS algorithm private key */
1259   if (!alg->import_private_key(alg, alg_key.data, silc_buffer_len(&alg_key),
1260                                &silc_privkey->private_key))
1261     goto err;
1262
1263   silc_free(pkcs_name);
1264   silc_asn1_free(asn1);
1265
1266   *ret_private_key = silc_privkey;
1267   *ret_alg = alg;
1268
1269   return key_len;
1270
1271  err:
1272   silc_free(pkcs_name);
1273   silc_free(silc_privkey);
1274   if (asn1)
1275     silc_asn1_free(asn1);
1276   SILC_LOG_ERROR(("Malformed SILC private key "));
1277   return 0;
1278 }
1279
1280 /* Exports private key as SILC implementation style private key file */
1281
1282 SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_pkcs_silc_export_private_key_file)
1283 {
1284   SilcCipher aes;
1285   SilcHash sha1;
1286   SilcHmac sha1hmac;
1287   SilcBuffer buf, enc;
1288   SilcUInt32 len, blocklen, padlen, key_len;
1289   unsigned char *key, *data;
1290   unsigned char tmp[32], keymat[64];
1291   int i;
1292
1293   SILC_LOG_DEBUG(("Encoding SILC private key file"));
1294
1295   /* Export the private key */
1296   key = silc_pkcs_silc_export_private_key(pkcs, stack, private_key, &key_len);
1297   if (!key)
1298     return NULL;
1299
1300   memset(tmp, 0, sizeof(tmp));
1301   memset(keymat, 0, sizeof(keymat));
1302
1303   /* Allocate the AES cipher */
1304   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1305     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1306     silc_sfree(stack, key);
1307     return NULL;
1308   }
1309   blocklen = silc_cipher_get_block_len(aes);
1310   if (blocklen * 2 > sizeof(tmp)) {
1311     silc_cipher_free(aes);
1312     silc_sfree(stack, key);
1313     return NULL;
1314   }
1315
1316   /* Allocate SHA1 hash */
1317   if (!silc_hash_alloc("sha1", &sha1)) {
1318     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1319     silc_sfree(stack, key);
1320     silc_cipher_free(aes);
1321     return NULL;
1322   }
1323
1324   /* Allocate HMAC */
1325   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1326     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1327     silc_sfree(stack, key);
1328     silc_hash_free(sha1);
1329     silc_cipher_free(aes);
1330     return NULL;
1331   }
1332
1333   /* Derive the encryption key from the provided key material.  The key
1334      is 256 bits length, and derived by taking hash of the data, then
1335      re-hashing the data and the previous digest, and using the first and
1336      second digest as the key. */
1337   silc_hash_init(sha1);
1338   silc_hash_update(sha1, passphrase, passphrase_len);
1339   silc_hash_final(sha1, keymat);
1340   silc_hash_init(sha1);
1341   silc_hash_update(sha1, passphrase, passphrase_len);
1342   silc_hash_update(sha1, keymat, 16);
1343   silc_hash_final(sha1, keymat + 16);
1344
1345   /* Set the key to the cipher */
1346   silc_cipher_set_key(aes, keymat, 256, TRUE);
1347
1348   /* Encode the buffer to be encrypted.  Add padding to it too, at least
1349      block size of the cipher. */
1350
1351   /* Allocate buffer for encryption */
1352   len = silc_hmac_len(sha1hmac);
1353   padlen = 16 + (16 - ((key_len + 4) % blocklen));
1354   enc = silc_buffer_salloc_size(stack, 4 + 4 + key_len + padlen + len);
1355   if (!enc) {
1356     silc_sfree(stack, key);
1357     silc_hmac_free(sha1hmac);
1358     silc_hash_free(sha1);
1359     silc_cipher_free(aes);
1360     return FALSE;
1361   }
1362
1363   /* Generate padding */
1364   for (i = 0; i < padlen; i++)
1365     tmp[i] = silc_rng_get_byte_fast(rng);
1366
1367   /* Put magic number */
1368   SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1369   silc_buffer_pull(enc, 4);
1370
1371   /* Encode the buffer */
1372   silc_buffer_sformat(stack, enc,
1373                       SILC_STR_UI_INT(key_len),
1374                       SILC_STR_UI_XNSTRING(key, key_len),
1375                       SILC_STR_UI_XNSTRING(tmp, padlen),
1376                       SILC_STR_END);
1377   silc_sfree(stack, key);
1378
1379   /* Encrypt. */
1380   silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1381                       silc_cipher_get_iv(aes));
1382
1383   silc_buffer_push(enc, 4);
1384
1385   /* Compute HMAC over the encrypted data and append the MAC to data.
1386      The key is the first digest of the original key material. */
1387   key_len = silc_buffer_len(enc) - len;
1388   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1389   silc_hmac_update(sha1hmac, enc->data, key_len);
1390   silc_buffer_pull(enc, key_len);
1391   silc_hmac_final(sha1hmac, enc->data, NULL);
1392   silc_buffer_push(enc, key_len);
1393
1394   /* Cleanup */
1395   memset(keymat, 0, sizeof(keymat));
1396   memset(tmp, 0, sizeof(tmp));
1397   silc_hmac_free(sha1hmac);
1398   silc_hash_free(sha1);
1399   silc_cipher_free(aes);
1400
1401   switch (encoding) {
1402   case SILC_PKCS_FILE_BIN:
1403     break;
1404
1405   case SILC_PKCS_FILE_BASE64:
1406     data = silc_base64_encode_file(stack, enc->data, silc_buffer_len(enc));
1407     if (!data) {
1408       silc_buffer_clear(enc);
1409       silc_buffer_sfree(stack, enc);
1410       return NULL;
1411     }
1412     silc_sfree(stack, silc_buffer_steal(enc, NULL));
1413     silc_buffer_set(enc, data, strlen(data));
1414     break;
1415   }
1416
1417   key = enc->data;
1418   key_len = silc_buffer_len(enc);
1419
1420   /* Encode the data and save to file */
1421   len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1422                    strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1423   buf = silc_buffer_salloc_size(stack, len);
1424   if (!buf) {
1425     silc_buffer_sfree(stack, enc);
1426     return NULL;
1427   }
1428   silc_buffer_sformat(stack, buf,
1429                       SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1430                       SILC_STR_UI_XNSTRING(key, key_len),
1431                       SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1432                       SILC_STR_END);
1433
1434   silc_buffer_sfree(stack, enc);
1435   data = silc_buffer_steal(buf, ret_len);
1436   silc_buffer_sfree(stack, buf);
1437
1438   return data;
1439 }
1440
1441 /* Exports private key as SILC implementation style private key */
1442
1443 SILC_PKCS_EXPORT_PRIVATE_KEY(silc_pkcs_silc_export_private_key)
1444 {
1445   SilcSILCPrivateKey silc_privkey = private_key;
1446   const SilcPKCSAlgorithm *alg = silc_privkey->pkcs;
1447   SilcBufferStruct alg_key;
1448   SilcBuffer buf = NULL;
1449   SilcAsn1 asn1 = NULL;
1450   unsigned char *prv = NULL, *key = NULL, *ret;
1451   SilcUInt32 prv_len, key_len, totlen;
1452
1453   SILC_LOG_DEBUG(("Encoding SILC private key"));
1454
1455   /* Export PKCS algorithm private key */
1456   if (alg->export_private_key)
1457     prv = alg->export_private_key(alg, stack,
1458                                   silc_privkey->private_key, &prv_len);
1459   if (!prv)
1460     return NULL;
1461   silc_buffer_set(&alg_key, prv, prv_len);
1462
1463   asn1 = silc_asn1_alloc(stack);
1464   if (!asn1)
1465     goto err;
1466
1467   if (!strcmp(alg->name, "rsa")) {
1468     /* Parse the PKCS #1 private key */
1469     SilcMPInt n, e, d, dp, dq, qp, p, q;
1470     SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1471       qp_len, p_len, q_len, len = 0;
1472     unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1473
1474     if (!silc_asn1_decode(asn1, &alg_key,
1475                           SILC_ASN1_SEQUENCE,
1476                             SILC_ASN1_INT(NULL),
1477                             SILC_ASN1_INT(&n),
1478                             SILC_ASN1_INT(&e),
1479                             SILC_ASN1_INT(&d),
1480                             SILC_ASN1_INT(&p),
1481                             SILC_ASN1_INT(&q),
1482                             SILC_ASN1_INT(&dp),
1483                             SILC_ASN1_INT(&dq),
1484                             SILC_ASN1_INT(&qp),
1485                           SILC_ASN1_END, SILC_ASN1_END))
1486       goto err;
1487
1488     /* Encode to SILC RSA private key */
1489     eb = silc_mp_mp2bin(&e, 0, &e_len);
1490     nb = silc_mp_mp2bin(&n, 0, &n_len);
1491     db = silc_mp_mp2bin(&d, 0, &d_len);
1492     dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1493     dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1494     qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1495     pb = silc_mp_mp2bin(&p, 0, &p_len);
1496     qb = silc_mp_mp2bin(&q, 0, &q_len);
1497     len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1498       dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1499
1500     buf = silc_buffer_salloc_size(stack, len);
1501     if (!buf)
1502       goto err;
1503     if (silc_buffer_sformat(stack, buf,
1504                             SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1505                             SILC_STR_UI_INT(e_len),
1506                             SILC_STR_UI_XNSTRING(eb, e_len),
1507                             SILC_STR_UI_INT(n_len),
1508                             SILC_STR_UI_XNSTRING(nb, n_len),
1509                             SILC_STR_UI_INT(d_len),
1510                             SILC_STR_UI_XNSTRING(db, d_len),
1511                             SILC_STR_UI_INT(dp_len),
1512                             SILC_STR_UI_XNSTRING(dpb, dp_len),
1513                             SILC_STR_UI_INT(dq_len),
1514                             SILC_STR_UI_XNSTRING(dqb, dq_len),
1515                             SILC_STR_UI_INT(qp_len),
1516                             SILC_STR_UI_XNSTRING(qpb, qp_len),
1517                             SILC_STR_UI_INT(p_len),
1518                             SILC_STR_UI_XNSTRING(pb, p_len),
1519                             SILC_STR_UI_INT(q_len),
1520                             SILC_STR_UI_XNSTRING(qb, q_len),
1521                             SILC_STR_END) < 0)
1522       goto err;
1523
1524     key = silc_buffer_steal(buf, &key_len);
1525     silc_buffer_sfree(stack, buf);
1526     silc_free(nb);
1527     silc_free(eb);
1528     silc_free(db);
1529     silc_free(dpb);
1530     silc_free(dqb);
1531     silc_free(qpb);
1532     silc_free(pb);
1533     silc_free(qb);
1534
1535   } else if (!strcmp(alg->name, "dsa")) {
1536     SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1537     goto err;
1538
1539   } else {
1540     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1541     goto err;
1542   }
1543
1544   /* Encode SILC private key */
1545   totlen = 2 + strlen(alg->name) + key_len;
1546   buf = silc_buffer_salloc_size(stack, totlen);
1547   if (!buf)
1548     goto err;
1549   if (silc_buffer_sformat(stack, buf,
1550                           SILC_STR_UI_SHORT(strlen(alg->name)),
1551                           SILC_STR_UI32_STRING(alg->name),
1552                           SILC_STR_UI_XNSTRING(key, key_len),
1553                           SILC_STR_END) < 0)
1554     goto err;
1555
1556   ret = silc_buffer_steal(buf, ret_len);
1557   silc_buffer_sfree(stack, buf);
1558   silc_sfree(stack, prv);
1559   silc_sfree(stack, key);
1560   silc_asn1_free(asn1);
1561
1562   return ret;
1563
1564  err:
1565   silc_sfree(stack, prv);
1566   silc_sfree(stack, key);
1567   silc_buffer_sfree(stack, buf);
1568   return NULL;
1569 }
1570
1571 /* Return key length */
1572
1573 SILC_PKCS_PRIVATE_KEY_BITLEN(silc_pkcs_silc_private_key_bitlen)
1574 {
1575   SilcSILCPrivateKey silc_privkey = private_key;
1576   return silc_privkey->pkcs->private_key_bitlen(silc_privkey->pkcs,
1577                                                 silc_privkey->private_key);
1578 }
1579
1580 /* Frees private key */
1581
1582 SILC_PKCS_PRIVATE_KEY_FREE(silc_pkcs_silc_private_key_free)
1583 {
1584   SilcSILCPrivateKey silc_privkey = private_key;
1585
1586   silc_privkey->pkcs->private_key_free(silc_privkey->pkcs,
1587                                        silc_privkey->private_key);
1588   silc_free(silc_privkey);
1589 }
1590
1591
1592 /***************************** PKCS operations ******************************/
1593
1594 /* Encrypts as specified in SILC protocol specification */
1595
1596 SILC_PKCS_ENCRYPT(silc_pkcs_silc_encrypt)
1597 {
1598   SilcSILCPublicKey silc_pubkey = public_key;
1599
1600   if (!silc_pubkey->pkcs->encrypt) {
1601     encrypt_cb(FALSE, NULL, 0, context);
1602     return NULL;
1603   }
1604
1605   return silc_pubkey->pkcs->encrypt(silc_pubkey->pkcs,
1606                                     silc_pubkey->public_key,
1607                                     src, src_len, rng, encrypt_cb, context);
1608 }
1609
1610 /* Decrypts as specified in SILC protocol specification */
1611
1612 SILC_PKCS_DECRYPT(silc_pkcs_silc_decrypt)
1613 {
1614   SilcSILCPrivateKey silc_privkey = private_key;
1615
1616   if (!silc_privkey->pkcs->decrypt) {
1617     decrypt_cb(FALSE, NULL, 0, context);
1618     return NULL;
1619   }
1620
1621   return silc_privkey->pkcs->decrypt(silc_privkey->pkcs,
1622                                      silc_privkey->private_key,
1623                                      src, src_len, decrypt_cb, context);
1624 }
1625
1626 /* Signs as specified in SILC protocol specification */
1627
1628 SILC_PKCS_SIGN(silc_pkcs_silc_sign)
1629 {
1630   SilcSILCPrivateKey silc_privkey = private_key;
1631
1632   if (!silc_privkey->pkcs->sign) {
1633     sign_cb(FALSE, NULL, 0, context);
1634     return NULL;
1635   }
1636
1637   return silc_privkey->pkcs->sign(silc_privkey->pkcs,
1638                                   silc_privkey->private_key,
1639                                   src, src_len,
1640                                   compute_hash, hash, rng,
1641                                   sign_cb, context);
1642 }
1643
1644 /* Verifies as specified in SILC protocol specification */
1645
1646 SILC_PKCS_VERIFY(silc_pkcs_silc_verify)
1647 {
1648   SilcSILCPublicKey silc_pubkey = public_key;
1649
1650   if (!silc_pubkey->pkcs->verify) {
1651     verify_cb(FALSE, context);
1652     return NULL;
1653   }
1654
1655   return silc_pubkey->pkcs->verify(silc_pubkey->pkcs,
1656                                    silc_pubkey->public_key,
1657                                    signature, signature_len,
1658                                    data, data_len, hash, rng,
1659                                    verify_cb, context);
1660 }