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