1 /*
2 
3   silcpkcs.c
4 
5   Author: Pekka Riikonen <priikone@silcnet.org>
6 
7   Copyright (C) 1997 - 2007 Pekka Riikonen
8 
9   The contents of this file are subject to one of the Licenses specified
10   in the COPYING file;  You may not use this file except in compliance
11   with the License.
12 
13   The software distributed under the License is distributed on an "AS IS"
14   basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15   KIND, either expressed or implied.  See the COPYING file for more
16   information.
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 
silc_pkcs_register(const SilcPKCSObject * pkcs)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 
silc_pkcs_unregister(SilcPKCSObject * pkcs)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 
silc_pkcs_algorithm_register(const SilcPKCSAlgorithm * pkcs)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 
silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm * pkcs)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 
silc_pkcs_register_default(void)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 
silc_pkcs_unregister_all(void)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 
silc_pkcs_get_supported(void)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   if (list)
357     list[len - 1] = 0;
358 
359   return list;
360 }
361 
362 /* Finds PKCS object */
363 
silc_pkcs_find_pkcs(SilcPKCSType type)364 const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type)
365 {
366   SilcPKCSObject *entry;
367 
368 #ifndef SILC_SYMBIAN
369   if (silc_pkcs_list) {
370     silc_dlist_start(silc_pkcs_list);
371     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
372       if (entry->type == type)
373 	return (const SilcPKCSObject *)entry;
374     }
375   }
376 #else
377   {
378     int i;
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 #endif /* SILC_SYMBIAN */
386 
387   return NULL;
388 }
389 
390 /* Finds PKCS algorithms object */
391 
silc_pkcs_find_algorithm(const char * algorithm,const char * scheme)392 const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
393 						  const char *scheme)
394 {
395   SilcPKCSAlgorithm *entry;
396 
397 #ifndef SILC_SYMBIAN
398   if (silc_pkcs_alg_list) {
399     silc_dlist_start(silc_pkcs_alg_list);
400     while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
401       if (!strcmp(entry->name, algorithm) &&
402 	  (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme)))
403 	return (const SilcPKCSAlgorithm *)entry;
404     }
405   }
406 #else
407   {
408     int i;
409     for (i = 0; silc_default_pkcs_alg[i].name; i++) {
410       entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
411       if (!strcmp(entry->name, algorithm) &&
412 	  (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme)))
413 	return (const SilcPKCSAlgorithm *)entry;
414     }
415   }
416 #endif /* SILC_SYMBIAN */
417 
418   return NULL;
419 }
420 
421 /* Returns PKCS context */
422 
silc_pkcs_get_pkcs(void * key)423 const SilcPKCSObject *silc_pkcs_get_pkcs(void *key)
424 {
425   SilcPublicKey public_key = key;
426   return public_key->pkcs;
427 }
428 
429 /* Returns PKCS algorithm context */
430 
silc_pkcs_get_algorithm(void * key)431 const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(void *key)
432 {
433   SilcPublicKey public_key = key;
434   return public_key->pkcs->get_algorithm(public_key->public_key);
435 }
436 
437 /* Return algorithm name */
438 
silc_pkcs_get_name(void * key)439 const char *silc_pkcs_get_name(void *key)
440 {
441   const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(key);
442   return pkcs->name;
443 }
444 
445 /* Returns PKCS type */
446 
silc_pkcs_get_type(void * key)447 SilcPKCSType silc_pkcs_get_type(void *key)
448 {
449   SilcPublicKey public_key = key;
450   return public_key->pkcs->type;
451 }
452 
453 /* Allocates new public key from the key data */
454 
silc_pkcs_public_key_alloc(SilcPKCSType type,unsigned char * key,SilcUInt32 key_len,SilcPublicKey * ret_public_key)455 SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
456 				    unsigned char *key,
457 				    SilcUInt32 key_len,
458 				    SilcPublicKey *ret_public_key)
459 {
460   const SilcPKCSObject *pkcs;
461   SilcPublicKey public_key;
462 
463   if (!ret_public_key)
464     return FALSE;
465 
466   /* Allocate public key context */
467   public_key = silc_calloc(1, sizeof(*public_key));
468   if (!public_key)
469     return FALSE;
470 
471   public_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
472   if (!public_key->pkcs) {
473     silc_free(public_key);
474     return FALSE;
475   }
476 
477   /* Import the PKCS public key */
478   if (!pkcs->import_public_key(key, key_len, &public_key->public_key)) {
479     silc_free(public_key);
480     return FALSE;
481   }
482 
483   *ret_public_key = public_key;
484 
485   return TRUE;
486 }
487 
488 /* Frees the public key */
489 
silc_pkcs_public_key_free(SilcPublicKey public_key)490 void silc_pkcs_public_key_free(SilcPublicKey public_key)
491 {
492   public_key->pkcs->public_key_free(public_key->public_key);
493   silc_free(public_key);
494 }
495 
496 /* Exports public key */
497 
silc_pkcs_public_key_encode(SilcPublicKey public_key,SilcUInt32 * ret_len)498 unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
499 					   SilcUInt32 *ret_len)
500 {
501   return public_key->pkcs->export_public_key(public_key->public_key,
502 					     ret_len);
503 }
504 
505 /* Return key length */
506 
silc_pkcs_public_key_get_len(SilcPublicKey public_key)507 SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key)
508 {
509   return public_key->pkcs->public_key_bitlen(public_key->public_key);
510 }
511 
512 /* Returns internal PKCS public key context */
513 
silc_pkcs_get_context(SilcPKCSType type,SilcPublicKey public_key)514 void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key)
515 {
516   if (public_key->pkcs->type != type)
517     return NULL;
518   return public_key->public_key;
519 }
520 
521 
522 /* Allocates new private key from key data */
523 
silc_pkcs_private_key_alloc(SilcPKCSType type,unsigned char * key,SilcUInt32 key_len,SilcPrivateKey * ret_private_key)524 SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
525 				     unsigned char *key,
526 				     SilcUInt32 key_len,
527 				     SilcPrivateKey *ret_private_key)
528 {
529   const SilcPKCSObject *pkcs;
530   SilcPrivateKey private_key;
531 
532   if (!ret_private_key)
533     return FALSE;
534 
535   /* Allocate private key context */
536   private_key = silc_calloc(1, sizeof(*private_key));
537   if (!private_key)
538     return FALSE;
539 
540   private_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
541   if (!private_key->pkcs) {
542     silc_free(private_key);
543     return FALSE;
544   }
545 
546   /* Import the PKCS private key */
547   if (!pkcs->import_private_key(key, key_len, &private_key->private_key)) {
548     silc_free(private_key);
549     return FALSE;
550   }
551 
552   *ret_private_key = private_key;
553 
554   return TRUE;
555 }
556 
557 /* Return key length */
558 
silc_pkcs_private_key_get_len(SilcPrivateKey private_key)559 SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key)
560 {
561   return private_key->pkcs->private_key_bitlen(private_key->private_key);
562 }
563 
564 /* Frees the private key */
565 
silc_pkcs_private_key_free(SilcPrivateKey private_key)566 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
567 {
568   private_key->pkcs->private_key_free(private_key->private_key);
569   silc_free(private_key);
570 }
571 
572 /* Encrypts */
573 
silc_pkcs_encrypt(SilcPublicKey public_key,unsigned char * src,SilcUInt32 src_len,unsigned char * dst,SilcUInt32 dst_size,SilcUInt32 * dst_len,SilcRng rng)574 SilcBool silc_pkcs_encrypt(SilcPublicKey public_key,
575 			   unsigned char *src, SilcUInt32 src_len,
576 			   unsigned char *dst, SilcUInt32 dst_size,
577 			   SilcUInt32 *dst_len, SilcRng rng)
578 {
579   return public_key->pkcs->encrypt(public_key->public_key, src, src_len,
580 				   dst, dst_size, dst_len, rng);
581 }
582 
583 /* Decrypts */
584 
silc_pkcs_decrypt(SilcPrivateKey private_key,unsigned char * src,SilcUInt32 src_len,unsigned char * dst,SilcUInt32 dst_size,SilcUInt32 * dst_len)585 SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
586 			   unsigned char *src, SilcUInt32 src_len,
587 			   unsigned char *dst, SilcUInt32 dst_size,
588 			   SilcUInt32 *dst_len)
589 {
590   return private_key->pkcs->decrypt(private_key->private_key, src, src_len,
591 				    dst, dst_size, dst_len);
592 }
593 
594 /* Generates signature */
595 
silc_pkcs_sign(SilcPrivateKey private_key,unsigned char * src,SilcUInt32 src_len,unsigned char * dst,SilcUInt32 dst_size,SilcUInt32 * dst_len,SilcBool compute_hash,SilcHash hash)596 SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
597 			unsigned char *src, SilcUInt32 src_len,
598 			unsigned char *dst, SilcUInt32 dst_size,
599 			SilcUInt32 *dst_len, SilcBool compute_hash,
600 			SilcHash hash)
601 {
602   return private_key->pkcs->sign(private_key->private_key, src, src_len,
603 				 dst, dst_size, dst_len, compute_hash, hash);
604 }
605 
606 /* Verifies signature */
607 
silc_pkcs_verify(SilcPublicKey public_key,unsigned char * signature,SilcUInt32 signature_len,unsigned char * data,SilcUInt32 data_len,SilcHash hash)608 SilcBool silc_pkcs_verify(SilcPublicKey public_key,
609 			  unsigned char *signature,
610 			  SilcUInt32 signature_len,
611 			  unsigned char *data,
612 			  SilcUInt32 data_len, SilcHash hash)
613 {
614   return public_key->pkcs->verify(public_key->public_key, signature,
615 				  signature_len, data, data_len, hash);
616 }
617 
618 /* Compares two public keys and returns TRUE if they are same key, and
619    FALSE if they are not same. */
620 
silc_pkcs_public_key_compare(SilcPublicKey key1,SilcPublicKey key2)621 SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
622 {
623   if (key1->pkcs->type != key2->pkcs->type)
624     return FALSE;
625 
626   return key1->pkcs->public_key_compare(key1->public_key, key2->public_key);
627 }
628 
629 /* Copies the public key indicated by `public_key' and returns new allocated
630    public key which is indentical to the `public_key'. */
631 
silc_pkcs_public_key_copy(SilcPublicKey public_key)632 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
633 {
634   SilcPublicKey key = silc_calloc(1, sizeof(*key));
635   if (!key)
636     return NULL;
637 
638   key->pkcs = public_key->pkcs;
639   key->public_key = public_key->pkcs->public_key_copy(public_key->public_key);
640   if (!key->public_key) {
641     silc_free(key);
642     return NULL;
643   }
644 
645   return key;
646 }
647 
648 /* Loads any kind of public key */
649 
silc_pkcs_load_public_key(const char * filename,SilcPublicKey * ret_public_key)650 SilcBool silc_pkcs_load_public_key(const char *filename,
651 				   SilcPublicKey *ret_public_key)
652 {
653   unsigned char *data;
654   SilcUInt32 data_len;
655   SilcPublicKey public_key;
656   SilcPKCSType type;
657 
658   SILC_LOG_DEBUG(("Loading public key file '%s'", filename));
659 
660   if (!ret_public_key)
661     return FALSE;
662 
663   data = silc_file_readfile(filename, &data_len);
664   if (!data)
665     return FALSE;
666 
667   /* Allocate public key context */
668   *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key));
669   if (!public_key) {
670     silc_free(data);
671     return FALSE;
672   }
673 
674   /* Try loading all types until one succeeds. */
675   for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
676     public_key->pkcs = silc_pkcs_find_pkcs(type);
677     if (!public_key->pkcs)
678       continue;
679 
680     if (public_key->pkcs->import_public_key_file(data, data_len,
681 						 SILC_PKCS_FILE_BASE64,
682 						 &public_key->public_key)) {
683       silc_free(data);
684       return TRUE;
685     }
686 
687     if (public_key->pkcs->import_public_key_file(data, data_len,
688 						 SILC_PKCS_FILE_BIN,
689 						 &public_key->public_key)) {
690       silc_free(data);
691       return TRUE;
692     }
693   }
694 
695   silc_free(data);
696   silc_free(public_key);
697   *ret_public_key = NULL;
698   return FALSE;
699 }
700 
701 /* Saves public key into a file */
702 
silc_pkcs_save_public_key(const char * filename,SilcPublicKey public_key,SilcPKCSFileEncoding encoding)703 SilcBool silc_pkcs_save_public_key(const char *filename,
704 				   SilcPublicKey public_key,
705 				   SilcPKCSFileEncoding encoding)
706 {
707   unsigned char *data;
708   SilcUInt32 data_len;
709 
710   /* Export the public key file */
711   data = public_key->pkcs->export_public_key_file(public_key->public_key,
712 						  encoding, &data_len);
713   if (!data)
714     return FALSE;
715 
716   /* Write to file */
717   if (silc_file_writefile(filename, data, data_len)) {
718     silc_free(data);
719     return FALSE;
720   }
721 
722   silc_free(data);
723   return TRUE;
724 }
725 
726 /* Loads any kind of private key */
727 
silc_pkcs_load_private_key(const char * filename,const unsigned char * passphrase,SilcUInt32 passphrase_len,SilcPrivateKey * ret_private_key)728 SilcBool silc_pkcs_load_private_key(const char *filename,
729 				    const unsigned char *passphrase,
730 				    SilcUInt32 passphrase_len,
731 				    SilcPrivateKey *ret_private_key)
732 {
733   unsigned char *data;
734   SilcUInt32 data_len;
735   SilcPrivateKey private_key;
736   SilcPKCSType type;
737 
738   SILC_LOG_DEBUG(("Loading private key file '%s'", filename));
739 
740   if (!ret_private_key)
741     return FALSE;
742 
743   data = silc_file_readfile(filename, &data_len);
744   if (!data)
745     return FALSE;
746 
747   /* Allocate private key context */
748   *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key));
749   if (!private_key) {
750     silc_free(data);
751     return FALSE;
752   }
753 
754   /* Try loading all types until one succeeds. */
755   for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
756     private_key->pkcs = silc_pkcs_find_pkcs(type);
757     if (!private_key->pkcs)
758       continue;
759 
760     if (private_key->pkcs->import_private_key_file(
761 					      data, data_len,
762 					      passphrase,
763 					      passphrase_len,
764 					      SILC_PKCS_FILE_BIN,
765 					      &private_key->private_key)) {
766       silc_free(data);
767       return TRUE;
768     }
769 
770     if (private_key->pkcs->import_private_key_file(
771 					      data, data_len,
772 					      passphrase,
773 					      passphrase_len,
774 					      SILC_PKCS_FILE_BASE64,
775 					      &private_key->private_key)) {
776       silc_free(data);
777       return TRUE;
778     }
779   }
780 
781   silc_free(data);
782   silc_free(private_key);
783   *ret_private_key = NULL;
784   return FALSE;
785 }
786 
787 /* Saves private key into a file */
788 
silc_pkcs_save_private_key(const char * filename,SilcPrivateKey private_key,const unsigned char * passphrase,SilcUInt32 passphrase_len,SilcPKCSFileEncoding encoding,SilcRng rng)789 SilcBool silc_pkcs_save_private_key(const char *filename,
790 				    SilcPrivateKey private_key,
791 				    const unsigned char *passphrase,
792 				    SilcUInt32 passphrase_len,
793 				    SilcPKCSFileEncoding encoding,
794 				    SilcRng rng)
795 {
796   unsigned char *data;
797   SilcUInt32 data_len;
798 
799   /* Export the private key file */
800   data = private_key->pkcs->export_private_key_file(private_key->private_key,
801 						    passphrase,
802 						    passphrase_len,
803 						    encoding, rng, &data_len);
804   if (!data)
805     return FALSE;
806 
807   /* Write to file */
808   if (silc_file_writefile(filename, data, data_len)) {
809     silc_free(data);
810     return FALSE;
811   }
812 
813   silc_free(data);
814   return TRUE;
815 }
816