5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 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_EPOC */
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_EPOC */
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_EPOC */
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_EPOC */
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_EPOC */
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_EPOC */
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_EPOC */
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_EPOC */
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].name; i++) {
379 entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
380 if (entry->type == type)
381 return (const SilcPKCSObject *)entry;
384 #endif /* SILC_EPOC */
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_EPOC */
420 /* Returns PKCS context */
422 const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPublicKey public_key)
424 return public_key->pkcs;
427 /* Returns PKCS algorithm context */
429 const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(SilcPublicKey public_key)
431 return public_key->pkcs->get_algorithm(public_key->public_key);
434 /* Return algorithm name */
436 const char *silc_pkcs_get_name(SilcPublicKey public_key)
438 const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(public_key);
442 /* Returns PKCS type */
444 SilcPKCSType silc_pkcs_get_type(SilcPublicKey public_key)
446 return public_key->pkcs->type;
449 /* Allocates new public key from the key data */
451 SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
454 SilcPublicKey *ret_public_key)
456 const SilcPKCSObject *pkcs;
457 SilcPublicKey public_key;
462 /* Allocate public key context */
463 public_key = silc_calloc(1, sizeof(*public_key));
467 public_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
468 if (!public_key->pkcs) {
469 silc_free(public_key);
473 /* Import the PKCS public key */
474 if (!pkcs->import_public_key(key, key_len, &public_key->public_key)) {
475 silc_free(public_key);
479 *ret_public_key = public_key;
484 /* Frees the public key */
486 void silc_pkcs_public_key_free(SilcPublicKey public_key)
488 public_key->pkcs->public_key_free(public_key->public_key);
491 /* Exports public key */
493 unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
496 return public_key->pkcs->export_public_key(public_key->public_key,
500 /* Return key length */
502 SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key)
504 return public_key->pkcs->public_key_bitlen(public_key->public_key);
507 /* Returns internal PKCS public key context */
509 void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key)
511 if (public_key->pkcs->type != type)
513 return public_key->public_key;
517 /* Allocates new private key from key data */
519 SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
522 SilcPrivateKey *ret_private_key)
524 const SilcPKCSObject *pkcs;
525 SilcPrivateKey private_key;
527 if (!ret_private_key)
530 /* Allocate private key context */
531 private_key = silc_calloc(1, sizeof(*private_key));
535 private_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
536 if (!private_key->pkcs) {
537 silc_free(private_key);
541 /* Import the PKCS private key */
542 if (!pkcs->import_private_key(key, key_len, &private_key->private_key)) {
543 silc_free(private_key);
547 *ret_private_key = private_key;
552 /* Return key length */
554 SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key)
556 return private_key->pkcs->private_key_bitlen(private_key->private_key);
559 /* Frees the private key */
561 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
563 private_key->pkcs->private_key_free(private_key->private_key);
568 SilcBool silc_pkcs_encrypt(SilcPublicKey public_key,
569 unsigned char *src, SilcUInt32 src_len,
570 unsigned char *dst, SilcUInt32 dst_size,
573 return public_key->pkcs->encrypt(public_key->public_key, src, src_len,
574 dst, dst_size, dst_len);
579 SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
580 unsigned char *src, SilcUInt32 src_len,
581 unsigned char *dst, SilcUInt32 dst_size,
584 return private_key->pkcs->decrypt(private_key->private_key, src, src_len,
585 dst, dst_size, dst_len);
588 /* Generates signature */
590 SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
591 unsigned char *src, SilcUInt32 src_len,
592 unsigned char *dst, SilcUInt32 dst_size,
593 SilcUInt32 *dst_len, SilcHash hash)
595 return private_key->pkcs->sign(private_key->private_key, src, src_len,
596 dst, dst_size, dst_len, hash);
599 /* Verifies signature */
601 SilcBool silc_pkcs_verify(SilcPublicKey public_key,
602 unsigned char *signature,
603 SilcUInt32 signature_len,
605 SilcUInt32 data_len, SilcHash hash)
607 return public_key->pkcs->verify(public_key->public_key, signature,
608 signature_len, data, data_len, hash);
611 /* Compares two public keys and returns TRUE if they are same key, and
612 FALSE if they are not same. */
614 SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
616 if (key1->pkcs->type != key2->pkcs->type)
619 return key1->pkcs->public_key_compare(key1->public_key, key2->public_key);
622 /* Copies the public key indicated by `public_key' and returns new allocated
623 public key which is indentical to the `public_key'. */
625 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
627 SilcPublicKey key = silc_calloc(1, sizeof(*key));
631 key->pkcs = public_key->pkcs;
632 key->public_key = public_key->pkcs->public_key_copy(public_key->public_key);
633 if (!key->public_key) {
641 /* Loads any kind of public key */
643 SilcBool silc_pkcs_load_public_key(const char *filename,
644 SilcPublicKey *ret_public_key)
648 SilcPublicKey public_key;
651 SILC_LOG_DEBUG(("Loading public key file '%s'", filename));
656 data = silc_file_readfile(filename, &data_len);
660 /* Allocate public key context */
661 *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key));
667 /* Try loading all types until one succeeds. */
668 for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
669 public_key->pkcs = silc_pkcs_find_pkcs(type);
670 if (!public_key->pkcs)
673 if (public_key->pkcs->import_public_key_file(data, data_len,
674 SILC_PKCS_FILE_BASE64,
675 &public_key->public_key)) {
680 if (public_key->pkcs->import_public_key_file(data, data_len,
682 &public_key->public_key)) {
689 silc_free(public_key);
693 /* Saves public key into a file */
695 SilcBool silc_pkcs_save_public_key(const char *filename,
696 SilcPublicKey public_key,
697 SilcPKCSFileEncoding encoding)
702 /* Export the public key file */
703 data = public_key->pkcs->export_public_key_file(public_key->public_key,
704 encoding, &data_len);
709 if (silc_file_writefile(filename, data, data_len)) {
718 /* Loads any kind of private key */
720 SilcBool silc_pkcs_load_private_key(const char *filename,
721 const unsigned char *passphrase,
722 SilcUInt32 passphrase_len,
723 SilcPrivateKey *ret_private_key)
727 SilcPrivateKey private_key;
730 SILC_LOG_DEBUG(("Loading private key file '%s'", filename));
732 if (!ret_private_key)
735 data = silc_file_readfile(filename, &data_len);
739 /* Allocate private key context */
740 *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key));
746 /* Try loading all types until one succeeds. */
747 for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
748 private_key->pkcs = silc_pkcs_find_pkcs(type);
749 if (!private_key->pkcs)
752 if (private_key->pkcs->import_private_key_file(
757 &private_key->private_key)) {
762 if (private_key->pkcs->import_private_key_file(
766 SILC_PKCS_FILE_BASE64,
767 &private_key->private_key)) {
774 silc_free(private_key);
778 /* Saves private key into a file */
780 SilcBool silc_pkcs_save_private_key(const char *filename,
781 SilcPrivateKey private_key,
782 const unsigned char *passphrase,
783 SilcUInt32 passphrase_len,
784 SilcPKCSFileEncoding encoding,
790 /* Export the private key file */
791 data = private_key->pkcs->export_private_key_file(private_key->private_key,
794 encoding, rng, &data_len);
799 if (silc_file_writefile(filename, data, data_len)) {