5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 Pekka Riikonen
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.
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.
23 #include "silcpkcs1_i.h"
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
32 #define SILC_PKCS_LIST TRUE
33 #define SILC_PKCS_ALG_LIST TRUE
34 #endif /* SILC_SYMBIAN */
36 /* Static list of PKCS for silc_pkcs_register_default(). */
37 const SilcPKCSObject silc_default_pkcs[] =
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,
60 silc_pkcs_silc_verify,
64 0, NULL, NULL, NULL, NULL, NULL,
65 NULL, NULL, NULL, NULL, NULL
69 /* Builtin PKCS algorithms */
70 const SilcPKCSAlgorithm silc_default_pkcs_alg[] =
72 /* PKCS #1, Version 1.5 without hash OIDs */
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,
90 silc_pkcs1_sign_no_oid,
91 silc_pkcs1_verify_no_oid
94 /* PKCS #1, Version 1.5 */
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,
117 NULL, NULL, NULL, NULL,
118 NULL, NULL, NULL, NULL,
119 NULL, NULL, NULL, NULL,
124 /* Register a new PKCS into SILC. */
126 SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs)
129 SilcPKCSObject *newpkcs;
131 SILC_LOG_DEBUG(("Registering new PKCS"));
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)
143 newpkcs = silc_calloc(1, sizeof(*newpkcs));
149 if (silc_pkcs_list == NULL)
150 silc_pkcs_list = silc_dlist_init();
151 silc_dlist_add(silc_pkcs_list, newpkcs);
153 #endif /* SILC_SYMBIAN */
157 /* Unregister a PKCS from the SILC. */
159 SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs)
162 SilcPKCSObject *entry;
164 SILC_LOG_DEBUG(("Unregistering PKCS"));
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);
175 if (silc_dlist_count(silc_pkcs_list) == 0) {
176 silc_dlist_uninit(silc_pkcs_list);
177 silc_pkcs_list = NULL;
184 #endif /* SILC_SYMBIAN */
188 /* Register algorithm */
190 SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs)
193 SilcPKCSAlgorithm *newalg;
195 SILC_LOG_DEBUG(("Registering new PKCS algorithm %s",
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))
210 newalg = silc_calloc(1, sizeof(*newalg));
215 newalg->name = strdup(pkcs->name);
219 newalg->scheme = strdup(pkcs->scheme);
223 newalg->hash = strdup(pkcs->hash);
228 if (silc_pkcs_alg_list == NULL)
229 silc_pkcs_alg_list = silc_dlist_init();
230 silc_dlist_add(silc_pkcs_alg_list, newalg);
232 #endif /* SILC_SYMBIAN */
236 /* Unregister algorithm */
238 SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs)
241 SilcPKCSAlgorithm*entry;
243 SILC_LOG_DEBUG(("Unregistering PKCS algorithm"));
245 if (!silc_pkcs_alg_list)
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);
257 if (silc_dlist_count(silc_pkcs_alg_list) == 0) {
258 silc_dlist_uninit(silc_pkcs_alg_list);
259 silc_pkcs_alg_list = NULL;
266 #endif /* SILC_SYMBIAN */
270 /* Function that registers all the default PKCS and PKCS algorithms. */
272 SilcBool silc_pkcs_register_default(void)
277 for (i = 0; silc_default_pkcs[i].type; i++)
278 silc_pkcs_register(&(silc_default_pkcs[i]));
280 for (i = 0; silc_default_pkcs_alg[i].name; i++)
281 silc_pkcs_algorithm_register(&(silc_default_pkcs_alg[i]));
283 #endif /* SILC_SYMBIAN */
287 SilcBool silc_pkcs_unregister_all(void)
290 SilcPKCSObject *entry;
291 SilcPKCSAlgorithm *alg;
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);
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)
311 #endif /* SILC_SYMBIAN */
315 /* Returns comma separated list of supported PKCS algorithms */
317 char *silc_pkcs_get_supported(void)
319 SilcPKCSAlgorithm *entry;
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);
332 memcpy(list + (len - strlen(entry->name)),
333 entry->name, strlen(entry->name));
334 memcpy(list + len, ",", 1);
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);
348 memcpy(list + (len - strlen(entry->name)),
349 entry->name, strlen(entry->name));
350 memcpy(list + len, ",", 1);
354 #endif /* SILC_SYMBIAN */
361 /* Finds PKCS object */
363 const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type)
365 SilcPKCSObject *entry;
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;
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;
384 #endif /* SILC_SYMBIAN */
389 /* Finds PKCS algorithms object */
391 const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
394 SilcPKCSAlgorithm *entry;
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;
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;
415 #endif /* SILC_SYMBIAN */
420 /* Returns PKCS context */
422 const SilcPKCSObject *silc_pkcs_get_pkcs(void *key)
424 SilcPublicKey public_key = key;
425 return public_key->pkcs;
428 /* Returns PKCS algorithm context */
430 const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(void *key)
432 SilcPublicKey public_key = key;
433 return public_key->pkcs->get_algorithm(public_key->public_key);
436 /* Return algorithm name */
438 const char *silc_pkcs_get_name(void *key)
440 const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(key);
444 /* Returns PKCS type */
446 SilcPKCSType silc_pkcs_get_type(void *key)
448 SilcPublicKey public_key = key;
449 return public_key->pkcs->type;
452 /* Allocates new public key from the key data */
454 SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
457 SilcPublicKey *ret_public_key)
459 const SilcPKCSObject *pkcs;
460 SilcPublicKey public_key;
465 /* Allocate public key context */
466 public_key = silc_calloc(1, sizeof(*public_key));
470 public_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
471 if (!public_key->pkcs) {
472 silc_free(public_key);
476 /* Import the PKCS public key */
477 if (!pkcs->import_public_key(key, key_len, &public_key->public_key)) {
478 silc_free(public_key);
482 *ret_public_key = public_key;
487 /* Frees the public key */
489 void silc_pkcs_public_key_free(SilcPublicKey public_key)
491 public_key->pkcs->public_key_free(public_key->public_key);
492 silc_free(public_key);
495 /* Exports public key */
497 unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
500 return public_key->pkcs->export_public_key(public_key->public_key,
504 /* Return key length */
506 SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key)
508 return public_key->pkcs->public_key_bitlen(public_key->public_key);
511 /* Returns internal PKCS public key context */
513 void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key)
515 if (public_key->pkcs->type != type)
517 return public_key->public_key;
521 /* Allocates new private key from key data */
523 SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
526 SilcPrivateKey *ret_private_key)
528 const SilcPKCSObject *pkcs;
529 SilcPrivateKey private_key;
531 if (!ret_private_key)
534 /* Allocate private key context */
535 private_key = silc_calloc(1, sizeof(*private_key));
539 private_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
540 if (!private_key->pkcs) {
541 silc_free(private_key);
545 /* Import the PKCS private key */
546 if (!pkcs->import_private_key(key, key_len, &private_key->private_key)) {
547 silc_free(private_key);
551 *ret_private_key = private_key;
556 /* Return key length */
558 SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key)
560 return private_key->pkcs->private_key_bitlen(private_key->private_key);
563 /* Frees the private key */
565 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
567 private_key->pkcs->private_key_free(private_key->private_key);
568 silc_free(private_key);
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)
578 return public_key->pkcs->encrypt(public_key->public_key, src, src_len,
579 dst, dst_size, dst_len, rng);
584 SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
585 unsigned char *src, SilcUInt32 src_len,
586 unsigned char *dst, SilcUInt32 dst_size,
589 return private_key->pkcs->decrypt(private_key->private_key, src, src_len,
590 dst, dst_size, dst_len);
593 /* Generates signature */
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,
601 return private_key->pkcs->sign(private_key->private_key, src, src_len,
602 dst, dst_size, dst_len, compute_hash, hash);
605 /* Verifies signature */
607 SilcBool silc_pkcs_verify(SilcPublicKey public_key,
608 unsigned char *signature,
609 SilcUInt32 signature_len,
611 SilcUInt32 data_len, SilcHash hash)
613 return public_key->pkcs->verify(public_key->public_key, signature,
614 signature_len, data, data_len, hash);
617 /* Compares two public keys and returns TRUE if they are same key, and
618 FALSE if they are not same. */
620 SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
622 if (key1->pkcs->type != key2->pkcs->type)
625 return key1->pkcs->public_key_compare(key1->public_key, key2->public_key);
628 /* Copies the public key indicated by `public_key' and returns new allocated
629 public key which is indentical to the `public_key'. */
631 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
633 SilcPublicKey key = silc_calloc(1, sizeof(*key));
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) {
647 /* Loads any kind of public key */
649 SilcBool silc_pkcs_load_public_key(const char *filename,
650 SilcPublicKey *ret_public_key)
654 SilcPublicKey public_key;
657 SILC_LOG_DEBUG(("Loading public key file '%s'", filename));
662 data = silc_file_readfile(filename, &data_len);
666 /* Allocate public key context */
667 *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key));
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)
679 if (public_key->pkcs->import_public_key_file(data, data_len,
680 SILC_PKCS_FILE_BASE64,
681 &public_key->public_key)) {
686 if (public_key->pkcs->import_public_key_file(data, data_len,
688 &public_key->public_key)) {
695 silc_free(public_key);
696 *ret_public_key = NULL;
700 /* Saves public key into a file */
702 SilcBool silc_pkcs_save_public_key(const char *filename,
703 SilcPublicKey public_key,
704 SilcPKCSFileEncoding encoding)
709 /* Export the public key file */
710 data = public_key->pkcs->export_public_key_file(public_key->public_key,
711 encoding, &data_len);
716 if (silc_file_writefile(filename, data, data_len)) {
725 /* Loads any kind of private key */
727 SilcBool silc_pkcs_load_private_key(const char *filename,
728 const unsigned char *passphrase,
729 SilcUInt32 passphrase_len,
730 SilcPrivateKey *ret_private_key)
734 SilcPrivateKey private_key;
737 SILC_LOG_DEBUG(("Loading private key file '%s'", filename));
739 if (!ret_private_key)
742 data = silc_file_readfile(filename, &data_len);
746 /* Allocate private key context */
747 *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key));
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)
759 if (private_key->pkcs->import_private_key_file(
764 &private_key->private_key)) {
769 if (private_key->pkcs->import_private_key_file(
773 SILC_PKCS_FILE_BASE64,
774 &private_key->private_key)) {
781 silc_free(private_key);
782 *ret_private_key = NULL;
786 /* Saves private key into a file */
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,
798 /* Export the private key file */
799 data = private_key->pkcs->export_private_key_file(private_key->private_key,
802 encoding, rng, &data_len);
807 if (silc_file_writefile(filename, data, data_len)) {