X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccrypt%2Fsilcpkcs.c;h=9611866171e7af8ba286dc5dc92cfb7a1a5102ea;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=7aeb3d1c09ecf41979fafe3abf4eefc8af9a93eb;hpb=410642a14d4185abd75715cee3f5177cd55b1ceb;p=silc.git diff --git a/lib/silccrypt/silcpkcs.c b/lib/silccrypt/silcpkcs.c index 7aeb3d1c..96118661 100644 --- a/lib/silccrypt/silcpkcs.c +++ b/lib/silccrypt/silcpkcs.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,8 +21,12 @@ #include "silc.h" #include "silcpk_i.h" #include "silcpkcs1_i.h" +#include "dsa.h" +#ifdef SILC_DIST_SSH +#include "silcssh_pkcs.h" +#endif /* SILC_DIST_SSH */ -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN /* Dynamically registered list of PKCS. */ SilcDList silc_pkcs_list = NULL; SilcDList silc_pkcs_alg_list = NULL; @@ -31,7 +35,7 @@ SilcDList silc_pkcs_alg_list = NULL; #else #define SILC_PKCS_LIST TRUE #define SILC_PKCS_ALG_LIST TRUE -#endif /* SILC_EPOC */ +#endif /* SILC_SYMBIAN */ /* Static list of PKCS for silc_pkcs_register_default(). */ const SilcPKCSObject silc_default_pkcs[] = @@ -60,6 +64,32 @@ const SilcPKCSObject silc_default_pkcs[] = silc_pkcs_silc_verify, }, +#ifdef SILC_DIST_SSH + /* SSH2 PKCS */ + { + SILC_PKCS_SSH2, + silc_pkcs_ssh_get_algorithm, + silc_pkcs_ssh_import_public_key_file, + silc_pkcs_ssh_import_public_key, + silc_pkcs_ssh_export_public_key_file, + silc_pkcs_ssh_export_public_key, + silc_pkcs_ssh_public_key_bitlen, + silc_pkcs_ssh_public_key_copy, + silc_pkcs_ssh_public_key_compare, + silc_pkcs_ssh_public_key_free, + silc_pkcs_ssh_import_private_key_file, + silc_pkcs_ssh_import_private_key, + silc_pkcs_ssh_export_private_key_file, + silc_pkcs_ssh_export_private_key, + silc_pkcs_ssh_private_key_bitlen, + silc_pkcs_ssh_private_key_free, + silc_pkcs_ssh_encrypt, + silc_pkcs_ssh_decrypt, + silc_pkcs_ssh_sign, + silc_pkcs_ssh_verify, + }, +#endif /* SILC_DIST_SSH */ + { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL @@ -113,6 +143,74 @@ const SilcPKCSAlgorithm silc_default_pkcs_alg[] = silc_pkcs1_verify }, + /* DSS */ + { + "dsa", + "dss", + "sha1", + silc_dsa_generate_key, + silc_dsa_import_public_key, + silc_dsa_export_public_key, + silc_dsa_public_key_bitlen, + silc_dsa_public_key_copy, + silc_dsa_public_key_compare, + silc_dsa_public_key_free, + silc_dsa_import_private_key, + silc_dsa_export_private_key, + silc_dsa_private_key_bitlen, + silc_dsa_private_key_free, + silc_dsa_encrypt, + silc_dsa_decrypt, + silc_dsa_sign, + silc_dsa_verify + }, + +#ifdef SILC_DIST_SSH + /* PKCS #1, SSH2 style public keys */ + { + "rsa", + "ssh", + "sha1", + silc_pkcs1_generate_key, + silc_ssh_rsa_import_public_key, + silc_ssh_rsa_export_public_key, + silc_pkcs1_public_key_bitlen, + silc_pkcs1_public_key_copy, + silc_pkcs1_public_key_compare, + silc_pkcs1_public_key_free, + silc_pkcs1_import_private_key, + silc_pkcs1_export_private_key, + silc_pkcs1_private_key_bitlen, + silc_pkcs1_private_key_free, + silc_pkcs1_encrypt, + silc_pkcs1_decrypt, + silc_pkcs1_sign, + silc_pkcs1_verify + }, + + /* DSS, SSH2 style public keys */ + { + "dsa", + "ssh", + "sha1", + silc_dsa_generate_key, + silc_ssh_dsa_import_public_key, + silc_ssh_dsa_export_public_key, + silc_dsa_public_key_bitlen, + silc_dsa_public_key_copy, + silc_dsa_public_key_compare, + silc_dsa_public_key_free, + silc_dsa_import_private_key, + silc_dsa_export_private_key, + silc_dsa_private_key_bitlen, + silc_dsa_private_key_free, + silc_dsa_encrypt, + silc_dsa_decrypt, + silc_dsa_sign, + silc_dsa_verify + }, +#endif /* SILC_DIST_SSH */ + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -121,11 +219,11 @@ const SilcPKCSAlgorithm silc_default_pkcs_alg[] = } }; -/* Register a new PKCS into SILC. */ +/* Register a new PKCS */ SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs) { -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN SilcPKCSObject *newpkcs; SILC_LOG_DEBUG(("Registering new PKCS")); @@ -150,15 +248,15 @@ SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs) silc_pkcs_list = silc_dlist_init(); silc_dlist_add(silc_pkcs_list, newpkcs); -#endif /* SILC_EPOC */ +#endif /* SILC_SYMBIAN */ return TRUE; } -/* Unregister a PKCS from the SILC. */ +/* Unregister a PKCS */ SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs) { -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN SilcPKCSObject *entry; SILC_LOG_DEBUG(("Unregistering PKCS")); @@ -181,7 +279,7 @@ SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs) } } -#endif /* SILC_EPOC */ +#endif /* SILC_SYMBIAN */ return FALSE; } @@ -189,7 +287,7 @@ SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs) SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs) { -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN SilcPKCSAlgorithm *newalg; SILC_LOG_DEBUG(("Registering new PKCS algorithm %s", @@ -229,7 +327,7 @@ SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs) silc_pkcs_alg_list = silc_dlist_init(); silc_dlist_add(silc_pkcs_alg_list, newalg); -#endif /* SILC_EPOC */ +#endif /* SILC_SYMBIAN */ return TRUE; } @@ -237,7 +335,7 @@ SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs) SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs) { -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN SilcPKCSAlgorithm*entry; SILC_LOG_DEBUG(("Unregistering PKCS algorithm")); @@ -263,7 +361,7 @@ SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs) } } -#endif /* SILC_EPOC */ +#endif /* SILC_SYMBIAN */ return FALSE; } @@ -271,22 +369,15 @@ SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs) SilcBool silc_pkcs_register_default(void) { -#ifndef SILC_EPOC - int i; - - for (i = 0; silc_default_pkcs[i].type; i++) - silc_pkcs_register(&(silc_default_pkcs[i])); - - for (i = 0; silc_default_pkcs_alg[i].name; i++) - silc_pkcs_algorithm_register(&(silc_default_pkcs_alg[i])); - -#endif /* SILC_EPOC */ + /* We use builtin PKCS and algorithms */ return TRUE; } +/* Unregister all PKCS and algorithms */ + SilcBool silc_pkcs_unregister_all(void) { -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN SilcPKCSObject *entry; SilcPKCSAlgorithm *alg; @@ -308,7 +399,7 @@ SilcBool silc_pkcs_unregister_all(void) } } -#endif /* SILC_EPOC */ +#endif /* SILC_SYMBIAN */ return TRUE; } @@ -316,11 +407,11 @@ SilcBool silc_pkcs_unregister_all(void) char *silc_pkcs_get_supported(void) { - SilcPKCSAlgorithm *entry; + SilcPKCSAlgorithm *entry, *entry2; char *list = NULL; - int len = 0; + int i, len = 0; -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN if (silc_pkcs_alg_list) { silc_dlist_start(silc_pkcs_alg_list); while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) { @@ -335,23 +426,31 @@ char *silc_pkcs_get_supported(void) len++; } } -#else - { - int i; - for (i = 0; silc_default_pkcs_alg[i].name; i++) { - entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]); - len += strlen(entry->name); - list = silc_realloc(list, len + 1); - if (!list) - return NULL; +#endif /* SILC_SYMBIAN */ - memcpy(list + (len - strlen(entry->name)), - entry->name, strlen(entry->name)); - memcpy(list + len, ",", 1); - len++; + for (i = 0; silc_default_pkcs_alg[i].name; i++) { + entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]); + + if (silc_pkcs_alg_list) { + silc_dlist_start(silc_pkcs_alg_list); + while ((entry2 = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) { + if (!strcmp(entry2->name, entry->name)) + break; + } + if (entry2) + continue; } + + len += strlen(entry->name); + list = silc_realloc(list, len + 1); + if (!list) + return NULL; + + memcpy(list + (len - strlen(entry->name)), + entry->name, strlen(entry->name)); + memcpy(list + len, ",", 1); + len++; } -#endif /* SILC_EPOC */ list[len - 1] = 0; @@ -363,8 +462,9 @@ char *silc_pkcs_get_supported(void) const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type) { SilcPKCSObject *entry; + int i; -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN if (silc_pkcs_list) { silc_dlist_start(silc_pkcs_list); while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) { @@ -372,16 +472,13 @@ const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type) return (const SilcPKCSObject *)entry; } } -#else - { - int i; - for (i = 0; silc_default_pkcs[i].name; i++) { - entry = (SilcPKCSObject *)&(silc_default_pkcs[i]); - if (entry->type == type) - return (const SilcPKCSObject *)entry; - } +#endif /* SILC_SYMBIAN */ + + for (i = 0; silc_default_pkcs[i].type; i++) { + entry = (SilcPKCSObject *)&(silc_default_pkcs[i]); + if (entry->type == type) + return (const SilcPKCSObject *)entry; } -#endif /* SILC_EPOC */ return NULL; } @@ -392,8 +489,9 @@ const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm, const char *scheme) { SilcPKCSAlgorithm *entry; + int i; -#ifndef SILC_EPOC +#ifndef SILC_SYMBIAN if (silc_pkcs_alg_list) { silc_dlist_start(silc_pkcs_alg_list); while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) { @@ -402,47 +500,47 @@ const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm, return (const SilcPKCSAlgorithm *)entry; } } -#else - { - int i; - for (i = 0; silc_default_pkcs_alg[i].name; i++) { - entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]); - if (!strcmp(entry->name, algorithm) && - (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme))) - return (const SilcPKCSAlgorithm *)entry; - } +#endif /* SILC_SYMBIAN */ + + for (i = 0; silc_default_pkcs_alg[i].name; i++) { + entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]); + if (!strcmp(entry->name, algorithm) && + (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme))) + return (const SilcPKCSAlgorithm *)entry; } -#endif /* SILC_EPOC */ return NULL; } /* Returns PKCS context */ -const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPublicKey public_key) +const SilcPKCSObject *silc_pkcs_get_pkcs(void *key) { + SilcPublicKey public_key = key; return public_key->pkcs; } /* Returns PKCS algorithm context */ -const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(SilcPublicKey public_key) +const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(void *key) { - return public_key->pkcs->get_algorithm(public_key->public_key); + SilcPublicKey public_key = key; + return public_key->alg; } /* Return algorithm name */ -const char *silc_pkcs_get_name(SilcPublicKey public_key) +const char *silc_pkcs_get_name(void *key) { - const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(public_key); + const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(key); return pkcs->name; } /* Returns PKCS type */ -SilcPKCSType silc_pkcs_get_type(SilcPublicKey public_key) +SilcPKCSType silc_pkcs_get_type(void *key) { + SilcPublicKey public_key = key; return public_key->pkcs->type; } @@ -464,14 +562,17 @@ SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type, if (!public_key) return FALSE; - public_key->pkcs = pkcs = silc_pkcs_find_pkcs(type); + pkcs = silc_pkcs_find_pkcs(type); + public_key->pkcs = (SilcPKCSObject *)pkcs; if (!public_key->pkcs) { silc_free(public_key); return FALSE; } /* Import the PKCS public key */ - if (!pkcs->import_public_key(key, key_len, &public_key->public_key)) { + if (!pkcs->import_public_key(pkcs, NULL, key, key_len, + &public_key->public_key, + &public_key->alg)) { silc_free(public_key); return FALSE; } @@ -485,34 +586,47 @@ SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type, void silc_pkcs_public_key_free(SilcPublicKey public_key) { - public_key->pkcs->public_key_free(public_key->public_key); + public_key->pkcs->public_key_free(public_key->pkcs, public_key->public_key); + silc_free(public_key); } /* Exports public key */ -unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key, +unsigned char *silc_pkcs_public_key_encode(SilcStack stack, + SilcPublicKey public_key, SilcUInt32 *ret_len) { - return public_key->pkcs->export_public_key(public_key->public_key, - ret_len); + return public_key->pkcs->export_public_key(public_key->pkcs, stack, + public_key->public_key, ret_len); } /* Return key length */ SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key) { - return public_key->pkcs->public_key_bitlen(public_key->public_key); + return public_key->pkcs->public_key_bitlen(public_key->pkcs, + public_key->public_key); } /* Returns internal PKCS public key context */ -void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key) +void *silc_pkcs_public_key_get_pkcs(SilcPKCSType type, + SilcPublicKey public_key) { if (public_key->pkcs->type != type) - return FALSE; + return NULL; return public_key->public_key; } +/* Returns internal PKCS private key context */ + +void *silc_pkcs_private_key_get_pkcs(SilcPKCSType type, + SilcPrivateKey private_key) +{ + if (private_key->pkcs->type != type) + return NULL; + return private_key->private_key; +} /* Allocates new private key from key data */ @@ -532,14 +646,17 @@ SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type, if (!private_key) return FALSE; - private_key->pkcs = pkcs = silc_pkcs_find_pkcs(type); + pkcs = silc_pkcs_find_pkcs(type); + private_key->pkcs = (SilcPKCSObject *)pkcs; if (!private_key->pkcs) { silc_free(private_key); return FALSE; } /* Import the PKCS private key */ - if (!pkcs->import_private_key(key, key_len, &private_key->private_key)) { + if (!pkcs->import_private_key(pkcs, NULL, key, key_len, + &private_key->private_key, + &private_key->alg)) { silc_free(private_key); return FALSE; } @@ -553,59 +670,75 @@ SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type, SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key) { - return private_key->pkcs->private_key_bitlen(private_key->private_key); + return private_key->pkcs->private_key_bitlen(private_key->pkcs, + private_key->private_key); } /* Frees the private key */ void silc_pkcs_private_key_free(SilcPrivateKey private_key) { - private_key->pkcs->private_key_free(private_key->private_key); + private_key->pkcs->private_key_free(private_key->pkcs, + private_key->private_key); + silc_free(private_key); } /* Encrypts */ -SilcBool silc_pkcs_encrypt(SilcPublicKey public_key, - unsigned char *src, SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 dst_size, - SilcUInt32 *dst_len) +SilcAsyncOperation silc_pkcs_encrypt(SilcPublicKey public_key, + unsigned char *src, SilcUInt32 src_len, + SilcRng rng, + SilcPKCSEncryptCb encrypt_cb, + void *context) { - return public_key->pkcs->encrypt(public_key->public_key, src, src_len, - dst, dst_size, dst_len); + return public_key->pkcs->encrypt(public_key->pkcs, + public_key->public_key, src, src_len, + rng, encrypt_cb, context); } /* Decrypts */ -SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key, - unsigned char *src, SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 dst_size, - SilcUInt32 *dst_len) +SilcAsyncOperation silc_pkcs_decrypt(SilcPrivateKey private_key, + unsigned char *src, SilcUInt32 src_len, + SilcPKCSDecryptCb decrypt_cb, + void *context) { - return private_key->pkcs->decrypt(private_key->private_key, src, src_len, - dst, dst_size, dst_len); + return private_key->pkcs->decrypt(private_key->pkcs, + private_key->private_key, src, src_len, + decrypt_cb, context); } /* Generates signature */ -SilcBool silc_pkcs_sign(SilcPrivateKey private_key, - unsigned char *src, SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 dst_size, - SilcUInt32 *dst_len, SilcHash hash) +SilcAsyncOperation silc_pkcs_sign(SilcPrivateKey private_key, + unsigned char *src, + SilcUInt32 src_len, + SilcBool compute_hash, + SilcHash hash, + SilcRng rng, + SilcPKCSSignCb sign_cb, + void *context) { - return private_key->pkcs->sign(private_key->private_key, src, src_len, - dst, dst_size, dst_len, hash); + return private_key->pkcs->sign(private_key->pkcs, + private_key->private_key, src, src_len, + compute_hash, hash, rng, sign_cb, context); } /* Verifies signature */ -SilcBool silc_pkcs_verify(SilcPublicKey public_key, - unsigned char *signature, - SilcUInt32 signature_len, - unsigned char *data, - SilcUInt32 data_len, SilcHash hash) +SilcAsyncOperation silc_pkcs_verify(SilcPublicKey public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, + SilcHash hash, + SilcPKCSVerifyCb verify_cb, + void *context) { - return public_key->pkcs->verify(public_key->public_key, signature, - signature_len, data, data_len, hash); + return public_key->pkcs->verify(public_key->pkcs, + public_key->public_key, signature, + signature_len, data, data_len, hash, NULL, + verify_cb, context); } /* Compares two public keys and returns TRUE if they are same key, and @@ -616,7 +749,8 @@ SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2) if (key1->pkcs->type != key2->pkcs->type) return FALSE; - return key1->pkcs->public_key_compare(key1->public_key, key2->public_key); + return key1->pkcs->public_key_compare(key1->pkcs, + key1->public_key, key2->public_key); } /* Copies the public key indicated by `public_key' and returns new allocated @@ -629,7 +763,8 @@ SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key) return NULL; key->pkcs = public_key->pkcs; - key->public_key = public_key->pkcs->public_key_copy(public_key->public_key); + key->public_key = public_key->pkcs->public_key_copy(public_key->pkcs, + public_key->public_key); if (!key->public_key) { silc_free(key); return NULL; @@ -641,21 +776,23 @@ SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key) /* Loads any kind of public key */ SilcBool silc_pkcs_load_public_key(const char *filename, + SilcPKCSType type, SilcPublicKey *ret_public_key) { unsigned char *data; SilcUInt32 data_len; SilcPublicKey public_key; - SilcPKCSType type; SILC_LOG_DEBUG(("Loading public key file '%s'", filename)); if (!ret_public_key) return FALSE; - data = silc_file_readfile(filename, &data_len); - if (!data) + data = silc_file_readfile(filename, &data_len, NULL); + if (!data) { + SILC_LOG_ERROR(("No such file: %s", filename)); return FALSE; + } /* Allocate public key context */ *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key)); @@ -664,25 +801,65 @@ SilcBool silc_pkcs_load_public_key(const char *filename, return FALSE; } - /* Try loading all types until one succeeds. */ - for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) { - public_key->pkcs = silc_pkcs_find_pkcs(type); - if (!public_key->pkcs) - continue; + if (type == SILC_PKCS_ANY) { + /* Try loading all types until one succeeds. */ + for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) { + public_key->pkcs = (SilcPKCSObject *)silc_pkcs_find_pkcs(type); + if (!public_key->pkcs) + continue; - if (public_key->pkcs->import_public_key_file(data, data_len, + if (public_key->pkcs->import_public_key_file(public_key->pkcs, + data, data_len, + SILC_PKCS_FILE_BASE64, + &public_key->public_key, + &public_key->alg)) { + silc_free(data); + return TRUE; + } + + if (public_key->pkcs->import_public_key_file(public_key->pkcs, + data, data_len, + SILC_PKCS_FILE_BIN, + &public_key->public_key, + &public_key->alg)) { + silc_free(data); + return TRUE; + } + } + } else { + /* Load specific type */ + public_key->pkcs = (SilcPKCSObject *)silc_pkcs_find_pkcs(type); + if (!public_key->pkcs) { + silc_free(data); + silc_free(public_key); + *ret_public_key = NULL; + SILC_LOG_ERROR(("Unsupported public key type")); + return FALSE; + } + + if (public_key->pkcs->import_public_key_file(public_key->pkcs, + data, data_len, SILC_PKCS_FILE_BASE64, - &public_key->public_key)) + &public_key->public_key, + &public_key->alg)) { + silc_free(data); return TRUE; + } - if (public_key->pkcs->import_public_key_file(data, data_len, + if (public_key->pkcs->import_public_key_file(public_key->pkcs, + data, data_len, SILC_PKCS_FILE_BIN, - &public_key->public_key)) + &public_key->public_key, + &public_key->alg)) { + silc_free(data); return TRUE; + } } silc_free(data); silc_free(public_key); + *ret_public_key = NULL; + SILC_LOG_ERROR(("Unsupported public key type")); return FALSE; } @@ -694,20 +871,29 @@ SilcBool silc_pkcs_save_public_key(const char *filename, { unsigned char *data; SilcUInt32 data_len; + SilcStack stack; + + stack = silc_stack_alloc(2048, silc_crypto_stack()); /* Export the public key file */ - data = public_key->pkcs->export_public_key_file(public_key->public_key, + data = public_key->pkcs->export_public_key_file(public_key->pkcs, + stack, + public_key->public_key, encoding, &data_len); - if (!data) + if (!data) { + silc_stack_free(stack); return FALSE; + } /* Write to file */ if (silc_file_writefile(filename, data, data_len)) { - silc_free(data); + silc_sfree(stack, data); + silc_stack_free(stack); return FALSE; } - silc_free(data); + silc_sfree(stack, data); + silc_stack_free(stack); return TRUE; } @@ -716,21 +902,23 @@ SilcBool silc_pkcs_save_public_key(const char *filename, SilcBool silc_pkcs_load_private_key(const char *filename, const unsigned char *passphrase, SilcUInt32 passphrase_len, + SilcPKCSType type, SilcPrivateKey *ret_private_key) { unsigned char *data; SilcUInt32 data_len; SilcPrivateKey private_key; - SilcPKCSType type; SILC_LOG_DEBUG(("Loading private key file '%s'", filename)); if (!ret_private_key) return FALSE; - data = silc_file_readfile(filename, &data_len); - if (!data) + data = silc_file_readfile(filename, &data_len, NULL); + if (!data) { + SILC_LOG_ERROR(("No such file: %s", filename)); return FALSE; + } /* Allocate private key context */ *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key)); @@ -739,29 +927,76 @@ SilcBool silc_pkcs_load_private_key(const char *filename, return FALSE; } - /* Try loading all types until one succeeds. */ - for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) { - private_key->pkcs = silc_pkcs_find_pkcs(type); - if (!private_key->pkcs) - continue; + if (type == SILC_PKCS_ANY) { + /* Try loading all types until one succeeds. */ + for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) { + private_key->pkcs = (SilcPKCSObject *)silc_pkcs_find_pkcs(type); + if (!private_key->pkcs) + continue; + + if (private_key->pkcs->import_private_key_file( + private_key->pkcs, + data, data_len, + passphrase, + passphrase_len, + SILC_PKCS_FILE_BIN, + &private_key->private_key, + &private_key->alg)) { + silc_free(data); + return TRUE; + } - if (private_key->pkcs->import_private_key_file(data, data_len, - passphrase, - passphrase_len, - SILC_PKCS_FILE_BIN, - &private_key->private_key)) + if (private_key->pkcs->import_private_key_file( + private_key->pkcs, + data, data_len, + passphrase, + passphrase_len, + SILC_PKCS_FILE_BASE64, + &private_key->private_key, + &private_key->alg)) { + silc_free(data); + return TRUE; + } + } + } else { + /* Load specific type */ + private_key->pkcs = (SilcPKCSObject *)silc_pkcs_find_pkcs(type); + if (!private_key->pkcs) { + silc_free(data); + silc_free(private_key); + *ret_private_key = NULL; + SILC_LOG_ERROR(("Unsupported private key type")); + return FALSE; + } + + if (private_key->pkcs->import_private_key_file( + private_key->pkcs, + data, data_len, + passphrase, + passphrase_len, + SILC_PKCS_FILE_BIN, + &private_key->private_key, + &private_key->alg)) { + silc_free(data); return TRUE; + } - if (private_key->pkcs->import_private_key_file(data, data_len, - passphrase, - passphrase_len, - SILC_PKCS_FILE_BASE64, - &private_key->private_key)) + if (private_key->pkcs->import_private_key_file( + private_key->pkcs, + data, data_len, + passphrase, + passphrase_len, + SILC_PKCS_FILE_BASE64, + &private_key->private_key, + &private_key->alg)) { + silc_free(data); return TRUE; + } } silc_free(data); silc_free(private_key); + *ret_private_key = NULL; return FALSE; } @@ -776,21 +1011,65 @@ SilcBool silc_pkcs_save_private_key(const char *filename, { unsigned char *data; SilcUInt32 data_len; + SilcStack stack; + + stack = silc_stack_alloc(2048, silc_crypto_stack()); /* Export the private key file */ - data = private_key->pkcs->export_private_key_file(private_key->private_key, + data = private_key->pkcs->export_private_key_file(private_key->pkcs, stack, + private_key->private_key, passphrase, passphrase_len, encoding, rng, &data_len); - if (!data) + if (!data) { + silc_stack_free(stack); return FALSE; + } /* Write to file */ if (silc_file_writefile(filename, data, data_len)) { - silc_free(data); + silc_sfree(stack, data); + silc_stack_free(stack); return FALSE; } - silc_free(data); + silc_sfree(stack, data); + silc_stack_free(stack); return TRUE; } + +/* Hash public key of any type. */ + +SilcUInt32 silc_hash_public_key(void *key, void *user_context) +{ + SilcPublicKey public_key = key; + unsigned char *pk; + SilcUInt32 pk_len; + SilcUInt32 hash = 0; + SilcStack stack = NULL; + + if (silc_crypto_stack()) + stack = silc_stack_alloc(2048, silc_crypto_stack()); + + pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len); + if (!pk) { + silc_stack_free(stack); + return hash; + } + + hash = silc_hash_data(pk, SILC_32_TO_PTR(pk_len)); + + silc_sfree(stack, pk); + silc_stack_free(stack); + + return hash; +} + +/* Compares two SILC Public keys. It may be used as SilcHashTable + comparison function. */ + +SilcBool silc_hash_public_key_compare(void *key1, void *key2, + void *user_context) +{ + return silc_pkcs_public_key_compare(key1, key2); +}