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