Merged silc_1_1_branch to trunk.
[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 into SILC. */
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 from the SILC. */
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 #ifndef SILC_SYMBIAN
275   int i;
276
277   for (i = 0; silc_default_pkcs[i].type; i++)
278     silc_pkcs_register(&(silc_default_pkcs[i]));
279
280   for (i = 0; silc_default_pkcs_alg[i].name; i++)
281     silc_pkcs_algorithm_register(&(silc_default_pkcs_alg[i]));
282
283 #endif /* SILC_SYMBIAN */
284   return TRUE;
285 }
286
287 SilcBool silc_pkcs_unregister_all(void)
288 {
289 #ifndef SILC_SYMBIAN
290   SilcPKCSObject *entry;
291   SilcPKCSAlgorithm *alg;
292
293   if (silc_pkcs_list) {
294     silc_dlist_start(silc_pkcs_list);
295     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
296       silc_pkcs_unregister(entry);
297       if (!silc_pkcs_list)
298         break;
299     }
300   }
301
302   if (silc_pkcs_alg_list) {
303     silc_dlist_start(silc_pkcs_alg_list);
304     while ((alg = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
305       silc_pkcs_algorithm_unregister(alg);
306       if (!silc_pkcs_alg_list)
307         break;
308     }
309   }
310
311 #endif /* SILC_SYMBIAN */
312   return TRUE;
313 }
314
315 /* Returns comma separated list of supported PKCS algorithms */
316
317 char *silc_pkcs_get_supported(void)
318 {
319   SilcPKCSAlgorithm *entry;
320   char *list = NULL;
321   int len = 0;
322
323 #ifndef SILC_SYMBIAN
324   if (silc_pkcs_alg_list) {
325     silc_dlist_start(silc_pkcs_alg_list);
326     while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
327       len += strlen(entry->name);
328       list = silc_realloc(list, len + 1);
329       if (!list)
330         return NULL;
331
332       memcpy(list + (len - strlen(entry->name)),
333              entry->name, strlen(entry->name));
334       memcpy(list + len, ",", 1);
335       len++;
336     }
337   }
338 #else
339   {
340     int i;
341     for (i = 0; silc_default_pkcs_alg[i].name; i++) {
342       entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
343       len += strlen(entry->name);
344       list = silc_realloc(list, len + 1);
345       if (!list)
346         return NULL;
347
348       memcpy(list + (len - strlen(entry->name)),
349              entry->name, strlen(entry->name));
350       memcpy(list + len, ",", 1);
351       len++;
352     }
353   }
354 #endif /* SILC_SYMBIAN */
355
356   list[len - 1] = 0;
357
358   return list;
359 }
360
361 /* Finds PKCS object */
362
363 const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type)
364 {
365   SilcPKCSObject *entry;
366
367 #ifndef SILC_SYMBIAN
368   if (silc_pkcs_list) {
369     silc_dlist_start(silc_pkcs_list);
370     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
371       if (entry->type == type)
372         return (const SilcPKCSObject *)entry;
373     }
374   }
375 #else
376   {
377     int i;
378     for (i = 0; silc_default_pkcs[i].type; i++) {
379       entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
380       if (entry->type == type)
381         return (const SilcPKCSObject *)entry;
382     }
383   }
384 #endif /* SILC_SYMBIAN */
385
386   return NULL;
387 }
388
389 /* Finds PKCS algorithms object */
390
391 const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
392                                                   const char *scheme)
393 {
394   SilcPKCSAlgorithm *entry;
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 #else
406   {
407     int i;
408     for (i = 0; silc_default_pkcs_alg[i].name; i++) {
409       entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
410       if (!strcmp(entry->name, algorithm) &&
411           (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme)))
412         return (const SilcPKCSAlgorithm *)entry;
413     }
414   }
415 #endif /* SILC_SYMBIAN */
416
417   return NULL;
418 }
419
420 /* Returns PKCS context */
421
422 const SilcPKCSObject *silc_pkcs_get_pkcs(void *key)
423 {
424   SilcPublicKey public_key = key;
425   return public_key->pkcs;
426 }
427
428 /* Returns PKCS algorithm context */
429
430 const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(void *key)
431 {
432   SilcPublicKey public_key = key;
433   return public_key->pkcs->get_algorithm(public_key->public_key);
434 }
435
436 /* Return algorithm name */
437
438 const char *silc_pkcs_get_name(void *key)
439 {
440   const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(key);
441   return pkcs->name;
442 }
443
444 /* Returns PKCS type */
445
446 SilcPKCSType silc_pkcs_get_type(void *key)
447 {
448   SilcPublicKey public_key = key;
449   return public_key->pkcs->type;
450 }
451
452 /* Allocates new public key from the key data */
453
454 SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
455                                     unsigned char *key,
456                                     SilcUInt32 key_len,
457                                     SilcPublicKey *ret_public_key)
458 {
459   const SilcPKCSObject *pkcs;
460   SilcPublicKey public_key;
461
462   if (!ret_public_key)
463     return FALSE;
464
465   /* Allocate public key context */
466   public_key = silc_calloc(1, sizeof(*public_key));
467   if (!public_key)
468     return FALSE;
469
470   public_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
471   if (!public_key->pkcs) {
472     silc_free(public_key);
473     return FALSE;
474   }
475
476   /* Import the PKCS public key */
477   if (!pkcs->import_public_key(key, key_len, &public_key->public_key)) {
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->public_key);
492   silc_free(public_key);
493 }
494
495 /* Exports public key */
496
497 unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
498                                            SilcUInt32 *ret_len)
499 {
500   return public_key->pkcs->export_public_key(public_key->public_key,
501                                              ret_len);
502 }
503
504 /* Return key length */
505
506 SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key)
507 {
508   return public_key->pkcs->public_key_bitlen(public_key->public_key);
509 }
510
511 /* Returns internal PKCS public key context */
512
513 void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key)
514 {
515   if (public_key->pkcs->type != type)
516     return NULL;
517   return public_key->public_key;
518 }
519
520
521 /* Allocates new private key from key data */
522
523 SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
524                                      unsigned char *key,
525                                      SilcUInt32 key_len,
526                                      SilcPrivateKey *ret_private_key)
527 {
528   const SilcPKCSObject *pkcs;
529   SilcPrivateKey private_key;
530
531   if (!ret_private_key)
532     return FALSE;
533
534   /* Allocate private key context */
535   private_key = silc_calloc(1, sizeof(*private_key));
536   if (!private_key)
537     return FALSE;
538
539   private_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
540   if (!private_key->pkcs) {
541     silc_free(private_key);
542     return FALSE;
543   }
544
545   /* Import the PKCS private key */
546   if (!pkcs->import_private_key(key, key_len, &private_key->private_key)) {
547     silc_free(private_key);
548     return FALSE;
549   }
550
551   *ret_private_key = private_key;
552
553   return TRUE;
554 }
555
556 /* Return key length */
557
558 SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key)
559 {
560   return private_key->pkcs->private_key_bitlen(private_key->private_key);
561 }
562
563 /* Frees the private key */
564
565 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
566 {
567   private_key->pkcs->private_key_free(private_key->private_key);
568   silc_free(private_key);
569 }
570
571 /* Encrypts */
572
573 SilcBool silc_pkcs_encrypt(SilcPublicKey public_key,
574                            unsigned char *src, SilcUInt32 src_len,
575                            unsigned char *dst, SilcUInt32 dst_size,
576                            SilcUInt32 *dst_len, SilcRng rng)
577 {
578   return public_key->pkcs->encrypt(public_key->public_key, src, src_len,
579                                    dst, dst_size, dst_len, rng);
580 }
581
582 /* Decrypts */
583
584 SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
585                            unsigned char *src, SilcUInt32 src_len,
586                            unsigned char *dst, SilcUInt32 dst_size,
587                            SilcUInt32 *dst_len)
588 {
589   return private_key->pkcs->decrypt(private_key->private_key, src, src_len,
590                                     dst, dst_size, dst_len);
591 }
592
593 /* Generates signature */
594
595 SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
596                         unsigned char *src, SilcUInt32 src_len,
597                         unsigned char *dst, SilcUInt32 dst_size,
598                         SilcUInt32 *dst_len, SilcBool compute_hash,
599                         SilcHash hash)
600 {
601   return private_key->pkcs->sign(private_key->private_key, src, src_len,
602                                  dst, dst_size, dst_len, compute_hash, hash);
603 }
604
605 /* Verifies signature */
606
607 SilcBool silc_pkcs_verify(SilcPublicKey public_key,
608                           unsigned char *signature,
609                           SilcUInt32 signature_len,
610                           unsigned char *data,
611                           SilcUInt32 data_len, SilcHash hash)
612 {
613   return public_key->pkcs->verify(public_key->public_key, signature,
614                                   signature_len, data, data_len, hash);
615 }
616
617 /* Compares two public keys and returns TRUE if they are same key, and
618    FALSE if they are not same. */
619
620 SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
621 {
622   if (key1->pkcs->type != key2->pkcs->type)
623     return FALSE;
624
625   return key1->pkcs->public_key_compare(key1->public_key, key2->public_key);
626 }
627
628 /* Copies the public key indicated by `public_key' and returns new allocated
629    public key which is indentical to the `public_key'. */
630
631 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
632 {
633   SilcPublicKey key = silc_calloc(1, sizeof(*key));
634   if (!key)
635     return NULL;
636
637   key->pkcs = public_key->pkcs;
638   key->public_key = public_key->pkcs->public_key_copy(public_key->public_key);
639   if (!key->public_key) {
640     silc_free(key);
641     return NULL;
642   }
643
644   return key;
645 }
646
647 /* Loads any kind of public key */
648
649 SilcBool silc_pkcs_load_public_key(const char *filename,
650                                    SilcPublicKey *ret_public_key)
651 {
652   unsigned char *data;
653   SilcUInt32 data_len;
654   SilcPublicKey public_key;
655   SilcPKCSType type;
656
657   SILC_LOG_DEBUG(("Loading public key file '%s'", filename));
658
659   if (!ret_public_key)
660     return FALSE;
661
662   data = silc_file_readfile(filename, &data_len);
663   if (!data)
664     return FALSE;
665
666   /* Allocate public key context */
667   *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key));
668   if (!public_key) {
669     silc_free(data);
670     return FALSE;
671   }
672
673   /* Try loading all types until one succeeds. */
674   for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
675     public_key->pkcs = silc_pkcs_find_pkcs(type);
676     if (!public_key->pkcs)
677       continue;
678
679     if (public_key->pkcs->import_public_key_file(data, data_len,
680                                                  SILC_PKCS_FILE_BASE64,
681                                                  &public_key->public_key)) {
682       silc_free(data);
683       return TRUE;
684     }
685
686     if (public_key->pkcs->import_public_key_file(data, data_len,
687                                                  SILC_PKCS_FILE_BIN,
688                                                  &public_key->public_key)) {
689       silc_free(data);
690       return TRUE;
691     }
692   }
693
694   silc_free(data);
695   silc_free(public_key);
696   *ret_public_key = NULL;
697   return FALSE;
698 }
699
700 /* Saves public key into a file */
701
702 SilcBool silc_pkcs_save_public_key(const char *filename,
703                                    SilcPublicKey public_key,
704                                    SilcPKCSFileEncoding encoding)
705 {
706   unsigned char *data;
707   SilcUInt32 data_len;
708
709   /* Export the public key file */
710   data = public_key->pkcs->export_public_key_file(public_key->public_key,
711                                                   encoding, &data_len);
712   if (!data)
713     return FALSE;
714
715   /* Write to file */
716   if (silc_file_writefile(filename, data, data_len)) {
717     silc_free(data);
718     return FALSE;
719   }
720
721   silc_free(data);
722   return TRUE;
723 }
724
725 /* Loads any kind of private key */
726
727 SilcBool silc_pkcs_load_private_key(const char *filename,
728                                     const unsigned char *passphrase,
729                                     SilcUInt32 passphrase_len,
730                                     SilcPrivateKey *ret_private_key)
731 {
732   unsigned char *data;
733   SilcUInt32 data_len;
734   SilcPrivateKey private_key;
735   SilcPKCSType type;
736
737   SILC_LOG_DEBUG(("Loading private key file '%s'", filename));
738
739   if (!ret_private_key)
740     return FALSE;
741
742   data = silc_file_readfile(filename, &data_len);
743   if (!data)
744     return FALSE;
745
746   /* Allocate private key context */
747   *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key));
748   if (!private_key) {
749     silc_free(data);
750     return FALSE;
751   }
752
753   /* Try loading all types until one succeeds. */
754   for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
755     private_key->pkcs = silc_pkcs_find_pkcs(type);
756     if (!private_key->pkcs)
757       continue;
758
759     if (private_key->pkcs->import_private_key_file(
760                                               data, data_len,
761                                               passphrase,
762                                               passphrase_len,
763                                               SILC_PKCS_FILE_BIN,
764                                               &private_key->private_key)) {
765       silc_free(data);
766       return TRUE;
767     }
768
769     if (private_key->pkcs->import_private_key_file(
770                                               data, data_len,
771                                               passphrase,
772                                               passphrase_len,
773                                               SILC_PKCS_FILE_BASE64,
774                                               &private_key->private_key)) {
775       silc_free(data);
776       return TRUE;
777     }
778   }
779
780   silc_free(data);
781   silc_free(private_key);
782   *ret_private_key = NULL;
783   return FALSE;
784 }
785
786 /* Saves private key into a file */
787
788 SilcBool silc_pkcs_save_private_key(const char *filename,
789                                     SilcPrivateKey private_key,
790                                     const unsigned char *passphrase,
791                                     SilcUInt32 passphrase_len,
792                                     SilcPKCSFileEncoding encoding,
793                                     SilcRng rng)
794 {
795   unsigned char *data;
796   SilcUInt32 data_len;
797
798   /* Export the private key file */
799   data = private_key->pkcs->export_private_key_file(private_key->private_key,
800                                                     passphrase,
801                                                     passphrase_len,
802                                                     encoding, rng, &data_len);
803   if (!data)
804     return FALSE;
805
806   /* Write to file */
807   if (silc_file_writefile(filename, data, data_len)) {
808     silc_free(data);
809     return FALSE;
810   }
811
812   silc_free(data);
813   return TRUE;
814 }