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 */
362 /* Finds PKCS object */
364 const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type)
366 SilcPKCSObject *entry;
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;
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;
385 #endif /* SILC_SYMBIAN */
390 /* Finds PKCS algorithms object */
392 const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
395 SilcPKCSAlgorithm *entry;
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;
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;
416 #endif /* SILC_SYMBIAN */
421 /* Returns PKCS context */
423 const SilcPKCSObject *silc_pkcs_get_pkcs(void *key)
425 SilcPublicKey public_key = key;
426 return public_key->pkcs;
429 /* Returns PKCS algorithm context */
431 const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(void *key)
433 SilcPublicKey public_key = key;
434 return public_key->pkcs->get_algorithm(public_key->public_key);
437 /* Return algorithm name */
439 const char *silc_pkcs_get_name(void *key)
441 const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(key);
445 /* Returns PKCS type */
447 SilcPKCSType silc_pkcs_get_type(void *key)
449 SilcPublicKey public_key = key;
450 return public_key->pkcs->type;
453 /* Allocates new public key from the key data */
455 SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
458 SilcPublicKey *ret_public_key)
460 const SilcPKCSObject *pkcs;
461 SilcPublicKey public_key;
466 /* Allocate public key context */
467 public_key = silc_calloc(1, sizeof(*public_key));
471 public_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
472 if (!public_key->pkcs) {
473 silc_free(public_key);
477 /* Import the PKCS public key */
478 if (!pkcs->import_public_key(key, key_len, &public_key->public_key)) {
479 silc_free(public_key);
483 *ret_public_key = public_key;
488 /* Frees the public key */
490 void silc_pkcs_public_key_free(SilcPublicKey public_key)
492 public_key->pkcs->public_key_free(public_key->public_key);
493 silc_free(public_key);
496 /* Exports public key */
498 unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
501 return public_key->pkcs->export_public_key(public_key->public_key,
505 /* Return key length */
507 SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key)
509 return public_key->pkcs->public_key_bitlen(public_key->public_key);
512 /* Returns internal PKCS public key context */
514 void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key)
516 if (public_key->pkcs->type != type)
518 return public_key->public_key;
522 /* Allocates new private key from key data */
524 SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
527 SilcPrivateKey *ret_private_key)
529 const SilcPKCSObject *pkcs;
530 SilcPrivateKey private_key;
532 if (!ret_private_key)
535 /* Allocate private key context */
536 private_key = silc_calloc(1, sizeof(*private_key));
540 private_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
541 if (!private_key->pkcs) {
542 silc_free(private_key);
546 /* Import the PKCS private key */
547 if (!pkcs->import_private_key(key, key_len, &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->private_key);
564 /* Frees the private key */
566 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
568 private_key->pkcs->private_key_free(private_key->private_key);
569 silc_free(private_key);
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)
579 return public_key->pkcs->encrypt(public_key->public_key, src, src_len,
580 dst, dst_size, dst_len, rng);
585 SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
586 unsigned char *src, SilcUInt32 src_len,
587 unsigned char *dst, SilcUInt32 dst_size,
590 return private_key->pkcs->decrypt(private_key->private_key, src, src_len,
591 dst, dst_size, dst_len);
594 /* Generates signature */
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,
602 return private_key->pkcs->sign(private_key->private_key, src, src_len,
603 dst, dst_size, dst_len, compute_hash, hash);
606 /* Verifies signature */
608 SilcBool silc_pkcs_verify(SilcPublicKey public_key,
609 unsigned char *signature,
610 SilcUInt32 signature_len,
612 SilcUInt32 data_len, SilcHash hash)
614 return public_key->pkcs->verify(public_key->public_key, signature,
615 signature_len, data, data_len, hash);
618 /* Compares two public keys and returns TRUE if they are same key, and
619 FALSE if they are not same. */
621 SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
623 if (key1->pkcs->type != key2->pkcs->type)
626 return key1->pkcs->public_key_compare(key1->public_key, key2->public_key);
629 /* Copies the public key indicated by `public_key' and returns new allocated
630 public key which is indentical to the `public_key'. */
632 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
634 SilcPublicKey key = silc_calloc(1, sizeof(*key));
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) {
648 /* Loads any kind of public key */
650 SilcBool silc_pkcs_load_public_key(const char *filename,
651 SilcPublicKey *ret_public_key)
655 SilcPublicKey public_key;
658 SILC_LOG_DEBUG(("Loading public key file '%s'", filename));
663 data = silc_file_readfile(filename, &data_len);
667 /* Allocate public key context */
668 *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key));
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)
680 if (public_key->pkcs->import_public_key_file(data, data_len,
681 SILC_PKCS_FILE_BASE64,
682 &public_key->public_key)) {
687 if (public_key->pkcs->import_public_key_file(data, data_len,
689 &public_key->public_key)) {
696 silc_free(public_key);
697 *ret_public_key = NULL;
701 /* Saves public key into a file */
703 SilcBool silc_pkcs_save_public_key(const char *filename,
704 SilcPublicKey public_key,
705 SilcPKCSFileEncoding encoding)
710 /* Export the public key file */
711 data = public_key->pkcs->export_public_key_file(public_key->public_key,
712 encoding, &data_len);
717 if (silc_file_writefile(filename, data, data_len)) {
726 /* Loads any kind of 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)
735 SilcPrivateKey private_key;
738 SILC_LOG_DEBUG(("Loading private key file '%s'", filename));
740 if (!ret_private_key)
743 data = silc_file_readfile(filename, &data_len);
747 /* Allocate private key context */
748 *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key));
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)
760 if (private_key->pkcs->import_private_key_file(
765 &private_key->private_key)) {
770 if (private_key->pkcs->import_private_key_file(
774 SILC_PKCS_FILE_BASE64,
775 &private_key->private_key)) {
782 silc_free(private_key);
783 *ret_private_key = NULL;
787 /* Saves private key into a file */
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,
799 /* Export the private key file */
800 data = private_key->pkcs->export_private_key_file(private_key->private_key,
803 encoding, rng, &data_len);
808 if (silc_file_writefile(filename, data, data_len)) {