Added synchronous and asynchronous PKCS calls.
[crypto.git] / lib / silccrypt / silcpkcs.c
1 /*
2
3   silcpkcs.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2008 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 "silccrypto.h"
21 #include "silcpk_i.h"
22 #include "silcpkcs1_i.h"
23 #include "dsa.h"
24 #ifdef SILC_DIST_SSH
25 #include "silcssh_pkcs.h"
26 #endif /* SILC_DIST_SSH */
27 #ifdef SILC_DIST_PGP
28 #include "silcpgp_pkcs.h"
29 #endif /* SILC_DIST_PGP */
30
31 #ifndef SILC_SYMBIAN
32 /* Dynamically registered list of PKCS. */
33 SilcDList silc_pkcs_list = NULL;
34 SilcDList silc_pkcs_alg_list = NULL;
35 #define SILC_PKCS_LIST silc_pkcs_list
36 #define SILC_PKCS_ALG_LIST silc_pkcs_alg_list
37 #else
38 #define SILC_PKCS_LIST TRUE
39 #define SILC_PKCS_ALG_LIST TRUE
40 #endif /* SILC_SYMBIAN */
41
42 /* Static list of PKCS for silc_pkcs_register_default(). */
43 const SilcPKCSObject silc_default_pkcs[] =
44 {
45   /* SILC PKCS */
46   {
47     SILC_PKCS_SILC,
48     silc_pkcs_silc_get_algorithm,
49     silc_pkcs_silc_import_public_key_file,
50     silc_pkcs_silc_import_public_key,
51     silc_pkcs_silc_export_public_key_file,
52     silc_pkcs_silc_export_public_key,
53     silc_pkcs_silc_public_key_bitlen,
54     silc_pkcs_silc_public_key_copy,
55     silc_pkcs_silc_public_key_compare,
56     silc_pkcs_silc_public_key_free,
57     silc_pkcs_silc_import_private_key_file,
58     silc_pkcs_silc_import_private_key,
59     silc_pkcs_silc_export_private_key_file,
60     silc_pkcs_silc_export_private_key,
61     silc_pkcs_silc_private_key_bitlen,
62     silc_pkcs_silc_private_key_free,
63     silc_pkcs_silc_encrypt,
64     silc_pkcs_silc_decrypt,
65     silc_pkcs_silc_sign,
66     silc_pkcs_silc_verify,
67   },
68
69 #ifdef SILC_DIST_SSH
70   /* SSH2 PKCS */
71   {
72     SILC_PKCS_SSH2,
73     silc_pkcs_ssh_get_algorithm,
74     silc_pkcs_ssh_import_public_key_file,
75     silc_pkcs_ssh_import_public_key,
76     silc_pkcs_ssh_export_public_key_file,
77     silc_pkcs_ssh_export_public_key,
78     silc_pkcs_ssh_public_key_bitlen,
79     silc_pkcs_ssh_public_key_copy,
80     silc_pkcs_ssh_public_key_compare,
81     silc_pkcs_ssh_public_key_free,
82     silc_pkcs_ssh_import_private_key_file,
83     silc_pkcs_ssh_import_private_key,
84     silc_pkcs_ssh_export_private_key_file,
85     silc_pkcs_ssh_export_private_key,
86     silc_pkcs_ssh_private_key_bitlen,
87     silc_pkcs_ssh_private_key_free,
88     silc_pkcs_ssh_encrypt,
89     silc_pkcs_ssh_decrypt,
90     silc_pkcs_ssh_sign,
91     silc_pkcs_ssh_verify,
92   },
93 #endif /* SILC_DIST_SSH */
94
95 #ifdef SILC_DIST_PGP
96   /* OpenPGP PKCS */
97   {
98     SILC_PKCS_OPENPGP,
99     silc_pkcs_pgp_get_algorithm,
100     silc_pkcs_pgp_import_public_key_file,
101     silc_pkcs_pgp_import_public_key,
102     silc_pkcs_pgp_export_public_key_file,
103     silc_pkcs_pgp_export_public_key,
104     silc_pkcs_pgp_public_key_bitlen,
105     silc_pkcs_pgp_public_key_copy,
106     silc_pkcs_pgp_public_key_compare,
107     silc_pkcs_pgp_public_key_free,
108     silc_pkcs_pgp_import_private_key_file,
109     silc_pkcs_pgp_import_private_key,
110     silc_pkcs_pgp_export_private_key_file,
111     silc_pkcs_pgp_export_private_key,
112     silc_pkcs_pgp_private_key_bitlen,
113     silc_pkcs_pgp_private_key_free,
114     silc_pkcs_pgp_encrypt,
115     silc_pkcs_pgp_decrypt,
116     silc_pkcs_pgp_sign,
117     silc_pkcs_pgp_verify,
118   },
119 #endif /* SILC_DIST_PGP */
120
121   {
122     0, NULL, NULL, NULL, NULL, NULL,
123        NULL, NULL, NULL, NULL, NULL
124   }
125 };
126
127 /* Builtin PKCS algorithms */
128 const SilcPKCSAlgorithm silc_default_pkcs_alg[] =
129 {
130   /* PKCS #1, Version 1.5 without hash OIDs */
131   {
132     "rsa",
133     "pkcs1-no-oid",
134     "sha1,md5",
135     silc_pkcs1_generate_key,
136     silc_pkcs1_import_public_key,
137     silc_pkcs1_export_public_key,
138     silc_pkcs1_public_key_bitlen,
139     silc_pkcs1_public_key_copy,
140     silc_pkcs1_public_key_compare,
141     silc_pkcs1_public_key_free,
142     silc_pkcs1_import_private_key,
143     silc_pkcs1_export_private_key,
144     silc_pkcs1_private_key_bitlen,
145     silc_pkcs1_private_key_free,
146     silc_pkcs1_encrypt,
147     silc_pkcs1_decrypt,
148     silc_pkcs1_sign_no_oid,
149     silc_pkcs1_verify_no_oid
150   },
151
152   /* PKCS #1, Version 1.5 */
153   {
154     "rsa",
155     "pkcs1",
156     "sha1,md5",
157     silc_pkcs1_generate_key,
158     silc_pkcs1_import_public_key,
159     silc_pkcs1_export_public_key,
160     silc_pkcs1_public_key_bitlen,
161     silc_pkcs1_public_key_copy,
162     silc_pkcs1_public_key_compare,
163     silc_pkcs1_public_key_free,
164     silc_pkcs1_import_private_key,
165     silc_pkcs1_export_private_key,
166     silc_pkcs1_private_key_bitlen,
167     silc_pkcs1_private_key_free,
168     silc_pkcs1_encrypt,
169     silc_pkcs1_decrypt,
170     silc_pkcs1_sign,
171     silc_pkcs1_verify
172   },
173
174   /* DSS, FIPS186-3 */
175   {
176     "dsa",
177     "dss",
178     "sha1",
179     silc_dsa_generate_key,
180     silc_dsa_import_public_key,
181     silc_dsa_export_public_key,
182     silc_dsa_public_key_bitlen,
183     silc_dsa_public_key_copy,
184     silc_dsa_public_key_compare,
185     silc_dsa_public_key_free,
186     silc_dsa_import_private_key,
187     silc_dsa_export_private_key,
188     silc_dsa_private_key_bitlen,
189     silc_dsa_private_key_free,
190     silc_dsa_encrypt,
191     silc_dsa_decrypt,
192     silc_dsa_sign,
193     silc_dsa_verify
194   },
195
196   /* DSS, FIPS186-2 */
197   {
198     "dsa",
199     "dss-fips186-2",
200     "sha1",
201     silc_dsa_generate_key,
202     silc_dsa_import_public_key,
203     silc_dsa_export_public_key,
204     silc_dsa_public_key_bitlen,
205     silc_dsa_public_key_copy,
206     silc_dsa_public_key_compare,
207     silc_dsa_public_key_free,
208     silc_dsa_import_private_key,
209     silc_dsa_export_private_key,
210     silc_dsa_private_key_bitlen,
211     silc_dsa_private_key_free,
212     silc_dsa_encrypt,
213     silc_dsa_decrypt,
214     silc_dsa_sign,
215     silc_dsa_verify
216   },
217
218 #ifdef SILC_DIST_SSH
219   /* PKCS #1, SSH2 style public keys */
220   {
221     "rsa",
222     "ssh",
223     "sha1",
224     silc_pkcs1_generate_key,
225     silc_ssh_rsa_import_public_key,
226     silc_ssh_rsa_export_public_key,
227     silc_pkcs1_public_key_bitlen,
228     silc_pkcs1_public_key_copy,
229     silc_pkcs1_public_key_compare,
230     silc_pkcs1_public_key_free,
231     silc_pkcs1_import_private_key,
232     silc_pkcs1_export_private_key,
233     silc_pkcs1_private_key_bitlen,
234     silc_pkcs1_private_key_free,
235     silc_pkcs1_encrypt,
236     silc_pkcs1_decrypt,
237     silc_pkcs1_sign,
238     silc_pkcs1_verify
239   },
240
241   /* DSS FIPS186-2, SSH2 style public keys */
242   {
243     "dsa",
244     "ssh",
245     "sha1,sha224,sha256,sha384,sha512",
246     silc_dsa_fips186_2_generate_key,
247     silc_ssh_dsa_import_public_key,
248     silc_ssh_dsa_export_public_key,
249     silc_dsa_public_key_bitlen,
250     silc_dsa_public_key_copy,
251     silc_dsa_public_key_compare,
252     silc_dsa_public_key_free,
253     silc_dsa_import_private_key,
254     silc_dsa_export_private_key,
255     silc_dsa_private_key_bitlen,
256     silc_dsa_private_key_free,
257     silc_dsa_encrypt,
258     silc_dsa_decrypt,
259     silc_dsa_sign,
260     silc_dsa_verify
261   },
262 #endif /* SILC_DIST_SSH */
263
264 #ifdef SILC_DIST_PGP
265   /* PKCS #1, OpenPGP style public keys */
266   {
267     "rsa",
268     "openpgp",
269     "sha1",
270     silc_pkcs1_generate_key,
271     silc_pgp_rsa_import_public_key,
272     silc_pgp_rsa_export_public_key,
273     silc_pkcs1_public_key_bitlen,
274     silc_pkcs1_public_key_copy,
275     silc_pkcs1_public_key_compare,
276     silc_pkcs1_public_key_free,
277     silc_pgp_rsa_import_private_key,
278     silc_pgp_rsa_export_private_key,
279     silc_pkcs1_private_key_bitlen,
280     silc_pkcs1_private_key_free,
281     silc_pkcs1_encrypt,
282     silc_pkcs1_decrypt,
283     silc_pkcs1_sign,
284     silc_pkcs1_verify
285   },
286
287   /* DSS, OpenPGP style public keys */
288   {
289     "dsa",
290     "openpgp",
291     "sha1,sha224,sha256,sha384,sha512",
292     silc_dsa_generate_key,
293     silc_pgp_dsa_import_public_key,
294     silc_pgp_dsa_export_public_key,
295     silc_dsa_public_key_bitlen,
296     silc_dsa_public_key_copy,
297     silc_dsa_public_key_compare,
298     silc_dsa_public_key_free,
299     silc_pgp_dsa_import_private_key,
300     silc_pgp_dsa_export_private_key,
301     silc_dsa_private_key_bitlen,
302     silc_dsa_private_key_free,
303     silc_dsa_encrypt,
304     silc_dsa_decrypt,
305     silc_dsa_sign,
306     silc_dsa_verify
307   },
308 #endif /* SILC_DIST_PGP */
309
310   {
311     NULL, NULL, NULL, NULL,
312     NULL, NULL, NULL, NULL,
313     NULL, NULL, NULL, NULL,
314     NULL, NULL
315   }
316 };
317
318 /* Register a new PKCS */
319
320 SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs)
321 {
322 #ifndef SILC_SYMBIAN
323   SilcPKCSObject *newpkcs;
324
325   SILC_LOG_DEBUG(("Registering new PKCS"));
326
327   /* Check if exists already */
328   if (silc_pkcs_list) {
329     SilcPKCSObject *entry;
330     silc_dlist_start(silc_pkcs_list);
331     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
332       if (entry->type == pkcs->type)
333         return FALSE;
334     }
335   }
336
337   newpkcs = silc_calloc(1, sizeof(*newpkcs));
338   if (!newpkcs)
339     return FALSE;
340   *newpkcs = *pkcs;
341
342   /* Add to list */
343   if (silc_pkcs_list == NULL)
344     silc_pkcs_list = silc_dlist_init();
345   silc_dlist_add(silc_pkcs_list, newpkcs);
346
347 #endif /* SILC_SYMBIAN */
348   return TRUE;
349 }
350
351 /* Unregister a PKCS */
352
353 SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs)
354 {
355 #ifndef SILC_SYMBIAN
356   SilcPKCSObject *entry;
357
358   SILC_LOG_DEBUG(("Unregistering PKCS"));
359
360   if (!silc_pkcs_list)
361     return FALSE;
362
363   silc_dlist_start(silc_pkcs_list);
364   while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
365     if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
366       silc_dlist_del(silc_pkcs_list, entry);
367       silc_free(entry);
368
369       if (silc_dlist_count(silc_pkcs_list) == 0) {
370         silc_dlist_uninit(silc_pkcs_list);
371         silc_pkcs_list = NULL;
372       }
373
374       return TRUE;
375     }
376   }
377
378 #endif /* SILC_SYMBIAN */
379   return FALSE;
380 }
381
382 /* Register algorithm */
383
384 SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs)
385 {
386 #ifndef SILC_SYMBIAN
387   SilcPKCSAlgorithm *newalg;
388
389   SILC_LOG_DEBUG(("Registering new PKCS algorithm %s",
390                   pkcs->name));
391
392   /* Check if exists already */
393   if (silc_pkcs_alg_list) {
394     SilcPKCSAlgorithm *entry;
395     silc_dlist_start(silc_pkcs_alg_list);
396     while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
397       if (!strcmp(entry->name, pkcs->name) &&
398           entry->scheme && pkcs->scheme &&
399           !strcmp(entry->scheme, pkcs->scheme))
400         return FALSE;
401     }
402   }
403
404   newalg = silc_calloc(1, sizeof(*newalg));
405   if (!newalg)
406     return FALSE;
407
408   *newalg = *pkcs;
409   newalg->name = strdup(pkcs->name);
410   if (!newalg->name)
411     return FALSE;
412   if (pkcs->scheme) {
413     newalg->scheme = strdup(pkcs->scheme);
414     if (!newalg->scheme)
415       return FALSE;
416   }
417   newalg->hash = strdup(pkcs->hash);
418   if (!newalg->hash)
419     return FALSE;
420
421   /* Add to list */
422   if (silc_pkcs_alg_list == NULL)
423     silc_pkcs_alg_list = silc_dlist_init();
424   silc_dlist_add(silc_pkcs_alg_list, newalg);
425
426 #endif /* SILC_SYMBIAN */
427   return TRUE;
428 }
429
430 /* Unregister algorithm */
431
432 SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs)
433 {
434 #ifndef SILC_SYMBIAN
435   SilcPKCSAlgorithm*entry;
436
437   SILC_LOG_DEBUG(("Unregistering PKCS algorithm"));
438
439   if (!silc_pkcs_alg_list)
440     return FALSE;
441
442   silc_dlist_start(silc_pkcs_alg_list);
443   while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
444     if (pkcs == SILC_ALL_PKCS_ALG || entry == pkcs) {
445       silc_dlist_del(silc_pkcs_alg_list, entry);
446       silc_free(entry->name);
447       silc_free(entry->scheme);
448       silc_free(entry->hash);
449       silc_free(entry);
450
451       if (silc_dlist_count(silc_pkcs_alg_list) == 0) {
452         silc_dlist_uninit(silc_pkcs_alg_list);
453         silc_pkcs_alg_list = NULL;
454       }
455
456       return TRUE;
457     }
458   }
459
460 #endif /* SILC_SYMBIAN */
461   return FALSE;
462 }
463
464 /* Function that registers all the default PKCS and PKCS algorithms. */
465
466 SilcBool silc_pkcs_register_default(void)
467 {
468   /* We use builtin PKCS and algorithms */
469   return TRUE;
470 }
471
472 /* Unregister all PKCS and algorithms */
473
474 SilcBool silc_pkcs_unregister_all(void)
475 {
476 #ifndef SILC_SYMBIAN
477   SilcPKCSObject *entry;
478   SilcPKCSAlgorithm *alg;
479
480   if (silc_pkcs_list) {
481     silc_dlist_start(silc_pkcs_list);
482     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
483       silc_pkcs_unregister(entry);
484       if (!silc_pkcs_list)
485         break;
486     }
487   }
488
489   if (silc_pkcs_alg_list) {
490     silc_dlist_start(silc_pkcs_alg_list);
491     while ((alg = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
492       silc_pkcs_algorithm_unregister(alg);
493       if (!silc_pkcs_alg_list)
494         break;
495     }
496   }
497
498 #endif /* SILC_SYMBIAN */
499   return TRUE;
500 }
501
502 /* Returns comma separated list of supported PKCS algorithms */
503
504 char *silc_pkcs_get_supported(void)
505 {
506   SilcPKCSAlgorithm *entry, *entry2;
507   char *list = NULL;
508   int i, len = 0;
509
510 #ifndef SILC_SYMBIAN
511   if (silc_pkcs_alg_list) {
512     silc_dlist_start(silc_pkcs_alg_list);
513     while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
514       len += strlen(entry->name);
515       list = silc_realloc(list, len + 1);
516       if (!list)
517         return NULL;
518
519       memcpy(list + (len - strlen(entry->name)),
520              entry->name, strlen(entry->name));
521       memcpy(list + len, ",", 1);
522       len++;
523     }
524   }
525 #endif /* SILC_SYMBIAN */
526
527   for (i = 0; silc_default_pkcs_alg[i].name; i++) {
528     entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
529
530     if (silc_pkcs_alg_list) {
531       silc_dlist_start(silc_pkcs_alg_list);
532       while ((entry2 = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
533         if (!strcmp(entry2->name, entry->name))
534           break;
535       }
536       if (entry2)
537         continue;
538     }
539
540     len += strlen(entry->name);
541     list = silc_realloc(list, len + 1);
542     if (!list)
543       return NULL;
544
545     memcpy(list + (len - strlen(entry->name)),
546            entry->name, strlen(entry->name));
547     memcpy(list + len, ",", 1);
548     len++;
549   }
550
551   list[len - 1] = 0;
552
553   return list;
554 }
555
556 /* Finds PKCS object */
557
558 const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type)
559 {
560   SilcPKCSObject *entry;
561   int i;
562
563 #ifndef SILC_SYMBIAN
564   if (silc_pkcs_list) {
565     silc_dlist_start(silc_pkcs_list);
566     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
567       if (entry->type == type)
568         return (const SilcPKCSObject *)entry;
569     }
570   }
571 #endif /* SILC_SYMBIAN */
572
573   for (i = 0; silc_default_pkcs[i].type; i++) {
574     entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
575     if (entry->type == type)
576       return (const SilcPKCSObject *)entry;
577   }
578
579   return NULL;
580 }
581
582 /* Finds PKCS algorithms object */
583
584 const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
585                                                   const char *scheme)
586 {
587   SilcPKCSAlgorithm *entry;
588   int i;
589
590 #ifndef SILC_SYMBIAN
591   if (silc_pkcs_alg_list) {
592     silc_dlist_start(silc_pkcs_alg_list);
593     while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
594       if (!strcmp(entry->name, algorithm) &&
595           (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme)))
596         return (const SilcPKCSAlgorithm *)entry;
597     }
598   }
599 #endif /* SILC_SYMBIAN */
600
601   for (i = 0; silc_default_pkcs_alg[i].name; i++) {
602     entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
603     if (!strcmp(entry->name, algorithm) &&
604         (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme)))
605       return (const SilcPKCSAlgorithm *)entry;
606   }
607
608   return NULL;
609 }
610
611 /* Returns PKCS context */
612
613 const SilcPKCSObject *silc_pkcs_get_pkcs(void *key)
614 {
615   SilcPublicKey public_key = key;
616   return public_key->pkcs;
617 }
618
619 /* Returns PKCS algorithm context */
620
621 const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(void *key)
622 {
623   SilcPublicKey public_key = key;
624   return public_key->alg;
625 }
626
627 /* Return algorithm name */
628
629 const char *silc_pkcs_get_name(void *key)
630 {
631   const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(key);
632   return pkcs->name;
633 }
634
635 /* Returns PKCS type */
636
637 SilcPKCSType silc_pkcs_get_type(void *key)
638 {
639   SilcPublicKey public_key = key;
640   return public_key->pkcs->type;
641 }
642
643 /* Allocates new public key from the key data */
644
645 SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
646                                     unsigned char *key,
647                                     SilcUInt32 key_len,
648                                     SilcPublicKey *ret_public_key)
649 {
650   const SilcPKCSObject *pkcs;
651   SilcPublicKey public_key;
652
653   if (!ret_public_key)
654     return FALSE;
655
656   /* Allocate public key context */
657   public_key = silc_calloc(1, sizeof(*public_key));
658   if (!public_key)
659     return FALSE;
660
661   if (type == SILC_PKCS_ANY) {
662     /* Try loading all types until one succeeds. */
663     for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
664       pkcs = (SilcPKCSObject *)silc_pkcs_find_pkcs(type);
665       if (!pkcs)
666         continue;
667
668       /* Import the PKCS public key */
669       if (pkcs->import_public_key(pkcs, NULL, key, key_len,
670                                   &public_key->public_key,
671                                   &public_key->alg)) {
672         public_key->pkcs = (SilcPKCSObject *)pkcs;
673         *ret_public_key = public_key;
674         return TRUE;
675       }
676     }
677   } else {
678     pkcs = silc_pkcs_find_pkcs(type);
679     public_key->pkcs = (SilcPKCSObject *)pkcs;
680     if (!public_key->pkcs) {
681       silc_free(public_key);
682       return FALSE;
683     }
684
685     /* Import the PKCS public key */
686     if (pkcs->import_public_key(pkcs, NULL, key, key_len,
687                                 &public_key->public_key,
688                                 &public_key->alg)) {
689       *ret_public_key = public_key;
690       return TRUE;
691     }
692   }
693
694   silc_free(public_key);
695   return FALSE;
696 }
697
698 /* Frees the public key */
699
700 void silc_pkcs_public_key_free(SilcPublicKey public_key)
701 {
702   public_key->pkcs->public_key_free(public_key->pkcs, public_key->public_key);
703   silc_free(public_key);
704 }
705
706 /* Exports public key */
707
708 unsigned char *silc_pkcs_public_key_encode(SilcStack stack,
709                                            SilcPublicKey public_key,
710                                            SilcUInt32 *ret_len)
711 {
712   return public_key->pkcs->export_public_key(public_key->pkcs, stack,
713                                              public_key->public_key, ret_len);
714 }
715
716 /* Return key length */
717
718 SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key)
719 {
720   return public_key->pkcs->public_key_bitlen(public_key->pkcs,
721                                              public_key->public_key);
722 }
723
724 /* Returns internal PKCS public key context */
725
726 void *silc_pkcs_public_key_get_pkcs(SilcPKCSType type,
727                                     SilcPublicKey public_key)
728 {
729   if (public_key->pkcs->type != type)
730     return NULL;
731   return public_key->public_key;
732 }
733
734 /* Returns internal PKCS private key context */
735
736 void *silc_pkcs_private_key_get_pkcs(SilcPKCSType type,
737                                      SilcPrivateKey private_key)
738 {
739   if (private_key->pkcs->type != type)
740     return NULL;
741   return private_key->private_key;
742 }
743
744 /* Allocates new private key from key data */
745
746 SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
747                                      unsigned char *key,
748                                      SilcUInt32 key_len,
749                                      SilcPrivateKey *ret_private_key)
750 {
751   const SilcPKCSObject *pkcs;
752   SilcPrivateKey private_key;
753
754   if (!ret_private_key)
755     return FALSE;
756
757   /* Allocate private key context */
758   private_key = silc_calloc(1, sizeof(*private_key));
759   if (!private_key)
760     return FALSE;
761
762   pkcs = silc_pkcs_find_pkcs(type);
763   private_key->pkcs = (SilcPKCSObject *)pkcs;
764   if (!private_key->pkcs) {
765     silc_free(private_key);
766     return FALSE;
767   }
768
769   /* Import the PKCS private key */
770   if (!pkcs->import_private_key(pkcs, NULL, NULL, 0, key, key_len,
771                                 &private_key->private_key,
772                                 &private_key->alg)) {
773     silc_free(private_key);
774     return FALSE;
775   }
776
777   *ret_private_key = private_key;
778
779   return TRUE;
780 }
781
782 /* Return key length */
783
784 SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key)
785 {
786   return private_key->pkcs->private_key_bitlen(private_key->pkcs,
787                                                private_key->private_key);
788 }
789
790 /* Frees the private key */
791
792 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
793 {
794   private_key->pkcs->private_key_free(private_key->pkcs,
795                                       private_key->private_key);
796   silc_free(private_key);
797 }
798
799 /* PKCS operation context */
800 typedef struct {
801   unsigned char *dst;
802   SilcUInt32 *dst_len;
803   SilcUInt32 dst_size;
804   SilcBool result;
805 } SilcPKCSOperation;
806
807 /* Encrypt, decrypt, sign callback */
808
809 static void silc_pkcs_op_cb(SilcBool success,
810                             const unsigned char *data,
811                             SilcUInt32 data_len, void *context)
812 {
813   SilcPKCSOperation *ctx = context;
814
815   ctx->result = success;
816
817   if (!success)
818     return;
819
820   if (data_len > ctx->dst_size) {
821     ctx->result = FALSE;
822     return;
823   }
824
825   memcpy(ctx->dst, data, data_len);
826   if (ctx->dst_len)
827     *ctx->dst_len = data_len;
828 }
829
830 /* Verify callback */
831
832 static void silc_pkcs_verify_cb(SilcBool success, void *context)
833 {
834   SilcPKCSOperation *ctx = context;
835   ctx->result = success;
836 }
837
838 /* Encrypts */
839
840 SilcBool silc_pkcs_encrypt(SilcPublicKey public_key,
841                            unsigned char *src, SilcUInt32 src_len,
842                            unsigned char *dst, SilcUInt32 dst_size,
843                            SilcUInt32 *dst_len, SilcRng rng)
844 {
845   SilcPKCSOperation ctx;
846
847   ctx.dst = dst;
848   ctx.dst_size = dst_size;
849   ctx.dst_len = dst_len;
850
851   public_key->pkcs->encrypt(public_key->pkcs,
852                             public_key->public_key, src, src_len,
853                             rng, silc_pkcs_op_cb, &ctx);
854
855   return ctx.result;
856 }
857
858 /* Encrypts, async */
859
860 SilcAsyncOperation
861 silc_pkcs_encrypt_async(SilcPublicKey public_key,
862                         unsigned char *src, SilcUInt32 src_len,
863                         SilcRng rng,
864                         SilcPKCSEncryptCb encrypt_cb,
865                         void *context)
866 {
867   return public_key->pkcs->encrypt(public_key->pkcs,
868                                    public_key->public_key, src, src_len,
869                                    rng, encrypt_cb, context);
870 }
871
872 /* Decrypts */
873
874 SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
875                            unsigned char *src, SilcUInt32 src_len,
876                            unsigned char *dst, SilcUInt32 dst_size,
877                            SilcUInt32 *dst_len)
878 {
879   SilcPKCSOperation ctx;
880
881   ctx.dst = dst;
882   ctx.dst_size = dst_size;
883   ctx.dst_len = dst_len;
884
885   private_key->pkcs->decrypt(private_key->pkcs,
886                              private_key->private_key, src, src_len,
887                              silc_pkcs_op_cb, &ctx);
888
889   return ctx.result;
890 }
891
892 /* Decrypts, async */
893
894 SilcAsyncOperation
895 silc_pkcs_decrypt_async(SilcPrivateKey private_key,
896                         unsigned char *src, SilcUInt32 src_len,
897                         SilcPKCSDecryptCb decrypt_cb,
898                         void *context)
899 {
900   return private_key->pkcs->decrypt(private_key->pkcs,
901                                     private_key->private_key, src, src_len,
902                                     decrypt_cb, context);
903 }
904
905 /* Generates signature */
906
907 SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
908                         unsigned char *src, SilcUInt32 src_len,
909                         unsigned char *dst, SilcUInt32 dst_size,
910                         SilcUInt32 *dst_len, SilcBool compute_hash,
911                         SilcHash hash, SilcRng rng)
912 {
913   SilcPKCSOperation ctx;
914
915   ctx.dst = dst;
916   ctx.dst_size = dst_size;
917   ctx.dst_len = dst_len;
918
919   private_key->pkcs->sign(private_key->pkcs,
920                           private_key->private_key, src, src_len,
921                           compute_hash, hash, rng,
922                           silc_pkcs_op_cb, &ctx);
923
924   return ctx.result;
925 }
926
927 /* Generates signature, async */
928
929 SilcAsyncOperation silc_pkcs_sign_async(SilcPrivateKey private_key,
930                                         unsigned char *src,
931                                         SilcUInt32 src_len,
932                                         SilcBool compute_hash,
933                                         SilcHash hash,
934                                         SilcRng rng,
935                                         SilcPKCSSignCb sign_cb,
936                                         void *context)
937 {
938   return private_key->pkcs->sign(private_key->pkcs,
939                                  private_key->private_key, src, src_len,
940                                  compute_hash, hash, rng, sign_cb, context);
941 }
942
943 /* Verifies signature */
944
945 SilcBool silc_pkcs_verify(SilcPublicKey public_key,
946                           unsigned char *signature,
947                           SilcUInt32 signature_len,
948                           unsigned char *data,
949                           SilcUInt32 data_len,
950                           SilcBool compute_hash,
951                           SilcHash hash)
952 {
953   SilcPKCSOperation ctx;
954
955   public_key->pkcs->verify(public_key->pkcs,
956                            public_key->public_key, signature,
957                            signature_len, data, data_len,
958                            compute_hash, hash, NULL,
959                            silc_pkcs_verify_cb, &ctx);
960
961   return ctx.result;
962 }
963
964 /* Verifies signature, async */
965
966 SilcAsyncOperation silc_pkcs_verify_async(SilcPublicKey public_key,
967                                           unsigned char *signature,
968                                           SilcUInt32 signature_len,
969                                           unsigned char *data,
970                                           SilcUInt32 data_len,
971                                           SilcBool compute_hash,
972                                           SilcHash hash,
973                                           SilcPKCSVerifyCb verify_cb,
974                                           void *context)
975 {
976   return public_key->pkcs->verify(public_key->pkcs,
977                                   public_key->public_key, signature,
978                                   signature_len, data, data_len,
979                                   compute_hash, hash, NULL,
980                                   verify_cb, context);
981 }
982
983 /* Compares two public keys and returns TRUE if they are same key, and
984    FALSE if they are not same. */
985
986 SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
987 {
988   if (key1->pkcs->type != key2->pkcs->type)
989     return FALSE;
990
991   return key1->pkcs->public_key_compare(key1->pkcs,
992                                         key1->public_key, key2->public_key);
993 }
994
995 /* Copies the public key indicated by `public_key' and returns new allocated
996    public key which is indentical to the `public_key'. */
997
998 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
999 {
1000   SilcPublicKey key = silc_calloc(1, sizeof(*key));
1001   if (!key)
1002     return NULL;
1003
1004   key->pkcs = public_key->pkcs;
1005   key->public_key = public_key->pkcs->public_key_copy(public_key->pkcs,
1006                                                       public_key->public_key);
1007   if (!key->public_key) {
1008     silc_free(key);
1009     return NULL;
1010   }
1011
1012   return key;
1013 }
1014
1015 /* Loads any kind of public key */
1016
1017 SilcBool silc_pkcs_load_public_key(const char *filename,
1018                                    SilcPKCSType type,
1019                                    SilcPublicKey *ret_public_key)
1020 {
1021   unsigned char *data;
1022   SilcUInt32 data_len;
1023   SilcPublicKey public_key;
1024
1025   SILC_LOG_DEBUG(("Loading public key file '%s'", filename));
1026
1027   if (!ret_public_key)
1028     return FALSE;
1029
1030   data = silc_file_readfile(filename, &data_len, NULL);
1031   if (!data) {
1032     SILC_LOG_ERROR(("No such file: %s", filename));
1033     return FALSE;
1034   }
1035
1036   /* Allocate public key context */
1037   *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key));
1038   if (!public_key) {
1039     silc_free(data);
1040     return FALSE;
1041   }
1042
1043   if (type == SILC_PKCS_ANY) {
1044     /* Try loading all types until one succeeds. */
1045     for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
1046       public_key->pkcs = (SilcPKCSObject *)silc_pkcs_find_pkcs(type);
1047       if (!public_key->pkcs)
1048         continue;
1049
1050       if (public_key->pkcs->import_public_key_file(public_key->pkcs,
1051                                                    data, data_len,
1052                                                    SILC_PKCS_FILE_BASE64,
1053                                                    &public_key->public_key,
1054                                                    &public_key->alg)) {
1055         silc_free(data);
1056         return TRUE;
1057       }
1058
1059       if (public_key->pkcs->import_public_key_file(public_key->pkcs,
1060                                                    data, data_len,
1061                                                    SILC_PKCS_FILE_BIN,
1062                                                    &public_key->public_key,
1063                                                    &public_key->alg)) {
1064         silc_free(data);
1065         return TRUE;
1066       }
1067     }
1068   } else {
1069     /* Load specific type */
1070     public_key->pkcs = (SilcPKCSObject *)silc_pkcs_find_pkcs(type);
1071     if (!public_key->pkcs) {
1072       silc_free(data);
1073       silc_free(public_key);
1074       *ret_public_key = NULL;
1075       SILC_LOG_ERROR(("Unsupported public key type"));
1076       return FALSE;
1077     }
1078
1079     if (public_key->pkcs->import_public_key_file(public_key->pkcs,
1080                                                  data, data_len,
1081                                                  SILC_PKCS_FILE_BASE64,
1082                                                  &public_key->public_key,
1083                                                  &public_key->alg)) {
1084       silc_free(data);
1085       return TRUE;
1086     }
1087
1088     if (public_key->pkcs->import_public_key_file(public_key->pkcs,
1089                                                  data, data_len,
1090                                                  SILC_PKCS_FILE_BIN,
1091                                                  &public_key->public_key,
1092                                                  &public_key->alg)) {
1093       silc_free(data);
1094       return TRUE;
1095     }
1096   }
1097
1098   silc_free(data);
1099   silc_free(public_key);
1100   *ret_public_key = NULL;
1101   SILC_LOG_ERROR(("Unsupported public key type"));
1102   return FALSE;
1103 }
1104
1105 /* Saves public key into a file */
1106
1107 SilcBool silc_pkcs_save_public_key(const char *filename,
1108                                    SilcPublicKey public_key,
1109                                    SilcPKCSFileEncoding encoding)
1110 {
1111   unsigned char *data;
1112   SilcUInt32 data_len;
1113   SilcStack stack;
1114
1115   stack = silc_stack_alloc(2048, silc_crypto_stack());
1116
1117   /* Export the public key file */
1118   data = public_key->pkcs->export_public_key_file(public_key->pkcs,
1119                                                   stack,
1120                                                   public_key->public_key,
1121                                                   encoding, &data_len);
1122   if (!data) {
1123     silc_stack_free(stack);
1124     return FALSE;
1125   }
1126
1127   /* Write to file */
1128   if (silc_file_writefile(filename, data, data_len)) {
1129     silc_sfree(stack, data);
1130     silc_stack_free(stack);
1131     return FALSE;
1132   }
1133
1134   silc_sfree(stack, data);
1135   silc_stack_free(stack);
1136   return TRUE;
1137 }
1138
1139 /* Loads any kind of private key */
1140
1141 SilcBool silc_pkcs_load_private_key(const char *filename,
1142                                     const unsigned char *passphrase,
1143                                     SilcUInt32 passphrase_len,
1144                                     SilcPKCSType type,
1145                                     SilcPrivateKey *ret_private_key)
1146 {
1147   unsigned char *data;
1148   SilcUInt32 data_len;
1149   SilcPrivateKey private_key;
1150
1151   SILC_LOG_DEBUG(("Loading private key file '%s'", filename));
1152
1153   if (!ret_private_key)
1154     return FALSE;
1155
1156   data = silc_file_readfile(filename, &data_len, NULL);
1157   if (!data) {
1158     SILC_LOG_ERROR(("No such file: %s", filename));
1159     return FALSE;
1160   }
1161
1162   /* Allocate private key context */
1163   *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key));
1164   if (!private_key) {
1165     silc_free(data);
1166     return FALSE;
1167   }
1168
1169   if (type == SILC_PKCS_ANY) {
1170     /* Try loading all types until one succeeds. */
1171     for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
1172       private_key->pkcs = (SilcPKCSObject *)silc_pkcs_find_pkcs(type);
1173       if (!private_key->pkcs)
1174         continue;
1175
1176       if (private_key->pkcs->import_private_key_file(
1177                                               private_key->pkcs,
1178                                               data, data_len,
1179                                               passphrase,
1180                                               passphrase_len,
1181                                               SILC_PKCS_FILE_BIN,
1182                                               &private_key->private_key,
1183                                               &private_key->alg)) {
1184         silc_free(data);
1185         return TRUE;
1186       }
1187
1188       if (private_key->pkcs->import_private_key_file(
1189                                               private_key->pkcs,
1190                                               data, data_len,
1191                                               passphrase,
1192                                               passphrase_len,
1193                                               SILC_PKCS_FILE_BASE64,
1194                                               &private_key->private_key,
1195                                               &private_key->alg)) {
1196         silc_free(data);
1197         return TRUE;
1198       }
1199     }
1200   } else {
1201     /* Load specific type */
1202     private_key->pkcs = (SilcPKCSObject *)silc_pkcs_find_pkcs(type);
1203     if (!private_key->pkcs) {
1204       silc_free(data);
1205       silc_free(private_key);
1206       *ret_private_key = NULL;
1207       SILC_LOG_ERROR(("Unsupported private key type"));
1208       return FALSE;
1209     }
1210
1211     if (private_key->pkcs->import_private_key_file(
1212                                               private_key->pkcs,
1213                                               data, data_len,
1214                                               passphrase,
1215                                               passphrase_len,
1216                                               SILC_PKCS_FILE_BIN,
1217                                               &private_key->private_key,
1218                                               &private_key->alg)) {
1219       silc_free(data);
1220       return TRUE;
1221     }
1222
1223     if (private_key->pkcs->import_private_key_file(
1224                                               private_key->pkcs,
1225                                               data, data_len,
1226                                               passphrase,
1227                                               passphrase_len,
1228                                               SILC_PKCS_FILE_BASE64,
1229                                               &private_key->private_key,
1230                                               &private_key->alg)) {
1231       silc_free(data);
1232       return TRUE;
1233     }
1234   }
1235
1236   silc_free(data);
1237   silc_free(private_key);
1238   *ret_private_key = NULL;
1239   return FALSE;
1240 }
1241
1242 /* Saves private key into a file */
1243
1244 SilcBool silc_pkcs_save_private_key(const char *filename,
1245                                     SilcPrivateKey private_key,
1246                                     const unsigned char *passphrase,
1247                                     SilcUInt32 passphrase_len,
1248                                     SilcPKCSFileEncoding encoding,
1249                                     SilcRng rng)
1250 {
1251   unsigned char *data;
1252   SilcUInt32 data_len;
1253   SilcStack stack;
1254
1255   stack = silc_stack_alloc(2048, silc_crypto_stack());
1256
1257   /* Export the private key file */
1258   data = private_key->pkcs->export_private_key_file(private_key->pkcs, stack,
1259                                                     private_key->private_key,
1260                                                     passphrase,
1261                                                     passphrase_len,
1262                                                     encoding, rng, &data_len);
1263   if (!data) {
1264     silc_stack_free(stack);
1265     return FALSE;
1266   }
1267
1268   /* Write to file */
1269   if (silc_file_writefile(filename, data, data_len)) {
1270     silc_sfree(stack, data);
1271     silc_stack_free(stack);
1272     return FALSE;
1273   }
1274
1275   silc_sfree(stack, data);
1276   silc_stack_free(stack);
1277   return TRUE;
1278 }
1279
1280 /* Hash public key of any type. */
1281
1282 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
1283 {
1284   SilcPublicKey public_key = key;
1285   unsigned char *pk;
1286   SilcUInt32 pk_len;
1287   SilcUInt32 hash = 0;
1288   SilcStack stack = NULL;
1289
1290   if (silc_crypto_stack())
1291     stack = silc_stack_alloc(2048, silc_crypto_stack());
1292
1293   pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len);
1294   if (!pk) {
1295     silc_stack_free(stack);
1296     return hash;
1297   }
1298
1299   hash = silc_hash_data(pk, SILC_32_TO_PTR(pk_len));
1300
1301   silc_sfree(stack, pk);
1302   silc_stack_free(stack);
1303
1304   return hash;
1305 }
1306
1307 /* Compares two SILC Public keys. It may be used as SilcHashTable
1308    comparison function. */
1309
1310 SilcBool silc_hash_public_key_compare(void *key1, void *key2,
1311                                       void *user_context)
1312 {
1313   return silc_pkcs_public_key_compare(key1, key2);
1314 }