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