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