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