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