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 */
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 */
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)
274 /* We use builtin PKCS and algorithms */
278 /* Unregister all PKCS and algorithms */
280 SilcBool silc_pkcs_unregister_all(void)
283 SilcPKCSObject *entry;
284 SilcPKCSAlgorithm *alg;
286 if (silc_pkcs_list) {
287 silc_dlist_start(silc_pkcs_list);
288 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
289 silc_pkcs_unregister(entry);
295 if (silc_pkcs_alg_list) {
296 silc_dlist_start(silc_pkcs_alg_list);
297 while ((alg = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
298 silc_pkcs_algorithm_unregister(alg);
299 if (!silc_pkcs_alg_list)
304 #endif /* SILC_SYMBIAN */
308 /* Returns comma separated list of supported PKCS algorithms */
310 char *silc_pkcs_get_supported(void)
312 SilcPKCSAlgorithm *entry, *entry2;
317 if (silc_pkcs_alg_list) {
318 silc_dlist_start(silc_pkcs_alg_list);
319 while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
320 len += strlen(entry->name);
321 list = silc_realloc(list, len + 1);
325 memcpy(list + (len - strlen(entry->name)),
326 entry->name, strlen(entry->name));
327 memcpy(list + len, ",", 1);
331 #endif /* SILC_SYMBIAN */
333 for (i = 0; silc_default_pkcs_alg[i].name; i++) {
334 entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
336 if (silc_pkcs_alg_list) {
337 silc_dlist_start(silc_pkcs_alg_list);
338 while ((entry2 = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
339 if (!strcmp(entry2->name, entry->name))
346 len += strlen(entry->name);
347 list = silc_realloc(list, len + 1);
351 memcpy(list + (len - strlen(entry->name)),
352 entry->name, strlen(entry->name));
353 memcpy(list + len, ",", 1);
362 /* Finds PKCS object */
364 const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type)
366 SilcPKCSObject *entry;
370 if (silc_pkcs_list) {
371 silc_dlist_start(silc_pkcs_list);
372 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
373 if (entry->type == type)
374 return (const SilcPKCSObject *)entry;
377 #endif /* SILC_SYMBIAN */
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;
388 /* Finds PKCS algorithms object */
390 const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
393 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;
405 #endif /* SILC_SYMBIAN */
407 for (i = 0; silc_default_pkcs_alg[i].name; i++) {
408 entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
409 if (!strcmp(entry->name, algorithm) &&
410 (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme)))
411 return (const SilcPKCSAlgorithm *)entry;
417 /* Returns PKCS context */
419 const SilcPKCSObject *silc_pkcs_get_pkcs(void *key)
421 SilcPublicKey public_key = key;
422 return public_key->pkcs;
425 /* Returns PKCS algorithm context */
427 const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(void *key)
429 SilcPublicKey public_key = key;
430 return public_key->pkcs->get_algorithm(public_key->pkcs,
431 public_key->public_key);
434 /* Return algorithm name */
436 const char *silc_pkcs_get_name(void *key)
438 const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(key);
442 /* Returns PKCS type */
444 SilcPKCSType silc_pkcs_get_type(void *key)
446 SilcPublicKey public_key = key;
447 return public_key->pkcs->type;
450 /* Allocates new public key from the key data */
452 SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
455 SilcPublicKey *ret_public_key)
457 const SilcPKCSObject *pkcs;
458 SilcPublicKey public_key;
463 /* Allocate public key context */
464 public_key = silc_calloc(1, sizeof(*public_key));
468 public_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
469 if (!public_key->pkcs) {
470 silc_free(public_key);
474 /* Import the PKCS public key */
475 if (!pkcs->import_public_key(pkcs, key, key_len, &public_key->public_key)) {
476 silc_free(public_key);
480 *ret_public_key = public_key;
485 /* Frees the public key */
487 void silc_pkcs_public_key_free(SilcPublicKey public_key)
489 public_key->pkcs->public_key_free(public_key->pkcs, public_key->public_key);
490 silc_free(public_key);
493 /* Exports public key */
495 unsigned char *silc_pkcs_public_key_encode(SilcStack stack,
496 SilcPublicKey public_key,
499 return public_key->pkcs->export_public_key(public_key->pkcs, stack,
500 public_key->public_key, ret_len);
503 /* Return key length */
505 SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key)
507 return public_key->pkcs->public_key_bitlen(public_key->pkcs,
508 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(pkcs, key, key_len,
547 &private_key->private_key)) {
548 silc_free(private_key);
552 *ret_private_key = private_key;
557 /* Return key length */
559 SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key)
561 return private_key->pkcs->private_key_bitlen(private_key->pkcs,
562 private_key->private_key);
565 /* Frees the private key */
567 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
569 private_key->pkcs->private_key_free(private_key->pkcs,
570 private_key->private_key);
571 silc_free(private_key);
576 SilcAsyncOperation silc_pkcs_encrypt(SilcPublicKey public_key,
577 unsigned char *src, SilcUInt32 src_len,
579 SilcPKCSEncryptCb encrypt_cb,
582 return public_key->pkcs->encrypt(public_key->pkcs,
583 public_key->public_key, src, src_len,
584 rng, encrypt_cb, context);
589 SilcAsyncOperation silc_pkcs_decrypt(SilcPrivateKey private_key,
590 unsigned char *src, SilcUInt32 src_len,
591 SilcPKCSDecryptCb decrypt_cb,
594 return private_key->pkcs->decrypt(private_key->pkcs,
595 private_key->private_key, src, src_len,
596 decrypt_cb, context);
599 /* Generates signature */
601 SilcAsyncOperation silc_pkcs_sign(SilcPrivateKey private_key,
604 SilcBool compute_hash,
606 SilcPKCSSignCb sign_cb,
609 return private_key->pkcs->sign(private_key->pkcs,
610 private_key->private_key, src, src_len,
611 compute_hash, hash, sign_cb, context);
614 /* Verifies signature */
616 SilcAsyncOperation silc_pkcs_verify(SilcPublicKey public_key,
617 unsigned char *signature,
618 SilcUInt32 signature_len,
622 SilcPKCSVerifyCb verify_cb,
625 return public_key->pkcs->verify(public_key->pkcs,
626 public_key->public_key, signature,
627 signature_len, data, data_len, hash,
631 /* Compares two public keys and returns TRUE if they are same key, and
632 FALSE if they are not same. */
634 SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
636 if (key1->pkcs->type != key2->pkcs->type)
639 return key1->pkcs->public_key_compare(key1->pkcs,
640 key1->public_key, key2->public_key);
643 /* Copies the public key indicated by `public_key' and returns new allocated
644 public key which is indentical to the `public_key'. */
646 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
648 SilcPublicKey key = silc_calloc(1, sizeof(*key));
652 key->pkcs = public_key->pkcs;
653 key->public_key = public_key->pkcs->public_key_copy(public_key->pkcs,
654 public_key->public_key);
655 if (!key->public_key) {
663 /* Loads any kind of public key */
665 SilcBool silc_pkcs_load_public_key(const char *filename,
666 SilcPublicKey *ret_public_key)
670 SilcPublicKey public_key;
673 SILC_LOG_DEBUG(("Loading public key file '%s'", filename));
678 data = silc_file_readfile(filename, &data_len, NULL);
682 /* Allocate public key context */
683 *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key));
689 /* Try loading all types until one succeeds. */
690 for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
691 public_key->pkcs = silc_pkcs_find_pkcs(type);
692 if (!public_key->pkcs)
695 if (public_key->pkcs->import_public_key_file(public_key->pkcs,
697 SILC_PKCS_FILE_BASE64,
698 &public_key->public_key)) {
703 if (public_key->pkcs->import_public_key_file(public_key->pkcs,
706 &public_key->public_key)) {
713 silc_free(public_key);
714 *ret_public_key = NULL;
718 /* Saves public key into a file */
720 SilcBool silc_pkcs_save_public_key(const char *filename,
721 SilcPublicKey public_key,
722 SilcPKCSFileEncoding encoding)
728 stack = silc_stack_alloc(2048, silc_crypto_stack());
730 /* Export the public key file */
731 data = public_key->pkcs->export_public_key_file(public_key->pkcs,
733 public_key->public_key,
734 encoding, &data_len);
736 silc_stack_free(stack);
741 if (silc_file_writefile(filename, data, data_len)) {
742 silc_sfree(stack, data);
743 silc_stack_free(stack);
747 silc_sfree(stack, data);
748 silc_stack_free(stack);
752 /* Loads any kind of private key */
754 SilcBool silc_pkcs_load_private_key(const char *filename,
755 const unsigned char *passphrase,
756 SilcUInt32 passphrase_len,
757 SilcPrivateKey *ret_private_key)
761 SilcPrivateKey private_key;
764 SILC_LOG_DEBUG(("Loading private key file '%s'", filename));
766 if (!ret_private_key)
769 data = silc_file_readfile(filename, &data_len, NULL);
773 /* Allocate private key context */
774 *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key));
780 /* Try loading all types until one succeeds. */
781 for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
782 private_key->pkcs = silc_pkcs_find_pkcs(type);
783 if (!private_key->pkcs)
786 if (private_key->pkcs->import_private_key_file(
792 &private_key->private_key)) {
797 if (private_key->pkcs->import_private_key_file(
802 SILC_PKCS_FILE_BASE64,
803 &private_key->private_key)) {
810 silc_free(private_key);
811 *ret_private_key = NULL;
815 /* Saves private key into a file */
817 SilcBool silc_pkcs_save_private_key(const char *filename,
818 SilcPrivateKey private_key,
819 const unsigned char *passphrase,
820 SilcUInt32 passphrase_len,
821 SilcPKCSFileEncoding encoding,
828 stack = silc_stack_alloc(2048, silc_crypto_stack());
830 /* Export the private key file */
831 data = private_key->pkcs->export_private_key_file(private_key->pkcs, stack,
832 private_key->private_key,
835 encoding, rng, &data_len);
837 silc_stack_free(stack);
842 if (silc_file_writefile(filename, data, data_len)) {
843 silc_sfree(stack, data);
844 silc_stack_free(stack);
848 silc_sfree(stack, data);
849 silc_stack_free(stack);
853 /* Hash public key of any type. */
855 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
857 SilcPublicKey public_key = key;
861 SilcStack stack = NULL;
863 if (silc_crypto_stack())
864 stack = silc_stack_alloc(2048, silc_crypto_stack());
866 pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len);
868 silc_stack_free(stack);
872 hash = silc_hash_data(pk, SILC_32_TO_PTR(pk_len));
874 silc_sfree(stack, pk);
875 silc_stack_free(stack);
880 /* Compares two SILC Public keys. It may be used as SilcHashTable
881 comparison function. */
883 SilcBool silc_hash_public_key_compare(void *key1, void *key2,
886 return silc_pkcs_public_key_compare(key1, key2);