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