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