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