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