From 410642a14d4185abd75715cee3f5177cd55b1ceb Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 1 Jan 2006 10:04:25 +0000 Subject: [PATCH] New SILC PKCS API, enabling support for other public keys/certs. Separated SILC Public Key Payload routines into lib/silccore. --- CHANGES | 8 + TODO | 2 +- includes/silc.h.in | 2 + lib/silcasn1/silcasn1.c | 4 - lib/silcasn1/silcasn1.h | 26 +- lib/silcasn1/silcasn1_decode.c | 5 +- lib/silcasn1/silcasn1_encode.c | 10 +- lib/silcasn1/silcber.c | 2 +- lib/silcasn1/tests/test_silcasn1.c | 40 + lib/silccore/Makefile.ad | 28 +- lib/silccore/silcauth.c | 32 +- lib/silccore/silcmessage.c | 54 +- lib/silccore/silcmessage.h | 32 +- lib/silccore/silcpacket.h | 6 +- lib/silccrypt/Makefile.ad | 36 +- lib/silccrypt/rsa.c | 822 +---------- lib/silccrypt/rsa.h | 53 +- lib/silccrypt/rsa_internal.h | 46 - lib/silccrypt/silchash.h | 10 +- lib/silccrypt/silcpk.c | 1601 +++++++++++++++++++++ lib/silccrypt/silcpk.h | 167 +++ lib/silccrypt/silcpk_i.h | 93 ++ lib/silccrypt/silcpkcs.c | 1668 ++++++---------------- lib/silccrypt/silcpkcs.h | 1003 ++++++------- lib/silccrypt/silcpkcs1.c | 563 +++++++- lib/silccrypt/silcpkcs1.h | 22 +- lib/silccrypt/silcpkcs1_i.h | 82 ++ lib/silcmath/mpbin.c | 2 + lib/silcmath/silcmath.h | 24 +- lib/silcmath/silcmp.h | 2 +- lib/silcserver/server.c | 7 - lib/silcserver/server_internal.h | 1 - lib/silcserver/server_st_accept.c | 3 +- lib/silcserver/server_st_command.c | 2 +- lib/silcserver/server_st_command_reply.c | 2 +- lib/silcserver/server_st_packet.c | 8 - lib/silcserver/tests/test_silcserver.c | 5 +- lib/silcske/silcske.c | 101 +- lib/silcske/silcske.h | 9 +- lib/silcskr/silcskr.c | 91 +- lib/silcskr/silcskr.h | 47 +- lib/silcutil/silcapputil.c | 175 +-- lib/silcutil/silcapputil.h | 78 +- lib/silcutil/silcutil.c | 25 +- lib/silcutil/silcutil.h | 2 +- 45 files changed, 3838 insertions(+), 3163 deletions(-) delete mode 100644 lib/silccrypt/rsa_internal.h create mode 100644 lib/silccrypt/silcpk.c create mode 100644 lib/silccrypt/silcpk.h create mode 100644 lib/silccrypt/silcpk_i.h create mode 100644 lib/silccrypt/silcpkcs1_i.h diff --git a/CHANGES b/CHANGES index 3fc948fd..432bd167 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +Sat Dec 30 22:54:21 EET 2005 Pekka Riikonen + + * New SILC PKCS API enabling support for other public keys + and certificates, lib/silccrypt/silcpkcs.[ch], silcpk.[ch]. + + * Separated SILC Public Key Payload routines from the PKCS API + to lib/silccore/silcpubkey.[ch]. + Wed Dec 28 13:55:22 EET 2005 Pekka Riikonen * Added SILC Key Repository library, lib/silcskr. diff --git a/TODO b/TODO index 6e39a0ab..3f5aa5cf 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,7 @@ TODO for 1.1 And Beyond ======================= -lib/silccrypt +lib/silccrypt ****PARTLY DONE**** ============= o Implement the defined SilcDH API. The definition is in diff --git a/includes/silc.h.in b/includes/silc.h.in index b85fd024..20be3339 100644 --- a/includes/silc.h.in +++ b/includes/silc.h.in @@ -252,6 +252,7 @@ extern "C" { #include "silchmac.h" #include "silcrng.h" #include "silcpkcs.h" +#include "silcpk.h" #include "silcpkcs1.h" /* More SILC util library includes */ @@ -297,6 +298,7 @@ extern "C" { #include "silcmode.h" #include "silcauth.h" #include "silcattrs.h" +#include "silcpubkey.h" #ifdef SILC_DIST_SKR #include "silcskr.h" diff --git a/lib/silcasn1/silcasn1.c b/lib/silcasn1/silcasn1.c index ccf77c2b..007f1990 100644 --- a/lib/silcasn1/silcasn1.c +++ b/lib/silcasn1/silcasn1.c @@ -66,10 +66,6 @@ SilcBool silc_asn1_init(SilcAsn1 asn1) void silc_asn1_uninit(SilcAsn1 asn1) { -#if 1 - silc_stack_stats(asn1->stack1); - silc_stack_stats(asn1->stack2); -#endif silc_stack_free(asn1->stack1); silc_stack_free(asn1->stack2); } diff --git a/lib/silcasn1/silcasn1.h b/lib/silcasn1/silcasn1.h index 57c31905..26c03f38 100644 --- a/lib/silcasn1/silcasn1.h +++ b/lib/silcasn1/silcasn1.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2003 - 2005 Pekka Riikonen + Copyright (C) 2003 - 2006 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 @@ -35,7 +35,7 @@ * pre-allocated SilcStack is used as memory. * * The encoding and decoding interface is simple. silc_asn1_encode is used - * encode and silc_asn1_decode to decode. The actual ASN.1 is defined + * to encode and silc_asn1_decode to decode. The actual ASN.1 is defined * as variable argument list to the function. Various macros can be used * to encode and decode different ASN.1 types. All types may also be used * to encode and decode with various options (such as implicit and explicit @@ -102,6 +102,16 @@ typedef struct SilcAsn1Object SilcAsn1Struct; * with SILC_ASN1_OPTS macro. Other options can be given with various * SILC_ASN1_*_T macros. * + * EXAMPLE + * + * // Encodes boolean value with explicit tag and private class, and + * // the result is allocated into `dest'. + * silc_asn1_encode(asn1, &dest, + * SILC_ASN1_OPTS(SILC_ASN1_ALLOC), + * SILC_ASN1_BOOLEAN_T(SILC_ASN1_PRIVATE | + * SILC_ASN1_EXPLICIT, 100, boolval), + * SILC_ASN1_END); + * * SOURCE */ typedef enum { @@ -413,7 +423,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...); * * Decoding: * SILC_ASN1_ANY(&buffer) - * SILC_ASN1_ANY_T(opts, tag, &buffer) + * SILC_ASN1_ANY_T(opts, tag, buffer) * * DESCRIPTION * @@ -453,7 +463,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...); * * Decoding: * SILC_ASN1_ANY_PRIMITIVE(tag, &buffer) - * SILC_ASN1_ANY_PRIMITIVE_T(opts, tag, &buffer) + * SILC_ASN1_ANY_PRIMITIVE_T(opts, tag, buffer) * * DESCRIPTION * @@ -671,7 +681,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...); * * Encoding: * SILC_ASN1_INT(integer) - * SILC_ASN1_INT_T(opts, tag, integer) + * SILC_ASN1_INT_T(opts, tag, &integer) * * Decoding: * SILC_ASN1_INT(&integer) @@ -694,7 +704,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...); * * Encoding: * SILC_ASN1_ENUM(enum) - * SILC_ASN1_ENUM_T(opts, tag, enum) + * SILC_ASN1_ENUM_T(opts, tag, &enum) * * Decoding: * SILC_ASN1_ENUM(&enum) @@ -1110,7 +1120,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...); * * Decoding: * SILC_ASN1_UTC_TIME(&str, &timeval) - * SILC_ASN1_UTC_TIME_T(opts, tag, &timeval) + * SILC_ASN1_UTC_TIME_T(opts, tag, timeval) * * DESCRIPTION * @@ -1133,7 +1143,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...); * * Decoding: * SILC_ASN1_GEN_TIME(&str, &timeval) - * SILC_ASN1_GEN_TIME_T(opts, tag, &timeval) + * SILC_ASN1_GEN_TIME_T(opts, tag, timeval) * * DESCRIPTION * diff --git a/lib/silcasn1/silcasn1_decode.c b/lib/silcasn1/silcasn1_decode.c index 34b93ca2..8fdfef24 100644 --- a/lib/silcasn1/silcasn1_decode.c +++ b/lib/silcasn1/silcasn1_decode.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2003 - 2005 Pekka Riikonen + Copyright (C) 2003 - 2006 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,7 +21,6 @@ #include "silcasn1.h" #include "silcber.h" - /************************** ASN.1 Decoder routines **************************/ /* Internal SEQUENCE OF and SET OF decoder. This is used only when decoding @@ -472,7 +471,7 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, /* 2s complement and change sign */ silc_mp_init(&z); - silc_mp_set(&z, 0); + silc_mp_set_ui(&z, 0); silc_mp_add_ui(*intval, *intval, 1); silc_mp_sub(*intval, &z, *intval); silc_mp_uninit(&z); diff --git a/lib/silcasn1/silcasn1_encode.c b/lib/silcasn1/silcasn1_encode.c index 123539f6..d8706b73 100644 --- a/lib/silcasn1/silcasn1_encode.c +++ b/lib/silcasn1/silcasn1_encode.c @@ -199,6 +199,8 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, len = silc_buffer_len(node); dest = silc_buffer_srealloc_size(stack1, dest, silc_buffer_truelen(dest) + len); + if (!dest) + goto fail; silc_buffer_put(dest, node->data, len); } break; @@ -266,11 +268,15 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, bytes in 1s complement */ } else { /* Positive */ - len = (silc_mp_sizeinbase(mpint, 2) + 7) / 8; - len += len & 7 ? 1: 0; + len = silc_mp_sizeinbase(mpint, 2); + if (!(len & 7)) + len = ((len + 7) / 8) + 1; + else + len = (len + 7) / 8; silc_stack_push(stack2, &frame); silc_buffer_srealloc_size(stack2, &buf, silc_buffer_truelen(&buf) + len); + buf.data[0] = 0x00; silc_mp_mp2bin_noalloc(mpint, buf.data, silc_buffer_len(&buf)); } diff --git a/lib/silcasn1/silcber.c b/lib/silcasn1/silcber.c index 9d83d8b5..e6f2de30 100644 --- a/lib/silcasn1/silcber.c +++ b/lib/silcasn1/silcber.c @@ -75,7 +75,7 @@ SilcBool silc_ber_encode(SilcBuffer ber, SilcBerClass ber_class, /* Long form */ /* Calculate the number of octets for the length field */ - tmp = tag; + tmp = data_len; c = 0; while (tmp) { c++; diff --git a/lib/silcasn1/tests/test_silcasn1.c b/lib/silcasn1/tests/test_silcasn1.c index 3e2bd3ce..fad097b5 100644 --- a/lib/silcasn1/tests/test_silcasn1.c +++ b/lib/silcasn1/tests/test_silcasn1.c @@ -53,6 +53,8 @@ int main(int argc, char **argv) unsigned char *str; SilcUInt32 str_len; char tmp[32]; + SilcRng rng; + SilcMPInt mpint, mpint2; memset(&node, 0, sizeof(node)); memset(&node2, 0, sizeof(node2)); @@ -63,6 +65,10 @@ int main(int argc, char **argv) silc_log_set_debug_string("*asn1*,*ber*"); } + silc_hash_register_default(); + rng = silc_rng_alloc(); + silc_rng_init(rng); + SILC_LOG_DEBUG(("Allocating ASN.1 context")); asn1 = silc_asn1_alloc(); if (!asn1) @@ -583,6 +589,7 @@ int main(int argc, char **argv) memset(&node, 0, sizeof(node)); printf("\n"); + memset(&node, 0, sizeof(node)); SILC_LOG_DEBUG(("Encoding ASN.1 tree 9")); success = @@ -641,6 +648,39 @@ int main(int argc, char **argv) SILC_LOG_DEBUG(("Ooctet-string %s, len %d", str, str_len)); printf("\n"); + + memset(&node, 0, sizeof(node)); + SILC_LOG_DEBUG(("Encoding ASN.1 tree 10 (INTEGER)")); + str = silc_rng_get_rn_data(rng, 256); + silc_mp_init(&mpint); + silc_mp_init(&mpint2); + silc_mp_bin2mp(str, 256, &mpint); + success = + silc_asn1_encode(asn1, &node, + SILC_ASN1_INT(&mpint), + SILC_ASN1_END); + if (!success) { + SILC_LOG_DEBUG(("Encoding failed")); + goto out; + } + SILC_LOG_DEBUG(("Encoding success")); + SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node)); + SILC_LOG_DEBUG(("Decoding ASN.1 tree 9")); + success = + silc_asn1_decode(asn1, &node, + SILC_ASN1_INT(&mpint2), + SILC_ASN1_END); + if (silc_mp_cmp(&mpint, &mpint2) != 0) { + SILC_LOG_DEBUG(("INTEGER MISMATCH")); + goto out; + } + if (!success) { + SILC_LOG_DEBUG(("Decoding failed")); + goto out; + } + SILC_LOG_DEBUG(("Decoding success")); + printf("\n"); + #endif silc_asn1_free(asn1); diff --git a/lib/silccore/Makefile.ad b/lib/silccore/Makefile.ad index b5d6d71b..7d9507e6 100644 --- a/lib/silccore/Makefile.ad +++ b/lib/silccore/Makefile.ad @@ -19,18 +19,19 @@ AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign noinst_LTLIBRARIES = libsilccore.la -libsilccore_la_SOURCES = \ - silcid.c \ - silcidcache.c \ - silcmessage.c \ - silcchannel.c \ - silccommand.c \ - silcpacket.c \ - silcargument.c \ - silcnotify.c \ - silcauth.c \ - silcattrs.c \ - silcstatus.c +libsilccore_la_SOURCES = \ + silcid.c \ + silcidcache.c \ + silcmessage.c \ + silcchannel.c \ + silccommand.c \ + silcpacket.c \ + silcargument.c \ + silcnotify.c \ + silcauth.c \ + silcattrs.c \ + silcstatus.c \ + silcpubkey.c #ifdef SILC_DIST_TOOLKIT include_HEADERS = \ @@ -45,7 +46,8 @@ include_HEADERS = \ silcpacket.h \ silcargument.h \ silcstatus.h \ - silcattrs.h + silcattrs.h \ + silcpubkey.h SILC_EXTRA_DIST = tests #endif SILC_DIST_TOOLKIT diff --git a/lib/silccore/silcauth.c b/lib/silccore/silcauth.c index b98f36e8..22ba281a 100644 --- a/lib/silccore/silcauth.c +++ b/lib/silccore/silcauth.c @@ -279,7 +279,6 @@ silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key, unsigned char *tmp; SilcUInt32 tmp_len; SilcBuffer buf; - SilcPKCS pkcs; SILC_LOG_DEBUG(("Generating Authentication Payload with data")); @@ -289,22 +288,11 @@ silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key, if (!tmp) return NULL; - /* Allocate PKCS object */ - if (!silc_pkcs_alloc(private_key->name, SILC_PKCS_SILC, &pkcs)) { - memset(tmp, 0, tmp_len); - silc_free(tmp); - return NULL; - } - silc_pkcs_public_key_set(pkcs, public_key); - silc_pkcs_private_key_set(pkcs, private_key); - /* Compute the hash and the signature. */ - if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 || - !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data, - &auth_len)) { + if (!silc_pkcs_sign(private_key, tmp, tmp_len, auth_data, + sizeof(auth_data) - 1, &auth_len, hash)) { memset(tmp, 0, tmp_len); silc_free(tmp); - silc_pkcs_free(pkcs); return NULL; } @@ -315,7 +303,6 @@ silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key, memset(tmp, 0, tmp_len); memset(auth_data, 0, sizeof(auth_data)); silc_free(tmp); - silc_pkcs_free(pkcs); return buf; } @@ -330,7 +317,6 @@ SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload, { unsigned char *tmp; SilcUInt32 tmp_len; - SilcPKCS pkcs; SILC_LOG_DEBUG(("Verifying authentication data")); @@ -343,28 +329,18 @@ SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload, return FALSE; } - /* Allocate PKCS object */ - if (!silc_pkcs_alloc(public_key->name, SILC_PKCS_SILC, &pkcs)) { - memset(tmp, 0, tmp_len); - silc_free(tmp); - return FALSE; - } - silc_pkcs_public_key_set(pkcs, public_key); - /* Verify the authentication data */ - if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data, - payload->auth_len, tmp, tmp_len)) { + if (!silc_pkcs_verify(public_key, payload->auth_data, + payload->auth_len, tmp, tmp_len, hash)) { memset(tmp, 0, tmp_len); silc_free(tmp); - silc_pkcs_free(pkcs); SILC_LOG_DEBUG(("Authentication failed")); return FALSE; } memset(tmp, 0, tmp_len); silc_free(tmp); - silc_pkcs_free(pkcs); SILC_LOG_DEBUG(("Authentication successful")); diff --git a/lib/silccore/silcmessage.c b/lib/silccore/silcmessage.c index cf4ee1bf..990050c6 100644 --- a/lib/silccore/silcmessage.c +++ b/lib/silccore/silcmessage.c @@ -543,7 +543,6 @@ silc_message_signed_payload_encode(const unsigned char *message_payload, SilcHash hash) { SilcBuffer buffer, sign; - SilcPKCS pkcs; unsigned char auth_data[2048 + 1]; SilcUInt32 auth_len; unsigned char *pk = NULL; @@ -553,11 +552,12 @@ silc_message_signed_payload_encode(const unsigned char *message_payload, if (!message_payload || !message_payload_len || !private_key || !hash) return NULL; - if (public_key) + if (public_key) { pk = silc_pkcs_public_key_encode(public_key, &pk_len); - - /* Now we support only SILC style public key */ - pk_type = SILC_SKE_PK_TYPE_SILC; + if (!pk) + return NULL; + } + pk_type = silc_pkcs_get_type(public_key); /* Encode the data to be signed */ sign = silc_message_signed_encode_data(message_payload, @@ -570,24 +570,12 @@ silc_message_signed_payload_encode(const unsigned char *message_payload, /* Sign the buffer */ - /* Allocate PKCS object */ - if (!silc_pkcs_alloc(private_key->name, SILC_PKCS_SILC, &pkcs)) { - SILC_LOG_ERROR(("Could not allocated PKCS")); - silc_buffer_clear(sign); - silc_buffer_free(sign); - silc_free(pk); - return NULL; - } - silc_pkcs_private_key_set(pkcs, private_key); - /* Compute the hash and the signature. */ - if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 || - !silc_pkcs_sign_with_hash(pkcs, hash, sign->data, silc_buffer_len(sign), auth_data, - &auth_len)) { + if (!silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign), + auth_data, sizeof(auth_data) - 1, &auth_len, hash)) { SILC_LOG_ERROR(("Could not compute signature")); silc_buffer_clear(sign); silc_buffer_free(sign); - silc_pkcs_free(pkcs); silc_free(pk); return NULL; } @@ -598,7 +586,6 @@ silc_message_signed_payload_encode(const unsigned char *message_payload, if (!buffer) { silc_buffer_clear(sign); silc_buffer_free(sign); - silc_pkcs_free(pkcs); memset(auth_data, 0, sizeof(auth_data)); silc_free(pk); return NULL; @@ -627,7 +614,6 @@ silc_message_signed_payload_encode(const unsigned char *message_payload, SILC_LOG_HEXDUMP(("sig payload"), buffer->data, silc_buffer_len(buffer)); memset(auth_data, 0, sizeof(auth_data)); - silc_pkcs_free(pkcs); silc_buffer_clear(sign); silc_buffer_free(sign); silc_free(pk); @@ -654,7 +640,6 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig, { int ret = SILC_AUTH_FAILED; SilcBuffer sign; - SilcPKCS pkcs; SilcBuffer tmp; if (!sig || !remote_public_key || !hash) @@ -678,22 +663,13 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig, if (!sign) return ret; - /* Allocate PKCS object */ - if (!silc_pkcs_alloc(remote_public_key->name, SILC_PKCS_SILC, &pkcs)) { - silc_buffer_clear(sign); - silc_buffer_free(sign); - return ret; - } - silc_pkcs_public_key_set(pkcs, remote_public_key); - /* Verify the authentication data */ - if (!silc_pkcs_verify_with_hash(pkcs, hash, sig->sign_data, - sig->sign_len, - sign->data, silc_buffer_len(sign))) { + if (!silc_pkcs_verify(remote_public_key, sig->sign_data, + sig->sign_len, + sign->data, silc_buffer_len(sign), hash)) { silc_buffer_clear(sign); silc_buffer_free(sign); - silc_pkcs_free(pkcs); SILC_LOG_DEBUG(("Signature verification failed")); return ret; } @@ -702,7 +678,6 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig, silc_buffer_clear(sign); silc_buffer_free(sign); - silc_pkcs_free(pkcs); SILC_LOG_DEBUG(("Signature verification successful")); @@ -713,13 +688,16 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig, SilcPublicKey silc_message_signed_get_public_key(SilcMessageSignedPayload sig, - unsigned char **pk_data, + const unsigned char **pk_data, SilcUInt32 *pk_data_len) { SilcPublicKey pk; - if (!sig->pk_data || !silc_pkcs_public_key_decode(sig->pk_data, - sig->pk_len, &pk)) + if (!sig->pk_data) + return NULL; + + if (!silc_pkcs_public_key_alloc(sig->pk_type, sig->pk_data, + sig->pk_len, &pk)) return NULL; if (pk_data) diff --git a/lib/silccore/silcmessage.h b/lib/silccore/silcmessage.h index 7dc136ef..356a2ad8 100644 --- a/lib/silccore/silcmessage.h +++ b/lib/silccore/silcmessage.h @@ -1,10 +1,10 @@ /* - silcmessage.h + silcmessage.h Author: Pekka Riikonen - Copyright (C) 1997 - 2002 Pekka Riikonen + Copyright (C) 1997 - 2005 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 @@ -26,7 +26,7 @@ * * This interface defines also the SILC_MESSAGE_FLAG_SIGNED Payload, * which defines how channel messages and private messages can be digitally - * signed. This interface provides the payload parsing, encoding, + * signed. This interface provides the payload parsing, encoding, * signature computing and signature verification routines. * ***/ @@ -37,7 +37,7 @@ /****s* silccore/SilcMessageAPI/SilcMessagePayload * * NAME - * + * * typedef struct SilcMessagePayloadStruct *SilcMessagePayload; * * @@ -54,7 +54,7 @@ typedef struct SilcMessagePayloadStruct *SilcMessagePayload; /****s* silccore/SilcMessageAPI/SilcMessageSignedPayload * * NAME - * + * * typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload; * * @@ -73,12 +73,12 @@ typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload; /****d* silccore/SilcMessageAPI/SilcMessageFlags * * NAME - * + * * typedef SilcUInt16 SilcMessageFlags; * * DESCRIPTION * - * The message flags type definition and the message flags. The + * The message flags type definition and the message flags. The * message flags are used to indicate some status of the message. * * SOURCE @@ -125,7 +125,7 @@ typedef SilcUInt16 SilcMessageFlags; * * This is usually used by the Message Payload interface itself but can * be called by the appliation if separate decryption process is required. - * For example server might need to call this directly in some + * For example server might need to call this directly in some * circumstances. The `cipher' is used to decrypt the payload. If * `check_mac' is FALSE then MAC is not verified. * @@ -142,7 +142,7 @@ SilcBool silc_message_payload_decrypt(unsigned char *data, * * SYNOPSIS * - * SilcMessagePayload + * SilcMessagePayload * silc_message_payload_parse(unsigned char *payload, * SilcUInt32 payload_len, * SilcBool private_message, @@ -167,7 +167,7 @@ SilcBool silc_message_payload_decrypt(unsigned char *data, * (no private message key) and this merely decodes the payload. * ***/ -SilcMessagePayload +SilcMessagePayload silc_message_payload_parse(unsigned char *payload, SilcUInt32 payload_len, SilcBool private_message, @@ -196,7 +196,7 @@ silc_message_payload_parse(unsigned char *payload, * * This is usually used by the Message Payload interface itself but can * be called by the appliation if separate encryption process is required. - * For example server might need to call this directly in some + * For example server might need to call this directly in some * circumstances. The `cipher' is used to encrypt the payload and `hmac' * to compute the MAC for the payload. * @@ -318,7 +318,7 @@ unsigned char *silc_message_get_data(SilcMessagePayload payload, * * DESCRIPTION * - * Return the MAC of the payload. The caller must already know the + * Return the MAC of the payload. The caller must already know the * length of the MAC. The caller must not free the MAC. * ***/ @@ -333,7 +333,7 @@ unsigned char *silc_message_get_mac(SilcMessagePayload payload); * * DESCRIPTION * - * Return the IV of the payload. The caller must already know the + * Return the IV of the payload. The caller must already know the * length of the IV. The caller must not free the IV. * ***/ @@ -405,7 +405,7 @@ silc_message_signed_payload_parse(const unsigned char *data, * is used to produce the signature. This function returns the encoded * payload with the signature or NULL on error. Caller must free the * returned buffer. The `hash' SHOULD be SHA-1 hash function. - * + * * Application usually does not need to call this since the function * silc_message_payload_encode calls this automatically if the caller * wants to sign the message. @@ -458,7 +458,7 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig, * * SilcPublicKey * silc_message_signed_get_public_key(SilcMessageSignedPayload sig, - * unsigned char **pk_data, + * const unsigned char **pk_data, * SilcUInt32 *pk_data_len); * * DESCRIPTION @@ -472,7 +472,7 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig, ***/ SilcPublicKey silc_message_signed_get_public_key(SilcMessageSignedPayload sig, - unsigned char **pk_data, + const unsigned char **pk_data, SilcUInt32 *pk_data_len); #endif /* SILCMESSAGE_H */ diff --git a/lib/silccore/silcpacket.h b/lib/silccore/silcpacket.h index eb3c97d7..f7c6853c 100644 --- a/lib/silccore/silcpacket.h +++ b/lib/silccore/silcpacket.h @@ -22,9 +22,9 @@ * DESCRIPTION * * The SILC secure binary packet protocol interface, provides interface for - * sending and receiving SILC packets. The interface provides a packet engine, - * that can be used to receive packets from packet streams, and routines - * for sending all kinds of SILC packets. + * sending and receiving SILC packets. The interface provides a packet + * engine, that can be used to receive packets from packet streams, and + * routines for sending all kinds of SILC packets. * * The packet engine and packet stream are thread safe. They can be safely * used in multi threaded environment. diff --git a/lib/silccrypt/Makefile.ad b/lib/silccrypt/Makefile.ad index 98c64393..01edf7c3 100644 --- a/lib/silccrypt/Makefile.ad +++ b/lib/silccrypt/Makefile.ad @@ -20,22 +20,23 @@ AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign noinst_LTLIBRARIES = libsilccrypt.la libsilccrypt_la_SOURCES = \ - none.c \ - rc5.c \ - md5.c \ - aes.c \ - rsa.c \ - sha1.c \ - sha256.c \ - twofish.c \ - blowfish.c \ - cast.c \ - silccipher.c \ - silchash.c \ - silchmac.c \ - silcrng.c \ - silcpkcs.c \ - silcpkcs1.c + none.c \ + rc5.c \ + md5.c \ + aes.c \ + rsa.c \ + sha1.c \ + sha256.c \ + twofish.c \ + blowfish.c \ + cast.c \ + silccipher.c \ + silchash.c \ + silchmac.c \ + silcrng.c \ + silcpkcs.c \ + silcpkcs1.c \ + silcpk.c if SILC_LIBTOOLFIX # Tell libtool to compile silccrypt as shared since silcsim will need it. @@ -68,7 +69,8 @@ include_HEADERS = \ silcpkcs.h \ silcrng.h \ silcpkcs1.h \ - twofish.h + twofish.h \ + silcpk.h SILC_EXTRA_DIST = tests #endif SILC_DIST_TOOLKIT diff --git a/lib/silccrypt/rsa.c b/lib/silccrypt/rsa.c index 18399a5a..b09693a5 100644 --- a/lib/silccrypt/rsa.c +++ b/lib/silccrypt/rsa.c @@ -5,7 +5,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2005 Pekka Riikonen + Copyright (C) 1997 - 2006 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 @@ -73,715 +73,43 @@ Fixed double free in public key setting. Use a bit larger e as starting point in key generation. + o Fri Dec 30 13:39:51 EET 2005 Pekka + + Support PKCS #1 format public and private keys. Support for new + PKCS API. */ #include "silc.h" -#include "rsa_internal.h" #include "rsa.h" -/* - * SILC PKCS API for RSA - */ - -/* Generates RSA key pair. */ - -SILC_PKCS_API_INIT(rsa) -{ - SilcUInt32 prime_bits = keylen / 2; - SilcMPInt p, q; - SilcBool found = FALSE; - - if (keylen < 768 || keylen > 16384) - return FALSE; - - printf("Generating RSA Public and Private keys, might take a while...\n"); - - silc_mp_init(&p); - silc_mp_init(&q); - - /* Find p and q */ - while (!found) { - printf("Finding p: "); - silc_math_gen_prime(&p, prime_bits, TRUE, rng); - - printf("\nFinding q: "); - silc_math_gen_prime(&q, prime_bits, TRUE, rng); - - if ((silc_mp_cmp(&p, &q)) == 0) - printf("\nFound equal primes, not good, retrying...\n"); - else - found = TRUE; - } - - /* If p is smaller than q, switch them */ - if ((silc_mp_cmp(&p, &q)) > 0) { - SilcMPInt hlp; - silc_mp_init(&hlp); - - silc_mp_set(&hlp, &p); - silc_mp_set(&p, &q); - silc_mp_set(&q, &hlp); - - silc_mp_uninit(&hlp); - } - - /* Generate the actual keys */ - rsa_generate_keys((RsaKey *)context, keylen, &p, &q); - - silc_mp_uninit(&p); - silc_mp_uninit(&q); - - printf("\nKeys generated successfully.\n"); - - return TRUE; -} - -SILC_PKCS_API_CLEAR_KEYS(rsa) -{ - rsa_clear_keys((RsaKey *)context); -} - -/* Returns SILC style encoded RSA public key. */ - -SILC_PKCS_API_GET_PUBLIC_KEY(rsa) -{ - RsaKey *key = (RsaKey *)context; - unsigned char *e, *n, *ret; - SilcUInt32 e_len, n_len; - unsigned char tmp[4]; - - e = silc_mp_mp2bin(&key->e, 0, &e_len); - n = silc_mp_mp2bin(&key->n, (key->bits + 7) / 8, &n_len); - - *ret_len = e_len + 4 + n_len + 4; - ret = silc_calloc(*ret_len, sizeof(unsigned char)); - - /* Put the length of the e. */ - SILC_PUT32_MSB(e_len, tmp); - memcpy(ret, tmp, 4); - - /* Put the e. */ - memcpy(ret + 4, e, e_len); - - /* Put the length of the n. */ - SILC_PUT32_MSB(n_len, tmp); - memcpy(ret + 4 + e_len, tmp, 4); - - /* Put the n. */ - memcpy(ret + 4 + e_len + 4, n, n_len); - - memset(e, 0, e_len); - memset(n, 0, n_len); - silc_free(e); - silc_free(n); - - return ret; -} - -/* Returns SILC style encoded RSA private key. Public key is always - returned in private key as well. Public keys are often derived - directly from private key. */ - -SILC_PKCS_API_GET_PRIVATE_KEY(rsa) -{ - RsaKey *key = (RsaKey *)context; - SilcBuffer buf; - unsigned char *e, *n, *d, *ret, *dp = NULL, *dq = NULL; - unsigned char *pq = NULL, *qp = NULL, *p = NULL, *q = NULL; - SilcUInt32 e_len, n_len, d_len, dp_len, dq_len, pq_len, qp_len, p_len, q_len; - SilcUInt32 len = 0; - - e = silc_mp_mp2bin(&key->e, 0, &e_len); - n = silc_mp_mp2bin(&key->n, (key->bits + 7) / 8, &n_len); - d = silc_mp_mp2bin(&key->d, 0, &d_len); - if (key->crt) { - dp = silc_mp_mp2bin(&key->dP, 0, &dp_len); - dq = silc_mp_mp2bin(&key->dQ, 0, &dq_len); - pq = silc_mp_mp2bin(&key->pQ, 0, &pq_len); - qp = silc_mp_mp2bin(&key->qP, 0, &qp_len); - p = silc_mp_mp2bin(&key->p, 0, &p_len); - q = silc_mp_mp2bin(&key->q, 0, &q_len); - len = dp_len + 4 + dq_len + 4 + pq_len + 4 + qp_len + 4 + p_len + 4 + - q_len + 4; - } - - buf = silc_buffer_alloc_size(e_len + 4 + n_len + 4 + d_len + 4 + len); - len = silc_buffer_format(buf, - SILC_STR_UI_INT(e_len), - SILC_STR_UI_XNSTRING(e, e_len), - SILC_STR_UI_INT(n_len), - SILC_STR_UI_XNSTRING(n, n_len), - SILC_STR_UI_INT(d_len), - SILC_STR_UI_XNSTRING(d, d_len), - SILC_STR_END); - - if (key->crt) { - silc_buffer_pull(buf, len); - silc_buffer_format(buf, - SILC_STR_UI_INT(dp_len), - SILC_STR_UI_XNSTRING(dp, dp_len), - SILC_STR_UI_INT(dq_len), - SILC_STR_UI_XNSTRING(dq, dq_len), - SILC_STR_UI_INT(pq_len), - SILC_STR_UI_XNSTRING(pq, pq_len), - SILC_STR_UI_INT(qp_len), - SILC_STR_UI_XNSTRING(qp, qp_len), - SILC_STR_UI_INT(p_len), - SILC_STR_UI_XNSTRING(p, p_len), - SILC_STR_UI_INT(q_len), - SILC_STR_UI_XNSTRING(q, q_len), - SILC_STR_END); - silc_buffer_push(buf, len); - - memset(dp, 0, dp_len); - memset(dq, 0, dq_len); - memset(pq, 0, pq_len); - memset(qp, 0, qp_len); - memset(p, 0, p_len); - memset(q, 0, q_len); - silc_free(dp); - silc_free(dq); - silc_free(pq); - silc_free(qp); - silc_free(p); - silc_free(q); - } - - memset(d, 0, d_len); - silc_free(e); - silc_free(n); - silc_free(d); - - ret = silc_buffer_steal(buf, ret_len); - silc_buffer_free(buf); - return ret; -} - -/* Set public key */ - -SILC_PKCS_API_SET_PUBLIC_KEY(rsa) -{ - RsaKey *key = (RsaKey *)context; - unsigned char tmp[4]; - SilcUInt32 e_len, n_len; - - if (key->pub_set) { - silc_mp_uninit(&key->e); - silc_mp_uninit(&key->n); - key->pub_set = FALSE; - } - - if (key_len < 4) - return 0; - - silc_mp_init(&key->e); - silc_mp_init(&key->n); - - memcpy(tmp, key_data, 4); - SILC_GET32_MSB(e_len, tmp); - if (!e_len || e_len + 4 > key_len) { - silc_mp_uninit(&key->e); - silc_mp_uninit(&key->n); - return 0; - } - - silc_mp_bin2mp(key_data + 4, e_len, &key->e); - - if (key_len < 4 + e_len + 4) { - silc_mp_uninit(&key->e); - silc_mp_uninit(&key->n); - return 0; - } - - memcpy(tmp, key_data + 4 + e_len, 4); - SILC_GET32_MSB(n_len, tmp); - if (!n_len || e_len + 4 + n_len + 4 > key_len) { - silc_mp_uninit(&key->e); - silc_mp_uninit(&key->n); - return 0; - } - - silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &key->n); - - key->bits = silc_mp_sizeinbase(&key->n, 2); - key->pub_set = TRUE; - - return key->bits; -} - -/* Set private key. This derives the public key from the private - key and sets the public key as well. Public key should not be set - already and should not be set after setting private key. */ - -SILC_PKCS_API_SET_PRIVATE_KEY(rsa) -{ - RsaKey *key = (RsaKey *)context; - SilcBufferStruct k; - unsigned char *tmp; - SilcUInt32 len; - - if (key->prv_set) { - silc_mp_uninit(&key->d); - key->prv_set = FALSE; - } - - if (key->pub_set) { - silc_mp_uninit(&key->e); - silc_mp_uninit(&key->n); - key->pub_set = FALSE; - } - - if (key_len < 4) - return FALSE; - - silc_buffer_set(&k, key_data, key_len); - - silc_mp_init(&key->e); - silc_mp_init(&key->n); - silc_mp_init(&key->d); - key->prv_set = TRUE; - key->pub_set = TRUE; - - /* Get e */ - if (silc_buffer_unformat(&k, - SILC_STR_UI_INT(&len), - SILC_STR_END) < 0) - goto err; - silc_buffer_pull(&k, 4); - if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), - SILC_STR_END) < 0) - goto err; - silc_mp_bin2mp(tmp, len, &key->e); - silc_buffer_pull(&k, len); - - /* Get n */ - if (silc_buffer_unformat(&k, - SILC_STR_UI_INT(&len), - SILC_STR_END) < 0) - goto err; - silc_buffer_pull(&k, 4); - if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), - SILC_STR_END) < 0) - goto err; - silc_mp_bin2mp(tmp, len, &key->n); - silc_buffer_pull(&k, len); - - /* Get d */ - if (silc_buffer_unformat(&k, - SILC_STR_UI_INT(&len), - SILC_STR_END) < 0) - goto err; - silc_buffer_pull(&k, 4); - if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), - SILC_STR_END) < 0) - goto err; - silc_mp_bin2mp(tmp, len, &key->d); - silc_buffer_pull(&k, len); - - /* Get optimized d for CRT, if present. */ - if (silc_buffer_len(&k) > 4) { - key->crt = TRUE; - silc_mp_init(&key->dP); - silc_mp_init(&key->dQ); - silc_mp_init(&key->pQ); - silc_mp_init(&key->qP); - silc_mp_init(&key->p); - silc_mp_init(&key->q); - - /* Get dP */ - if (silc_buffer_unformat(&k, - SILC_STR_UI_INT(&len), - SILC_STR_END) < 0) - goto err; - silc_buffer_pull(&k, 4); - if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), - SILC_STR_END) < 0) - goto err; - silc_mp_bin2mp(tmp, len, &key->dP); - silc_buffer_pull(&k, len); - - /* Get dQ */ - if (silc_buffer_unformat(&k, - SILC_STR_UI_INT(&len), - SILC_STR_END) < 0) - goto err; - silc_buffer_pull(&k, 4); - if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), - SILC_STR_END) < 0) - goto err; - silc_mp_bin2mp(tmp, len, &key->dQ); - silc_buffer_pull(&k, len); - - /* Get pQ */ - if (silc_buffer_unformat(&k, - SILC_STR_UI_INT(&len), - SILC_STR_END) < 0) - goto err; - silc_buffer_pull(&k, 4); - if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), - SILC_STR_END) < 0) - goto err; - silc_mp_bin2mp(tmp, len, &key->pQ); - silc_buffer_pull(&k, len); - - /* Get qP */ - if (silc_buffer_unformat(&k, - SILC_STR_UI_INT(&len), - SILC_STR_END) < 0) - goto err; - silc_buffer_pull(&k, 4); - if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), - SILC_STR_END) < 0) - goto err; - silc_mp_bin2mp(tmp, len, &key->qP); - silc_buffer_pull(&k, len); - - /* Get p */ - if (silc_buffer_unformat(&k, - SILC_STR_UI_INT(&len), - SILC_STR_END) < 0) - goto err; - silc_buffer_pull(&k, 4); - if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), - SILC_STR_END) < 0) - goto err; - silc_mp_bin2mp(tmp, len, &key->p); - silc_buffer_pull(&k, len); - - /* Get q */ - if (silc_buffer_unformat(&k, - SILC_STR_UI_INT(&len), - SILC_STR_END) < 0) - goto err; - silc_buffer_pull(&k, 4); - if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), - SILC_STR_END) < 0) - goto err; - silc_mp_bin2mp(tmp, len, &key->q); - silc_buffer_pull(&k, len); - } - - key->bits = silc_mp_sizeinbase(&key->n, 2); - return key->bits; - - err: - rsa_clear_keys(key); - return FALSE; -} - -SILC_PKCS_API_CONTEXT_LEN(rsa) -{ - return sizeof(RsaKey); -} - -/* Raw RSA routines */ - -SILC_PKCS_API_ENCRYPT(rsa) -{ - RsaKey *key = (RsaKey *)context; - int tmplen; - SilcMPInt mp_tmp; - SilcMPInt mp_dst; - - silc_mp_init(&mp_tmp); - silc_mp_init(&mp_dst); - - /* Format the data into MP int */ - silc_mp_bin2mp(src, src_len, &mp_tmp); - - /* Encrypt */ - rsa_public_operation(key, &mp_tmp, &mp_dst); - - tmplen = (key->bits + 7) / 8; - - /* Format the MP int back into data */ - silc_mp_mp2bin_noalloc(&mp_dst, dst, tmplen); - *dst_len = tmplen; - - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - - return TRUE; -} - -SILC_PKCS_API_DECRYPT(rsa) -{ - RsaKey *key = (RsaKey *)context; - int tmplen; - SilcMPInt mp_tmp; - SilcMPInt mp_dst; - - silc_mp_init(&mp_tmp); - silc_mp_init(&mp_dst); - - /* Format the data into MP int */ - silc_mp_bin2mp(src, src_len, &mp_tmp); - - /* Decrypt */ - rsa_private_operation(key, &mp_tmp, &mp_dst); - - tmplen = (key->bits + 7) / 8; - - /* Format the MP int back into data */ - silc_mp_mp2bin_noalloc(&mp_dst, dst, tmplen); - *dst_len = tmplen; - - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - - return TRUE; -} - -SILC_PKCS_API_SIGN(rsa) -{ - RsaKey *key = (RsaKey *)context; - int tmplen; - SilcMPInt mp_tmp; - SilcMPInt mp_dst; - - silc_mp_init(&mp_tmp); - silc_mp_init(&mp_dst); - - /* Format the data into MP int */ - silc_mp_bin2mp(src, src_len, &mp_tmp); - - /* Sign */ - rsa_private_operation(key, &mp_tmp, &mp_dst); - - tmplen = (key->bits + 7) / 8; - - /* Format the MP int back into data */ - silc_mp_mp2bin_noalloc(&mp_dst, dst, tmplen); - *dst_len = tmplen; - - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - - return TRUE; -} - -SILC_PKCS_API_VERIFY(rsa) -{ - RsaKey *key = (RsaKey *)context; - int ret; - SilcMPInt mp_tmp, mp_tmp2; - SilcMPInt mp_dst; - - silc_mp_init(&mp_tmp); - silc_mp_init(&mp_tmp2); - silc_mp_init(&mp_dst); - - /* Format the signature into MP int */ - silc_mp_bin2mp(signature, signature_len, &mp_tmp2); - - /* Verify */ - rsa_public_operation(key, &mp_tmp2, &mp_dst); - - /* Format the data into MP int */ - silc_mp_bin2mp(data, data_len, &mp_tmp); - - ret = TRUE; - - /* Compare */ - if ((silc_mp_cmp(&mp_tmp, &mp_dst)) != 0) - ret = FALSE; - - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_tmp2); - silc_mp_uninit(&mp_dst); - - return ret; -} - - -/* PKCS#1 RSA routines */ - -SILC_PKCS_API_ENCRYPT(pkcs1) -{ - RsaKey *key = (RsaKey *)context; - SilcMPInt mp_tmp; - SilcMPInt mp_dst; - unsigned char padded[2048 + 1]; - SilcUInt32 len = (key->bits + 7) / 8; - - if (sizeof(padded) < len) - return FALSE; - - /* Pad data */ - if (!silc_pkcs1_encode(SILC_PKCS1_BT_PUB, src, src_len, - padded, len, NULL)) - return FALSE; - - silc_mp_init(&mp_tmp); - silc_mp_init(&mp_dst); - - /* Data to MP */ - silc_mp_bin2mp(padded, len, &mp_tmp); - - /* Encrypt */ - rsa_public_operation(key, &mp_tmp, &mp_dst); - - /* MP to data */ - silc_mp_mp2bin_noalloc(&mp_dst, dst, len); - *dst_len = len; - - memset(padded, 0, sizeof(padded)); - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - - return TRUE; -} - -SILC_PKCS_API_DECRYPT(pkcs1) -{ - RsaKey *key = (RsaKey *)context; - SilcMPInt mp_tmp; - SilcMPInt mp_dst; - unsigned char *padded, unpadded[2048 + 1]; - SilcUInt32 padded_len; - - silc_mp_init(&mp_tmp); - silc_mp_init(&mp_dst); - - /* Data to MP */ - silc_mp_bin2mp(src, src_len, &mp_tmp); - - /* Decrypt */ - rsa_private_operation(key, &mp_tmp, &mp_dst); - - /* MP to data */ - padded = silc_mp_mp2bin(&mp_dst, (key->bits + 7) / 8, &padded_len); - - /* Unpad data */ - if (!silc_pkcs1_decode(SILC_PKCS1_BT_PUB, padded, padded_len, - unpadded, sizeof(unpadded), dst_len)) { - memset(padded, 0, padded_len); - silc_free(padded); - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - return FALSE; - } - - /* Copy to destination */ - memcpy(dst, unpadded, *dst_len); - - memset(padded, 0, padded_len); - memset(unpadded, 0, sizeof(unpadded)); - silc_free(padded); - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - - return TRUE; -} - -SILC_PKCS_API_SIGN(pkcs1) -{ - RsaKey *key = (RsaKey *)context; - SilcMPInt mp_tmp; - SilcMPInt mp_dst; - unsigned char padded[2048 + 1]; - SilcUInt32 len = (key->bits + 7) / 8; - - if (sizeof(padded) < len) - return FALSE; - - /* Pad data */ - if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, src, src_len, - padded, len, NULL)) - return FALSE; - - silc_mp_init(&mp_tmp); - silc_mp_init(&mp_dst); - - /* Data to MP */ - silc_mp_bin2mp(padded, len, &mp_tmp); - - /* Sign */ - rsa_private_operation(key, &mp_tmp, &mp_dst); - - /* MP to data */ - silc_mp_mp2bin_noalloc(&mp_dst, dst, len); - *dst_len = len; - - memset(padded, 0, sizeof(padded)); - silc_mp_uninit(&mp_tmp); - silc_mp_uninit(&mp_dst); - - return TRUE; -} - -SILC_PKCS_API_VERIFY(pkcs1) -{ - RsaKey *key = (RsaKey *)context; - int ret = TRUE; - SilcMPInt mp_tmp2; - SilcMPInt mp_dst; - unsigned char *verify, unpadded[2048 + 1]; - SilcUInt32 verify_len, len = (key->bits + 7) / 8; - - silc_mp_init(&mp_tmp2); - silc_mp_init(&mp_dst); - - /* Format the signature into MP int */ - silc_mp_bin2mp(signature, signature_len, &mp_tmp2); - - /* Verify */ - rsa_public_operation(key, &mp_tmp2, &mp_dst); - - /* MP to data */ - verify = silc_mp_mp2bin(&mp_dst, len, &verify_len); - - /* Unpad data */ - if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len, - unpadded, sizeof(unpadded), &len)) { - memset(verify, 0, verify_len); - silc_free(verify); - silc_mp_uninit(&mp_tmp2); - silc_mp_uninit(&mp_dst); - return FALSE; - } - - /* Compare */ - if (memcmp(data, unpadded, len)) - ret = FALSE; - - memset(verify, 0, verify_len); - memset(unpadded, 0, sizeof(unpadded)); - silc_free(verify); - silc_mp_uninit(&mp_tmp2); - silc_mp_uninit(&mp_dst); - - return ret; -} - /* Generates RSA public and private keys. Primes p and q that are used to compute the modulus n has to be generated before calling this. They are then sent as argument for the function. */ -SilcBool rsa_generate_keys(RsaKey *key, SilcUInt32 bits, - SilcMPInt *p, SilcMPInt *q) +SilcBool rsa_generate_keys(SilcUInt32 bits, SilcMPInt *p, SilcMPInt *q, + void **ret_public_key, void **ret_private_key) { + RsaPublicKey *pubkey; + RsaPrivateKey *privkey; SilcMPInt phi, hlp; SilcMPInt div, lcm; SilcMPInt pm1, qm1; + *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey)); + if (!pubkey) + return FALSE; + + *ret_private_key = privkey = silc_calloc(1, sizeof(*privkey)); + if (!privkey) + return FALSE; + /* Initialize variables */ - silc_mp_init(&key->n); - silc_mp_init(&key->e); - silc_mp_init(&key->d); - silc_mp_init(&key->dP); - silc_mp_init(&key->dQ); - silc_mp_init(&key->pQ); - silc_mp_init(&key->qP); + silc_mp_init(&privkey->n); + silc_mp_init(&privkey->e); + silc_mp_init(&privkey->d); + silc_mp_init(&privkey->dP); + silc_mp_init(&privkey->dQ); + silc_mp_init(&privkey->qP); silc_mp_init(&phi); silc_mp_init(&hlp); silc_mp_init(&div); @@ -790,10 +118,10 @@ SilcBool rsa_generate_keys(RsaKey *key, SilcUInt32 bits, silc_mp_init(&qm1); /* Set modulus length */ - key->bits = bits; + privkey->bits = bits; /* Compute modulus, n = p * q */ - silc_mp_mul(&key->n, p, q); + silc_mp_mul(&privkey->n, p, q); /* phi = (p - 1) * (q - 1) */ silc_mp_sub_ui(&pm1, p, 1); @@ -803,33 +131,27 @@ SilcBool rsa_generate_keys(RsaKey *key, SilcUInt32 bits, /* Set e, the public exponent. We try to use same public exponent for all keys. Also, to make encryption faster we use small number. */ - silc_mp_set_ui(&key->e, 65533); + silc_mp_set_ui(&privkey->e, 65533); retry_e: /* See if e is relatively prime to phi. gcd == greates common divisor, if gcd equals 1 they are relatively prime. */ - silc_mp_gcd(&hlp, &key->e, &phi); + silc_mp_gcd(&hlp, &privkey->e, &phi); if ((silc_mp_cmp_ui(&hlp, 1)) > 0) { - silc_mp_add_ui(&key->e, &key->e, 2); + silc_mp_add_ui(&privkey->e, &privkey->e, 2); goto retry_e; } /* Find d, the private exponent, e ^ -1 mod lcm(phi). */ silc_mp_gcd(&div, &pm1, &qm1); silc_mp_div(&lcm, &phi, &div); - silc_mp_modinv(&key->d, &key->e, &lcm); - - /* Optimize d with CRT. We precompute as much as possible. */ - silc_mp_mod(&key->dP, &key->d, &pm1); - silc_mp_mod(&key->dQ, &key->d, &qm1); - silc_mp_modinv(&key->pQ, p, q); - silc_mp_mul(&key->pQ, p, &key->pQ); - silc_mp_mod(&key->pQ, &key->pQ, &key->n); - silc_mp_modinv(&key->qP, q, p); - silc_mp_mul(&key->qP, q, &key->qP); - silc_mp_mod(&key->qP, &key->qP, &key->n); - silc_mp_set(&key->p, p); - silc_mp_set(&key->q, q); - key->crt = TRUE; + silc_mp_modinv(&privkey->d, &privkey->e, &lcm); + + /* Optimize d with CRT. */ + silc_mp_mod(&privkey->dP, &privkey->d, &pm1); + silc_mp_mod(&privkey->dQ, &privkey->d, &qm1); + silc_mp_modinv(&privkey->qP, q, p); + silc_mp_set(&privkey->p, p); + silc_mp_set(&privkey->q, q); silc_mp_uninit(&phi); silc_mp_uninit(&hlp); @@ -838,34 +160,20 @@ SilcBool rsa_generate_keys(RsaKey *key, SilcUInt32 bits, silc_mp_uninit(&pm1); silc_mp_uninit(&qm1); - return TRUE; -} + /* Set public key */ + silc_mp_init(&pubkey->n); + silc_mp_init(&pubkey->e); + pubkey->bits = privkey->bits; + silc_mp_set(&pubkey->n, &privkey->n); + silc_mp_set(&pubkey->e, &privkey->e); -/* Clears whole key structure. */ - -SilcBool rsa_clear_keys(RsaKey *key) -{ - key->bits = 0; - if (key->pub_set) { - silc_mp_uninit(&key->n); - silc_mp_uninit(&key->e); - } - if (key->prv_set) - silc_mp_uninit(&key->d); - if (key->prv_set && key->crt) { - silc_mp_uninit(&key->dP); - silc_mp_uninit(&key->dQ); - silc_mp_uninit(&key->pQ); - silc_mp_uninit(&key->qP); - silc_mp_uninit(&key->p); - silc_mp_uninit(&key->q); - } return TRUE; } /* RSA public key operation */ -SilcBool rsa_public_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst) +SilcBool rsa_public_operation(RsaPublicKey *key, SilcMPInt *src, + SilcMPInt *dst) { /* dst = src ^ e mod n */ silc_mp_pow_mod(dst, src, &key->e, &key->n); @@ -874,27 +182,29 @@ SilcBool rsa_public_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst) /* RSA private key operation */ -SilcBool rsa_private_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst) +SilcBool rsa_private_operation(RsaPrivateKey *key, SilcMPInt *src, + SilcMPInt *dst) { - if (!key->crt) { - /* dst = src ^ d mod n */ - silc_mp_pow_mod(dst, src, &key->d, &key->n); - } else { - /* CRT */ - SilcMPInt tmp; - - silc_mp_init(&tmp); - - /* dst = ((src ^ dP mod p) * qP) + ((src ^ dQ mod q) * pQ) mod n */ - silc_mp_pow_mod(dst, src, &key->dP, &key->p); - silc_mp_mul(dst, dst, &key->qP); - silc_mp_pow_mod(&tmp, src, &key->dQ, &key->q); - silc_mp_mul(&tmp, &tmp, &key->pQ); - silc_mp_add(dst, dst, &tmp); - silc_mp_mod(dst, dst, &key->n); - - silc_mp_uninit(&tmp); - } + SilcMPInt tmp; + + silc_mp_init(&tmp); + + /* dst = (src ^ dP mod p) */ + silc_mp_pow_mod(dst, src, &key->dP, &key->p); + + /* tmp = (src ^ dQ mod q) */ + silc_mp_pow_mod(&tmp, src, &key->dQ, &key->q); + + /* dst = (dst - tmp) * qP mod p */ + silc_mp_sub(dst, dst, &tmp); + silc_mp_mul(dst, dst, &key->qP); + silc_mp_mod(dst, dst, &key->p); + + /* dst = (q * dst) + tmp */ + silc_mp_mul(dst, dst, &key->q); + silc_mp_add(dst, dst, &tmp); + + silc_mp_uninit(&tmp); return TRUE; } diff --git a/lib/silccrypt/rsa.h b/lib/silccrypt/rsa.h index a697fef4..0b05728e 100644 --- a/lib/silccrypt/rsa.h +++ b/lib/silccrypt/rsa.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2003 Pekka Riikonen + Copyright (C) 1997 - 2006 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 @@ -20,26 +20,31 @@ #ifndef RSA_H #define RSA_H -/* - * SILC PKCS API for RSA - */ - -SILC_PKCS_API_INIT(rsa); -SILC_PKCS_API_CLEAR_KEYS(rsa); -SILC_PKCS_API_GET_PUBLIC_KEY(rsa); -SILC_PKCS_API_GET_PRIVATE_KEY(rsa); -SILC_PKCS_API_SET_PUBLIC_KEY(rsa); -SILC_PKCS_API_SET_PRIVATE_KEY(rsa); -SILC_PKCS_API_CONTEXT_LEN(rsa); -SILC_PKCS_API_ENCRYPT(rsa); -SILC_PKCS_API_DECRYPT(rsa); -SILC_PKCS_API_SIGN(rsa); -SILC_PKCS_API_VERIFY(rsa); - -SILC_PKCS_API_ENCRYPT(pkcs1); -SILC_PKCS_API_DECRYPT(pkcs1); -SILC_PKCS_API_SIGN(pkcs1); -SILC_PKCS_API_VERIFY(pkcs1); - - -#endif +/* RSA Public Key */ +typedef struct { + int bits; /* bits in key */ + SilcMPInt n; /* modulus */ + SilcMPInt e; /* public exponent */ +} RsaPublicKey; + +/* RSA Private Key */ +typedef struct { + int bits; /* bits in key */ + SilcMPInt n; /* modulus */ + SilcMPInt e; /* public exponent */ + SilcMPInt d; /* private exponent */ + SilcMPInt p; /* CRT, p */ + SilcMPInt q; /* CRT, q */ + SilcMPInt dP; /* CRT, d mod p - 1 */ + SilcMPInt dQ; /* CRT, d mod q - 1 */ + SilcMPInt qP; /* CRT, q ^ -1 mod p */ +} RsaPrivateKey; + +SilcBool rsa_generate_keys(SilcUInt32 bits, SilcMPInt *p, SilcMPInt *q, + void **ret_public_key, void **ret_private_key); +SilcBool rsa_public_operation(RsaPublicKey *key, SilcMPInt *src, + SilcMPInt *dst); +SilcBool rsa_private_operation(RsaPrivateKey *key, SilcMPInt *src, + SilcMPInt *dst); + +#endif /* RSA_H */ diff --git a/lib/silccrypt/rsa_internal.h b/lib/silccrypt/rsa_internal.h deleted file mode 100644 index f3daa126..00000000 --- a/lib/silccrypt/rsa_internal.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - - rsa_internal.h - - Author: Pekka Riikonen - - Copyright (C) 1997 - 2003 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 - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - -*/ - -#ifndef RSA_INTERNAL_H -#define RSA_INTERNAL_H - -/* RSA Keys, includes both Private and Public key */ -typedef struct { - int bits; /* bits in key */ - SilcMPInt n; /* modulus */ - SilcMPInt e; /* public exponent */ - SilcMPInt d; /* private exponent (no CRT) */ - SilcMPInt p; /* p */ - SilcMPInt q; /* q */ - SilcMPInt dP; /* CRT, d mod p - 1 */ - SilcMPInt dQ; /* CRT, d mod q - 1 */ - SilcMPInt pQ; /* CRT, p * (p ^ -1 mod q) mod n */ - SilcMPInt qP; /* CRT, q * (q ^ -1 mod p) mod n */ - unsigned int pub_set : 1; /* TRUE if n and e is set */ - unsigned int prv_set : 1; /* TRUE if d is set */ - unsigned int crt : 1; /* TRUE if CRT is used */ -} RsaKey; - -SilcBool rsa_generate_keys(RsaKey *key, SilcUInt32 bits, - SilcMPInt *p, SilcMPInt *q); -SilcBool rsa_clear_keys(RsaKey *key); -SilcBool rsa_public_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst); -SilcBool rsa_private_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst); - -#endif diff --git a/lib/silccrypt/silchash.h b/lib/silccrypt/silchash.h index d7317f0c..698ce15a 100644 --- a/lib/silccrypt/silchash.h +++ b/lib/silccrypt/silchash.h @@ -1,10 +1,10 @@ /* - silchash.h + silchash.h Author: Pekka Riikonen - Copyright (C) 1997 - 2002 Pekka Riikonen + Copyright (C) 1997 - 2005 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 @@ -34,7 +34,7 @@ /****s* silccrypt/SilcHashAPI/SilcHash * * NAME - * + * * typedef struct SilcHashStruct *SilcHash; * * DESCRIPTION @@ -50,7 +50,7 @@ typedef struct SilcHashStruct *SilcHash; /****s* silccrypt/SilcHashAPI/SilcHashObject * * NAME - * + * * typedef struct { ... } SilcHashObject; * * DESCRIPTION @@ -310,7 +310,7 @@ void silc_hash_make(SilcHash hash, const unsigned char *data, * put them into a buffer and compute the digest from the buffer by * calling the silc_hash_make, or you can use the silc_hash_init, * silc_hash_update and silc_hash_final to do the digest. This function - * prepares the allocated hash function context for this kind of digest + * prepares the allocated hash function context for this kind of digest * computation. To add the data to be used in the digest computation * call the silc_hash_update function. * diff --git a/lib/silccrypt/silcpk.c b/lib/silccrypt/silcpk.c new file mode 100644 index 00000000..0de35d6a --- /dev/null +++ b/lib/silccrypt/silcpk.c @@ -0,0 +1,1601 @@ +/* + + silcpk.c + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2006 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#include "silc.h" +#include "silcpk_i.h" + +/****************************** Key generation *******************************/ + +/* Generate new SILC key pair. */ + +SilcBool silc_pkcs_silc_generate_key(const char *algorithm, + const char *scheme, + SilcUInt32 bits_key_len, + const char *identifier, + SilcRng rng, + SilcPublicKey *ret_public_key, + SilcPrivateKey *ret_private_key) +{ + SilcSILCPublicKey pubkey; + SilcSILCPrivateKey privkey; + const SilcPKCSAlgorithm *alg; + const SilcPKCSObject *pkcs; + + SILC_LOG_DEBUG(("Generating SILC %s key pair with key length %d bits", + algorithm, bits_key_len)); + + if (!rng) + return FALSE; + + pkcs = silc_pkcs_find_pkcs(SILC_PKCS_SILC); + if (!pkcs) + return FALSE; + + alg = silc_pkcs_find_algorithm(algorithm, scheme); + if (!alg) + return FALSE; + + /* Allocate SILC public key */ + pubkey = silc_calloc(1, sizeof(*pubkey)); + if (!pubkey) + return FALSE; + pubkey->pkcs = alg; + + /* Decode identifier */ + if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier)) { + silc_free(pubkey); + return FALSE; + } + + /* Allocate SILC private key */ + privkey = silc_calloc(1, sizeof(*privkey)); + if (!privkey) { + silc_free(pubkey); + return FALSE; + } + privkey->pkcs = alg; + + /* Allocate public key */ + *ret_public_key = silc_calloc(1, sizeof(**ret_public_key)); + if (!(*ret_public_key)) { + silc_free(pubkey); + silc_free(privkey); + return FALSE; + } + (*ret_public_key)->pkcs = pkcs; + (*ret_public_key)->public_key = pubkey; + + /* Allocate private key */ + *ret_private_key = silc_calloc(1, sizeof(**ret_private_key)); + if (!(*ret_private_key)) { + silc_free(pubkey); + silc_free(privkey); + silc_free(*ret_public_key); + return FALSE; + } + (*ret_private_key)->pkcs = pkcs; + (*ret_private_key)->private_key = privkey; + + /* Generate the algorithm key pair */ + if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key, + &privkey->private_key)) { + silc_free(pubkey); + silc_free(privkey); + silc_free(*ret_public_key); + silc_free(*ret_private_key); + return FALSE; + } + + return TRUE; +} + + +/**************************** Utility functions ******************************/ + +/* Decodes the provided `identifier' */ + +SilcBool silc_pkcs_silc_decode_identifier(const char *identifier, + SilcPublicKeyIdentifier ident) +{ + char *cp, *item; + int len; + + /* Protocol says that at least UN and HN must be provided as identifier */ + if (!strstr(identifier, "UN=") && !strstr(identifier, "HN=")) { + SILC_LOG_DEBUG(("The public does not have the required UN= and HN= " + "identifiers")); + return FALSE; + } + + cp = (char *)identifier; + while (cp) { + len = strcspn(cp, ","); + if (len < 1) { + cp = NULL; + break; + } + if (len - 1 >= 0 && cp[len - 1] == '\\') { + while (cp) { + if (len + 1 > strlen(cp)) { + cp = NULL; + break; + } + cp += len + 1; + len = strcspn(cp, ",") + len; + if (len < 1) { + cp = NULL; + break; + } + if (len - 1 >= 0 && cp[len - 1] != '\\') + break; + } + } + + if (!cp) + break; + + item = silc_calloc(len + 1, sizeof(char)); + if (!item) + return FALSE; + if (len > strlen(cp)) + break; + memcpy(item, cp, len); + + if (strstr(item, "UN=")) + ident->username = strdup(item + strcspn(cp, "=") + 1); + else if (strstr(item, "HN=")) + ident->host = strdup(item + strcspn(cp, "=") + 1); + else if (strstr(item, "RN=")) + ident->realname = strdup(item + strcspn(cp, "=") + 1); + else if (strstr(item, "E=")) + ident->email = strdup(item + strcspn(cp, "=") + 1); + else if (strstr(item, "O=")) + ident->org = strdup(item + strcspn(cp, "=") + 1); + else if (strstr(item, "C=")) + ident->country = strdup(item + strcspn(cp, "=") + 1); + + cp += len; + if (strlen(cp) < 1) + cp = NULL; + else + cp += 1; + + if (item) + silc_free(item); + } + + return TRUE; +} + +/* Encodes and returns SILC public key identifier. If some of the + arguments is NULL those are not encoded into the identifier string. + Protocol says that at least username and host must be provided. */ + +char *silc_pkcs_silc_encode_identifier(char *username, char *host, + char *realname, char *email, + char *org, char *country) +{ + SilcBuffer buf; + char *identifier; + SilcUInt32 len, tlen = 0; + + if (!username || !host) + return NULL; + + len = (username ? strlen(username) : 0) + + (host ? strlen(host) : 0) + + (realname ? strlen(realname) : 0) + + (email ? strlen(email) : 0) + + (org ? strlen(org) : 0) + + (country ? strlen(country) : 0); + + if (len < 3) + return NULL; + + len += 3 + 5 + 5 + 4 + 4 + 4; + buf = silc_buffer_alloc(len); + if (!buf) + return NULL; + silc_buffer_pull_tail(buf, len); + + if (username) { + silc_buffer_format(buf, + SILC_STR_UI32_STRING("UN="), + SILC_STR_UI32_STRING(username), + SILC_STR_END); + silc_buffer_pull(buf, 3 + strlen(username)); + tlen = 3 + strlen(username); + } + + if (host) { + silc_buffer_format(buf, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("HN="), + SILC_STR_UI32_STRING(host), + SILC_STR_END); + silc_buffer_pull(buf, 5 + strlen(host)); + tlen += 5 + strlen(host); + } + + if (realname) { + silc_buffer_format(buf, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("RN="), + SILC_STR_UI32_STRING(realname), + SILC_STR_END); + silc_buffer_pull(buf, 5 + strlen(realname)); + tlen += 5 + strlen(realname); + } + + if (email) { + silc_buffer_format(buf, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("E="), + SILC_STR_UI32_STRING(email), + SILC_STR_END); + silc_buffer_pull(buf, 4 + strlen(email)); + tlen += 4 + strlen(email); + } + + if (org) { + silc_buffer_format(buf, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("O="), + SILC_STR_UI32_STRING(org), + SILC_STR_END); + silc_buffer_pull(buf, 4 + strlen(org)); + tlen += 4 + strlen(org); + } + + if (country) { + silc_buffer_format(buf, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("C="), + SILC_STR_UI32_STRING(country), + SILC_STR_END); + silc_buffer_pull(buf, 4 + strlen(country)); + tlen += 4 + strlen(country); + } + + silc_buffer_push(buf, buf->data - buf->head); + identifier = silc_calloc(tlen + 1, sizeof(*identifier)); + if (!identifier) + return NULL; + memcpy(identifier, buf->data, tlen); + silc_buffer_free(buf); + + return identifier; +} + + +/*************************** Public key routines *****************************/ + +/* Returns PKCS algorithm context */ + +const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key) +{ + SilcSILCPublicKey silc_pubkey = public_key; + return silc_pubkey->pkcs; +} + +/* Imports SILC protocol style public key from SILC public key file */ + +SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata, + SilcUInt32 filedata_len, + SilcPKCSFileEncoding encoding, + void **ret_public_key) +{ + SilcUInt32 i, len; + unsigned char *data = NULL; + SilcBool ret; + + SILC_LOG_DEBUG(("Parsing SILC public key file")); + + if (!ret_public_key) + return FALSE; + + /* Check start of file and remove header from the data. */ + len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN); + if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END)) + return FALSE; + for (i = 0; i < len; i++) { + if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) + return FALSE; + filedata++; + } + filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) + + strlen(SILC_PKCS_PUBLIC_KEYFILE_END)); + + switch (encoding) { + case SILC_PKCS_FILE_BIN: + break; + + case SILC_PKCS_FILE_BASE64: + data = silc_pem_decode(filedata, filedata_len, &filedata_len); + if (!data) + return FALSE; + filedata = data; + break; + } + + ret = silc_pkcs_silc_import_public_key(filedata, filedata_len, + ret_public_key); + silc_free(data); + + return ret; +} + +/* Imports SILC protocol style public key */ + +SilcBool silc_pkcs_silc_import_public_key(unsigned char *key, + SilcUInt32 key_len, + void **ret_public_key) +{ + const SilcPKCSAlgorithm *pkcs; + SilcBufferStruct buf, alg_key; + SilcSILCPublicKey silc_pubkey = NULL; + SilcAsn1 asn1 = NULL; + SilcUInt32 totlen, keydata_len; + SilcUInt16 pkcs_len, identifier_len; + unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL; + int ret; + + SILC_LOG_DEBUG(("Parsing SILC public key")); + + if (!ret_public_key) + return FALSE; + + silc_buffer_set(&buf, key, key_len); + + /* Get length */ + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_INT(&totlen), + SILC_STR_END); + if (ret == -1) + goto err; + + if (totlen + 4 != key_len) + goto err; + + /* Get algorithm name and identifier */ + ret = + silc_buffer_unformat(&buf, + SILC_STR_OFFSET(4), + SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len), + SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len), + SILC_STR_END); + if (ret == -1) + goto err; + + if (pkcs_len < 1 || identifier_len < 3 || + pkcs_len + identifier_len > totlen) + goto err; + + /* Get key data */ + silc_buffer_pull(&buf, 4 + 2 + pkcs_len + 2 + identifier_len); + keydata_len = silc_buffer_len(&buf); + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_XNSTRING(&key_data, + keydata_len), + SILC_STR_END); + if (ret == -1) + goto err; + + /* Allocate SILC public key context */ + silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey)); + if (!silc_pubkey) + goto err; + + /* Decode SILC identifier */ + if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier)) + goto err; + + asn1 = silc_asn1_alloc(); + if (!asn1) + goto err; + + if (!strcmp(pkcs_name, "rsa")) { + /* Parse the SILC RSA public key */ + SilcUInt32 e_len, n_len; + SilcMPInt n, e; + + /* Get PKCS object */ + pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid"); + if (!pkcs) { + SILC_LOG_DEBUG(("Unsupported PKCS algorithm")); + goto err; + } + silc_pubkey->pkcs = pkcs; + + if (keydata_len < 4) + goto err; + SILC_GET32_MSB(e_len, key_data); + if (!e_len || e_len + 4 > keydata_len) + goto err; + silc_mp_init(&e); + silc_mp_bin2mp(key_data + 4, e_len, &e); + if (keydata_len < 4 + e_len + 4) { + silc_mp_uninit(&e); + goto err; + } + SILC_GET32_MSB(n_len, key_data + 4 + e_len); + if (!n_len || e_len + 4 + n_len + 4 > keydata_len) { + silc_mp_uninit(&e); + goto err; + } + silc_mp_init(&n); + silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n); + + /* Encode to PKCS #1 format */ + memset(&alg_key, 0, sizeof(alg_key)); + if (!silc_asn1_encode(asn1, &alg_key, + SILC_ASN1_SEQUENCE, + SILC_ASN1_INT(&n), + SILC_ASN1_INT(&e), + SILC_ASN1_END, SILC_ASN1_END)) { + silc_mp_uninit(&e); + silc_mp_uninit(&n); + goto err; + } + + silc_mp_uninit(&e); + silc_mp_uninit(&n); + + } else if (!strcmp(pkcs_name, "dsa")) { + SILC_NOT_IMPLEMENTED("DSA SILC Public Key"); + goto err; + + } else { + SILC_LOG_DEBUG(("Unsupported PKCS algorithm")); + goto err; + } + + /* Import PKCS algorithm public key */ + if (pkcs->import_public_key) + if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key), + &silc_pubkey->public_key)) + goto err; + + silc_free(pkcs_name); + silc_free(ident); + silc_asn1_free(asn1); + + *ret_public_key = silc_pubkey; + + return TRUE; + + err: + silc_free(pkcs_name); + silc_free(ident); + silc_free(silc_pubkey); + if (asn1) + silc_asn1_free(asn1); + return FALSE; +} + +/* Exports public key as SILC protocol style public key file */ + +unsigned char * +silc_pkcs_silc_export_public_key_file(void *public_key, + SilcPKCSFileEncoding encoding, + SilcUInt32 *ret_len) +{ + SilcBuffer buf; + unsigned char *key, *data; + SilcUInt32 key_len; + + SILC_LOG_DEBUG(("Encoding SILC public key file")); + + /* Export key */ + key = silc_pkcs_silc_export_public_key(public_key, &key_len); + if (!key) + return NULL; + + switch (encoding) { + case SILC_PKCS_FILE_BIN: + break; + + case SILC_PKCS_FILE_BASE64: + data = silc_pem_encode_file(key, key_len); + if (!data) + return NULL; + silc_free(key); + key = data; + key_len = strlen(data); + break; + } + + /* Encode SILC public key file */ + buf = silc_buffer_alloc_size(key_len + + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) + + strlen(SILC_PKCS_PUBLIC_KEYFILE_END))); + if (!buf) { + silc_free(key); + return NULL; + } + + if (silc_buffer_format(buf, + SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN), + SILC_STR_UI_XNSTRING(key, key_len), + SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END), + SILC_STR_END) < 0) { + silc_buffer_free(buf); + silc_free(key); + return NULL; + } + + silc_free(key); + key = silc_buffer_steal(buf, ret_len); + silc_buffer_free(buf); + + return key; +} + +/* Exports public key as SILC protocol style public key */ + +unsigned char *silc_pkcs_silc_export_public_key(void *public_key, + SilcUInt32 *ret_len) +{ + SilcSILCPublicKey silc_pubkey = public_key; + const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs; + SilcBufferStruct alg_key; + SilcBuffer buf = NULL; + SilcAsn1 asn1 = NULL; + unsigned char *pk = NULL, *key = NULL, *ret; + SilcUInt32 pk_len, key_len, totlen; + char *identifier; + + SILC_LOG_DEBUG(("Encoding SILC public key")); + + /* Export PKCS algorithm public key */ + if (pkcs->export_public_key) + pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len); + if (!pk) + return NULL; + silc_buffer_set(&alg_key, pk, pk_len); + + /* Encode identifier */ + identifier = + silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username, + silc_pubkey->identifier.host, + silc_pubkey->identifier.realname, + silc_pubkey->identifier.email, + silc_pubkey->identifier.org, + silc_pubkey->identifier.country); + if (!identifier) + goto err; + + asn1 = silc_asn1_alloc(); + if (!asn1) + goto err; + + if (!strcmp(pkcs->name, "rsa")) { + /* Parse the PKCS #1 public key */ + SilcMPInt n, e; + SilcUInt32 n_len, e_len; + unsigned char *nb, *eb; + + memset(&n, 0, sizeof(n)); + memset(&e, 0, sizeof(e)); + if (!silc_asn1_decode(asn1, &alg_key, + SILC_ASN1_SEQUENCE, + SILC_ASN1_INT(&n), + SILC_ASN1_INT(&e), + SILC_ASN1_END, SILC_ASN1_END)) + goto err; + + /* Encode to SILC RSA public key */ + eb = silc_mp_mp2bin(&e, 0, &e_len); + if (!eb) + goto err; + nb = silc_mp_mp2bin(&n, 0, &n_len); + if (!nb) + goto err; + key_len = e_len + 4 + n_len + 4; + key = silc_calloc(key_len, sizeof(*key)); + if (!key) + goto err; + + /* Put e length and e */ + SILC_PUT32_MSB(e_len, key); + memcpy(key + 4, eb, e_len); + + /* Put n length and n. */ + SILC_PUT32_MSB(n_len, key + 4 + e_len); + memcpy(key + 4 + e_len + 4, nb, n_len); + + silc_free(nb); + silc_free(eb); + + } else if (!strcmp(pkcs->name, "dsa")) { + SILC_NOT_IMPLEMENTED("SILC DSA Public Key"); + goto err; + + } else { + SILC_LOG_DEBUG(("Unsupported PKCS algorithm")); + goto err; + } + + /* Encode SILC Public Key */ + totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len; + buf = silc_buffer_alloc_size(totlen + 4); + if (!buf) + goto err; + if (silc_buffer_format(buf, + SILC_STR_UI_INT(totlen), + SILC_STR_UI_SHORT(strlen(pkcs->name)), + SILC_STR_UI32_STRING(pkcs->name), + SILC_STR_UI_SHORT(strlen(identifier)), + SILC_STR_UI32_STRING(identifier), + SILC_STR_UI_XNSTRING(key, key_len), + SILC_STR_END) < 0) + goto err; + + ret = silc_buffer_steal(buf, ret_len); + silc_buffer_free(buf); + silc_free(key); + silc_free(identifier); + silc_asn1_free(asn1); + + return ret; + + err: + silc_free(identifier); + silc_free(pk); + silc_free(key); + if (buf) + silc_buffer_free(buf); + if (asn1) + silc_asn1_free(asn1); + return NULL; +} + +/* Return key length */ + +SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key) +{ + SilcSILCPublicKey silc_pubkey = public_key; + return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key); +} + +/* Copy public key */ + +void *silc_pkcs_silc_public_key_copy(void *public_key) +{ + SilcSILCPublicKey silc_pubkey = public_key, new_pubkey; + + new_pubkey = silc_calloc(1, sizeof(*new_pubkey)); + if (!new_pubkey) + return NULL; + new_pubkey->pkcs = silc_pubkey->pkcs; + + new_pubkey->public_key = + silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key); + if (!new_pubkey->public_key) { + silc_free(new_pubkey); + return NULL; + } + + return new_pubkey; +} + +/* Compares public keys */ + +SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2) +{ + SilcSILCPublicKey k1 = key1, k2 = key2; + + if (strcmp(k1->pkcs->name, k2->pkcs->name)) + return FALSE; + + if ((k1->identifier.username && !k2->identifier.username) || + (!k1->identifier.username && k2->identifier.username) || + (k1->identifier.username && k2->identifier.username && + strcmp(k1->identifier.username, k2->identifier.username))) + return FALSE; + + if ((k1->identifier.host && !k2->identifier.host) || + (!k1->identifier.host && k2->identifier.host) || + (k1->identifier.host && k2->identifier.host && + strcmp(k1->identifier.host, k2->identifier.host))) + return FALSE; + + if ((k1->identifier.realname && !k2->identifier.realname) || + (!k1->identifier.realname && k2->identifier.realname) || + (k1->identifier.realname && k2->identifier.realname && + strcmp(k1->identifier.realname, k2->identifier.realname))) + return FALSE; + + if ((k1->identifier.email && !k2->identifier.email) || + (!k1->identifier.email && k2->identifier.email) || + (k1->identifier.email && k2->identifier.email && + strcmp(k1->identifier.email, k2->identifier.email))) + return FALSE; + + if ((k1->identifier.org && !k2->identifier.org) || + (!k1->identifier.org && k2->identifier.org) || + (k1->identifier.org && k2->identifier.org && + strcmp(k1->identifier.org, k2->identifier.org))) + return FALSE; + + if ((k1->identifier.country && !k2->identifier.country) || + (!k1->identifier.country && k2->identifier.country) || + (k1->identifier.country && k2->identifier.country && + strcmp(k1->identifier.country, k2->identifier.country))) + return FALSE; + + return k1->pkcs->public_key_compare(k1->public_key, k2->public_key); +} + +/* Frees public key */ + +void silc_pkcs_silc_public_key_free(void *public_key) +{ + SilcSILCPublicKey silc_pubkey = public_key; + + silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key); + + silc_free(silc_pubkey->identifier.username); + silc_free(silc_pubkey->identifier.host); + silc_free(silc_pubkey->identifier.realname); + silc_free(silc_pubkey->identifier.email); + silc_free(silc_pubkey->identifier.org); + silc_free(silc_pubkey->identifier.country); + silc_free(silc_pubkey); +} + + +/*************************** Private key routines ****************************/ + +/* Private key file magic */ +#define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531 + +/* Imports SILC implementation style private key file */ + +SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata, + SilcUInt32 filedata_len, + const char *passphrase, + SilcUInt32 passphrase_len, + SilcPKCSFileEncoding encoding, + void **ret_private_key) +{ + SilcCipher aes; + SilcHash sha1; + SilcHmac sha1hmac; + SilcUInt32 blocklen; + unsigned char tmp[32], keymat[64], *data = NULL; + SilcUInt32 i, len, magic, mac_len; + SilcBool ret; + + SILC_LOG_DEBUG(("Parsing SILC private key file")); + + /* Check start of file and remove header from the data. */ + len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN); + if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)) + return FALSE; + for (i = 0; i < len; i++) { + if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) + return FALSE; + filedata++; + } + + len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) + + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)); + + switch (encoding) { + case SILC_PKCS_FILE_BIN: + break; + + case SILC_PKCS_FILE_BASE64: + data = silc_pem_decode(filedata, filedata_len, &len); + if (!data) + return FALSE; + filedata = data; + break; + } + + memset(tmp, 0, sizeof(tmp)); + memset(keymat, 0, sizeof(keymat)); + + /* Check file magic */ + SILC_GET32_MSB(magic, filedata); + if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) { + SILC_LOG_ERROR(("Private key does not have correct magic")); + return FALSE; + } + + /* Allocate the AES cipher */ + if (!silc_cipher_alloc("aes-256-cbc", &aes)) { + SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered")); + return FALSE; + } + blocklen = silc_cipher_get_block_len(aes); + if (blocklen * 2 > sizeof(tmp)) { + silc_cipher_free(aes); + return FALSE; + } + + /* Allocate SHA1 hash */ + if (!silc_hash_alloc("sha1", &sha1)) { + SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered")); + silc_cipher_free(aes); + return FALSE; + } + + /* Allocate HMAC */ + if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) { + SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered")); + silc_hash_free(sha1); + silc_cipher_free(aes); + return FALSE; + } + + /* Derive the decryption key from the provided key material. The key + is 256 bits length, and derived by taking hash of the data, then + re-hashing the data and the previous digest, and using the first and + second digest as the key. */ + silc_hash_init(sha1); + silc_hash_update(sha1, passphrase, passphrase_len); + silc_hash_final(sha1, keymat); + silc_hash_init(sha1); + silc_hash_update(sha1, passphrase, passphrase_len); + silc_hash_update(sha1, keymat, 16); + silc_hash_final(sha1, keymat + 16); + + /* Set the key to the cipher */ + silc_cipher_set_key(aes, keymat, 256); + + /* First, verify the MAC of the private key data */ + mac_len = silc_hmac_len(sha1hmac); + silc_hmac_init_with_key(sha1hmac, keymat, 16); + silc_hmac_update(sha1hmac, filedata, len - mac_len); + silc_hmac_final(sha1hmac, tmp, NULL); + if (memcmp(tmp, filedata + (len - mac_len), mac_len)) { + SILC_LOG_DEBUG(("Integrity check for private key failed")); + memset(keymat, 0, sizeof(keymat)); + memset(tmp, 0, sizeof(tmp)); + silc_hmac_free(sha1hmac); + silc_hash_free(sha1); + silc_cipher_free(aes); + return FALSE; + } + filedata += 4; + len -= 4; + + /* Decrypt the private key buffer */ + silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL); + SILC_GET32_MSB(i, filedata); + if (i > len) { + SILC_LOG_DEBUG(("Bad private key length in buffer!")); + memset(keymat, 0, sizeof(keymat)); + memset(tmp, 0, sizeof(tmp)); + silc_hmac_free(sha1hmac); + silc_hash_free(sha1); + silc_cipher_free(aes); + return FALSE; + } + filedata += 4; + len = i; + + /* Cleanup */ + memset(keymat, 0, sizeof(keymat)); + memset(tmp, 0, sizeof(tmp)); + silc_hmac_free(sha1hmac); + silc_hash_free(sha1); + silc_cipher_free(aes); + + /* Import the private key */ + ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key); + + silc_free(data); + + return ret; +} + +/* Private key version */ +#define SILC_PRIVATE_KEY_VERSION_1 0x82171273 + +/* Imports SILC implementation style private key */ + +SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, + SilcUInt32 key_len, + void **ret_private_key) +{ + SilcBufferStruct buf; + const SilcPKCSAlgorithm *pkcs; + SilcBufferStruct alg_key; + SilcSILCPrivateKey silc_privkey = NULL; + SilcAsn1 asn1 = NULL; + SilcUInt16 pkcs_len; + SilcUInt32 keydata_len; + unsigned char *pkcs_name = NULL, *key_data; + int ret; + + SILC_LOG_DEBUG(("Parsing SILC private key")); + + if (!ret_private_key) + return FALSE; + + silc_buffer_set(&buf, key, key_len); + + /* Get algorithm name and identifier */ + ret = + silc_buffer_unformat(&buf, + SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len), + SILC_STR_END); + if (ret == -1) { + SILC_LOG_DEBUG(("Cannot decode private key buffer")); + goto err; + } + + if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) { + SILC_LOG_DEBUG(("Malformed private key buffer")); + goto err; + } + + /* Get key data. We assume that rest of the buffer is key data. */ + silc_buffer_pull(&buf, 2 + pkcs_len); + keydata_len = silc_buffer_len(&buf); + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_XNSTRING(&key_data, keydata_len), + SILC_STR_END); + if (ret == -1) + goto err; + + /* Allocate SILC private key context */ + silc_privkey = silc_calloc(1, sizeof(*silc_privkey)); + if (!silc_privkey) + goto err; + + asn1 = silc_asn1_alloc(); + if (!asn1) + goto err; + + if (!strcmp(pkcs_name, "rsa")) { + /* Parse the RSA SILC private key */ + SilcBufferStruct k; + SilcMPInt n, e, d, dp, dq, qp, p, q; + SilcMPInt version; + unsigned char *tmp; + SilcUInt32 len, ver; + + /* Get PKCS object */ + pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid"); + if (!pkcs) { + SILC_LOG_DEBUG(("Unsupported PKCS algorithm")); + goto err; + } + silc_privkey->pkcs = pkcs; + + if (keydata_len < 4) + goto err; + + silc_buffer_set(&k, key_data, keydata_len); + + /* Get version. Key without the version is old style private key + and we need to do some computation to get it to correct format. */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&ver), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + + if (ver != SILC_PRIVATE_KEY_VERSION_1) { + len = ver; + } else { + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&len), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + } + + /* Get e */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_END) < 0) + goto err; + silc_mp_init(&e); + silc_mp_bin2mp(tmp, len, &e); + silc_buffer_pull(&k, len); + + /* Get n */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&len), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + if (silc_buffer_unformat(&k, + SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_END) < 0) + goto err; + silc_mp_init(&n); + silc_mp_bin2mp(tmp, len, &n); + silc_buffer_pull(&k, len); + + /* Get d */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&len), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + if (silc_buffer_unformat(&k, + SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_END) < 0) + goto err; + silc_mp_init(&d); + silc_mp_bin2mp(tmp, len, &d); + silc_buffer_pull(&k, len); + + /* Get dP */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&len), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + if (silc_buffer_unformat(&k, + SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_END) < 0) + goto err; + silc_mp_init(&dp); + silc_mp_bin2mp(tmp, len, &dp); + silc_buffer_pull(&k, len); + + /* Get dQ */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&len), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + if (silc_buffer_unformat(&k, + SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_END) < 0) + goto err; + silc_mp_init(&dq); + silc_mp_bin2mp(tmp, len, &dq); + silc_buffer_pull(&k, len); + + if (ver != SILC_PRIVATE_KEY_VERSION_1) { + /* Old version */ + + /* Get pQ len */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&len), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + if (silc_buffer_len(&k) < len) + goto err; + silc_buffer_pull(&k, len); + + /* Get qP len */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&len), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + if (silc_buffer_len(&k) < len) + goto err; + silc_buffer_pull(&k, len); + } else { + /* New version */ + + /* Get qP */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&len), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + if (silc_buffer_unformat(&k, + SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_END) < 0) + goto err; + silc_mp_init(&qp); + silc_mp_bin2mp(tmp, len, &qp); + silc_buffer_pull(&k, len); + } + + /* Get p */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&len), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + if (silc_buffer_unformat(&k, + SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_END) < 0) + goto err; + silc_mp_init(&p); + silc_mp_bin2mp(tmp, len, &p); + silc_buffer_pull(&k, len); + + /* Get q */ + if (silc_buffer_unformat(&k, + SILC_STR_UI_INT(&len), + SILC_STR_END) < 0) + goto err; + silc_buffer_pull(&k, 4); + if (silc_buffer_unformat(&k, + SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_END) < 0) + goto err; + silc_mp_init(&q); + silc_mp_bin2mp(tmp, len, &q); + silc_buffer_pull(&k, len); + + if (ver != SILC_PRIVATE_KEY_VERSION_1) { + /* Old version. Compute to new version */ + SILC_LOG_DEBUG(("Old version private key")); + silc_mp_init(&qp); + silc_mp_modinv(&qp, &q, &p); + } + + /* Encode to PKCS #1 format */ + silc_mp_init(&version); + silc_mp_set_ui(&version, 0); + memset(&alg_key, 0, sizeof(alg_key)); + if (!silc_asn1_encode(asn1, &alg_key, + SILC_ASN1_SEQUENCE, + SILC_ASN1_INT(&version), + SILC_ASN1_INT(&n), + SILC_ASN1_INT(&e), + SILC_ASN1_INT(&d), + SILC_ASN1_INT(&p), + SILC_ASN1_INT(&q), + SILC_ASN1_INT(&dp), + SILC_ASN1_INT(&dq), + SILC_ASN1_INT(&qp), + SILC_ASN1_END, SILC_ASN1_END)) + goto err; + + silc_mp_uninit(&version); + silc_mp_uninit(&n); + silc_mp_uninit(&e); + silc_mp_uninit(&e); + silc_mp_uninit(&d); + silc_mp_uninit(&p); + silc_mp_uninit(&q); + silc_mp_uninit(&dp); + silc_mp_uninit(&dq); + silc_mp_uninit(&qp); + + } else if (!strcmp(pkcs_name, "dsa")) { + SILC_NOT_IMPLEMENTED("DSA SILC Private Key"); + goto err; + + } else { + SILC_LOG_DEBUG(("Unsupported PKCS algorithm")); + goto err; + } + + /* Import PKCS algorithm private key */ + if (pkcs->import_private_key) + if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key), + &silc_privkey->private_key)) + goto err; + + silc_free(pkcs_name); + silc_asn1_free(asn1); + + *ret_private_key = silc_privkey; + + return TRUE; + + err: + silc_free(pkcs_name); + silc_free(silc_privkey); + if (asn1) + silc_asn1_free(asn1); + return FALSE; +} + +/* Exports private key as SILC implementation style private key file */ + +unsigned char * +silc_pkcs_silc_export_private_key_file(void *private_key, + const char *passphrase, + SilcUInt32 passphrase_len, + SilcPKCSFileEncoding encoding, + SilcRng rng, + SilcUInt32 *ret_len) +{ + SilcCipher aes; + SilcHash sha1; + SilcHmac sha1hmac; + SilcBuffer buf, enc; + SilcUInt32 len, blocklen, padlen, key_len; + unsigned char *key, *data; + unsigned char tmp[32], keymat[64]; + int i; + + SILC_LOG_DEBUG(("Encoding SILC private key file")); + + /* Export the private key */ + key = silc_pkcs_silc_export_private_key(private_key, &key_len); + if (!key) + return NULL; + + memset(tmp, 0, sizeof(tmp)); + memset(keymat, 0, sizeof(keymat)); + + /* Allocate the AES cipher */ + if (!silc_cipher_alloc("aes-256-cbc", &aes)) { + SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered")); + silc_free(key); + return NULL; + } + blocklen = silc_cipher_get_block_len(aes); + if (blocklen * 2 > sizeof(tmp)) { + silc_cipher_free(aes); + silc_free(key); + return NULL; + } + + /* Allocate SHA1 hash */ + if (!silc_hash_alloc("sha1", &sha1)) { + SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered")); + silc_cipher_free(aes); + return NULL; + } + + /* Allocate HMAC */ + if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) { + SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered")); + silc_hash_free(sha1); + silc_cipher_free(aes); + return NULL; + } + + /* Derive the encryption key from the provided key material. The key + is 256 bits length, and derived by taking hash of the data, then + re-hashing the data and the previous digest, and using the first and + second digest as the key. */ + silc_hash_init(sha1); + silc_hash_update(sha1, passphrase, passphrase_len); + silc_hash_final(sha1, keymat); + silc_hash_init(sha1); + silc_hash_update(sha1, passphrase, passphrase_len); + silc_hash_update(sha1, keymat, 16); + silc_hash_final(sha1, keymat + 16); + + /* Set the key to the cipher */ + silc_cipher_set_key(aes, keymat, 256); + + /* Encode the buffer to be encrypted. Add padding to it too, at least + block size of the cipher. */ + + /* Allocate buffer for encryption */ + len = silc_hmac_len(sha1hmac); + padlen = 16 + (16 - ((key_len + 4) % blocklen)); + enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len); + if (!enc) { + silc_hmac_free(sha1hmac); + silc_hash_free(sha1); + silc_cipher_free(aes); + return FALSE; + } + + /* Generate padding */ + for (i = 0; i < padlen; i++) + tmp[i] = silc_rng_get_byte_fast(rng); + + /* Put magic number */ + SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data); + silc_buffer_pull(enc, 4); + + /* Encode the buffer */ + silc_buffer_format(enc, + SILC_STR_UI_INT(key_len), + SILC_STR_UI_XNSTRING(key, key_len), + SILC_STR_UI_XNSTRING(tmp, padlen), + SILC_STR_END); + silc_free(key); + + /* Encrypt. */ + silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len, + silc_cipher_get_iv(aes)); + + silc_buffer_push(enc, 4); + + /* Compute HMAC over the encrypted data and append the MAC to data. + The key is the first digest of the original key material. */ + key_len = silc_buffer_len(enc) - len; + silc_hmac_init_with_key(sha1hmac, keymat, 16); + silc_hmac_update(sha1hmac, enc->data, key_len); + silc_buffer_pull(enc, key_len); + silc_hmac_final(sha1hmac, enc->data, NULL); + silc_buffer_push(enc, key_len); + + /* Cleanup */ + memset(keymat, 0, sizeof(keymat)); + memset(tmp, 0, sizeof(tmp)); + silc_hmac_free(sha1hmac); + silc_hash_free(sha1); + silc_cipher_free(aes); + + switch (encoding) { + case SILC_PKCS_FILE_BIN: + break; + + case SILC_PKCS_FILE_BASE64: + data = silc_pem_encode_file(enc->data, silc_buffer_len(enc)); + if (!data) { + silc_buffer_clear(enc); + silc_buffer_free(enc); + return NULL; + } + silc_free(silc_buffer_steal(enc, NULL)); + silc_buffer_set(enc, data, strlen(data)); + break; + } + + key = enc->data; + key_len = silc_buffer_len(enc); + + /* Encode the data and save to file */ + len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) + + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)); + buf = silc_buffer_alloc_size(len); + if (!buf) { + silc_buffer_free(enc); + return NULL; + } + silc_buffer_format(buf, + SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN), + SILC_STR_UI_XNSTRING(key, key_len), + SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END), + SILC_STR_END); + + silc_buffer_free(enc); + data = silc_buffer_steal(buf, ret_len); + silc_buffer_free(buf); + + return data; +} + +/* Exports private key as SILC implementation style private key */ + +unsigned char *silc_pkcs_silc_export_private_key(void *private_key, + SilcUInt32 *ret_len) +{ + SilcSILCPrivateKey silc_privkey = private_key; + const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs; + SilcBufferStruct alg_key; + SilcBuffer buf = NULL; + SilcAsn1 asn1 = NULL; + unsigned char *prv = NULL, *key = NULL, *ret; + SilcUInt32 prv_len, key_len, totlen; + + SILC_LOG_DEBUG(("Encoding SILC private key")); + + /* Export PKCS algorithm private key */ + if (pkcs->export_private_key) + prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len); + if (!prv) + return NULL; + silc_buffer_set(&alg_key, prv, prv_len); + + asn1 = silc_asn1_alloc(); + if (!asn1) + goto err; + + if (!strcmp(pkcs->name, "rsa")) { + /* Parse the PKCS #1 private key */ + SilcMPInt n, e, d, dp, dq, qp, p, q; + SilcUInt32 e_len, n_len, d_len, dp_len, dq_len, + qp_len, p_len, q_len, len = 0; + unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb; + + if (!silc_asn1_decode(asn1, &alg_key, + SILC_ASN1_SEQUENCE, + SILC_ASN1_INT(NULL), + SILC_ASN1_INT(&n), + SILC_ASN1_INT(&e), + SILC_ASN1_INT(&d), + SILC_ASN1_INT(&p), + SILC_ASN1_INT(&q), + SILC_ASN1_INT(&dp), + SILC_ASN1_INT(&dq), + SILC_ASN1_INT(&qp), + SILC_ASN1_END, SILC_ASN1_END)) + goto err; + + /* Encode to SILC RSA private key */ + eb = silc_mp_mp2bin(&e, 0, &e_len); + nb = silc_mp_mp2bin(&n, 0, &n_len); + db = silc_mp_mp2bin(&d, 0, &d_len); + dpb = silc_mp_mp2bin(&dp, 0, &dp_len); + dqb = silc_mp_mp2bin(&dq, 0, &dq_len); + qpb = silc_mp_mp2bin(&qp, 0, &qp_len); + pb = silc_mp_mp2bin(&p, 0, &p_len); + qb = silc_mp_mp2bin(&q, 0, &q_len); + len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 + + dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4; + + buf = silc_buffer_alloc_size(len); + if (!buf) + goto err; + if (silc_buffer_format(buf, + SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1), + SILC_STR_UI_INT(e_len), + SILC_STR_UI_XNSTRING(eb, e_len), + SILC_STR_UI_INT(n_len), + SILC_STR_UI_XNSTRING(nb, n_len), + SILC_STR_UI_INT(d_len), + SILC_STR_UI_XNSTRING(db, d_len), + SILC_STR_UI_INT(dp_len), + SILC_STR_UI_XNSTRING(dpb, dp_len), + SILC_STR_UI_INT(dq_len), + SILC_STR_UI_XNSTRING(dqb, dq_len), + SILC_STR_UI_INT(qp_len), + SILC_STR_UI_XNSTRING(qpb, qp_len), + SILC_STR_UI_INT(p_len), + SILC_STR_UI_XNSTRING(pb, p_len), + SILC_STR_UI_INT(q_len), + SILC_STR_UI_XNSTRING(qb, q_len), + SILC_STR_END) < 0) + goto err; + + key = silc_buffer_steal(buf, &key_len); + silc_buffer_free(buf); + silc_free(nb); + silc_free(eb); + silc_free(db); + silc_free(dpb); + silc_free(dqb); + silc_free(qpb); + silc_free(pb); + silc_free(qb); + + } else if (!strcmp(pkcs->name, "dsa")) { + SILC_NOT_IMPLEMENTED("SILC DSA Private Key"); + goto err; + + } else { + SILC_LOG_DEBUG(("Unsupported PKCS algorithm")); + goto err; + } + + /* Encode SILC private key */ + totlen = 2 + strlen(pkcs->name) + key_len; + buf = silc_buffer_alloc_size(totlen); + if (!buf) + goto err; + if (silc_buffer_format(buf, + SILC_STR_UI_SHORT(strlen(pkcs->name)), + SILC_STR_UI32_STRING(pkcs->name), + SILC_STR_UI_XNSTRING(key, key_len), + SILC_STR_END) < 0) + goto err; + + ret = silc_buffer_steal(buf, ret_len); + silc_buffer_free(buf); + silc_free(prv); + silc_free(key); + silc_asn1_free(asn1); + + return ret; + + err: + silc_free(prv); + silc_free(key); + if (buf) + silc_buffer_free(buf); + return NULL; +} + +/* Return key length */ + +SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key) +{ + SilcSILCPrivateKey silc_privkey = private_key; + return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key); +} + +/* Frees private key */ + +void silc_pkcs_silc_private_key_free(void *private_key) +{ + SilcSILCPrivateKey silc_privkey = private_key; + + silc_privkey->pkcs->private_key_free(silc_privkey->private_key); + + silc_free(silc_privkey); +} + + +/***************************** PKCS operations ******************************/ + +/* Encrypts as specified in SILC protocol specification */ + +SilcBool silc_pkcs_silc_encrypt(void *public_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len) +{ + SilcSILCPublicKey silc_pubkey = public_key; + + if (!silc_pubkey->pkcs->encrypt) + return FALSE; + + return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key, + src, src_len, + dst, dst_size, ret_dst_len); +} + +/* Decrypts as specified in SILC protocol specification */ + +SilcBool silc_pkcs_silc_decrypt(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len) +{ + SilcSILCPrivateKey silc_privkey = private_key; + + if (!silc_privkey->pkcs->decrypt) + return FALSE; + + return silc_privkey->pkcs->decrypt(silc_privkey->private_key, + src, src_len, + dst, dst_size, ret_dst_len); +} + +/* Signs as specified in SILC protocol specification */ + +SilcBool silc_pkcs_silc_sign(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *signature, + SilcUInt32 signature_size, + SilcUInt32 *ret_signature_len, + SilcHash hash) +{ + SilcSILCPrivateKey silc_privkey = private_key; + + if (!silc_privkey->pkcs->sign) + return FALSE; + + return silc_privkey->pkcs->sign(silc_privkey->private_key, + src, src_len, + signature, signature_size, + ret_signature_len, hash); +} + +/* Verifies as specified in SILC protocol specification */ + +SilcBool silc_pkcs_silc_verify(void *public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, + SilcHash hash) +{ + SilcSILCPublicKey silc_pubkey = public_key; + + if (!silc_pubkey->pkcs->verify) + return FALSE; + + return silc_pubkey->pkcs->verify(silc_pubkey->public_key, + signature, signature_len, + data, data_len, hash); +} diff --git a/lib/silccrypt/silcpk.h b/lib/silccrypt/silcpk.h new file mode 100644 index 00000000..3db2cf2f --- /dev/null +++ b/lib/silccrypt/silcpk.h @@ -0,0 +1,167 @@ +/* + + silcpk.h + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2005 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +/****h* silccrypt/SILC Public Key Interface + * + * DESCRIPTION + * + * This interface implements the SILC protocol style public key, as defined + * by the SILC protocol specification. + * + ***/ + +#ifndef SILCPK_H +#define SILCPK_H + +/****s* silccrypt/SilcPubkeyAPI/SilcPublicKeyIdentifier + * + * NAME + * + * typedef struct { ... } *SilcPublicKeyIdentifier, + * SilcPublicKeyIdentifierStruct; + * + * DESCRIPTION + * + * This structure contains the SILC Public Key identifier. Note that + * some of the fields may be NULL. + * + * SOURCE + */ +typedef struct { + char *username; + char *host; + char *realname; + char *email; + char *org; + char *country; +} *SilcPublicKeyIdentifier, SilcPublicKeyIdentifierStruct; +/***/ + +/****s* silccrypt/SilcPubkeyAPI/SilcSILCPublicKey + * + * NAME + * + * typedef struct { ... } *SilcSILCPublicKey; + * + * DESCRIPTION + * + * This structure defines the SILC protocol style public key. User + * doesn't have to access this structure usually, except when access to + * the identifier is required. The silc_pkcs_get_context for the + * PKCS type SILC_PKCS_SILC returns this context. + * + * SOURCE + */ +typedef struct { + SilcPublicKeyIdentifierStruct identifier; + const SilcPKCSAlgorithm *pkcs; /* PKCS algorithm */ + void *public_key; /* MPKCS algorithm specific public key */ +} *SilcSILCPublicKey; +/***/ + +/****s* silccrypt/SilcPubkeyAPI/SilcSILCPrivateKey + * + * NAME + * + * typedef struct { ... } *SilcSILCPrivateKey; + * + * DESCRIPTION + * + * This structure defines the SILC protocol implementation specific + * private key. This structure isn't usually needed by the user. + * + * SOURCE + */ +typedef struct { + const SilcPKCSAlgorithm *pkcs; /* PKCS algorithm */ + void *private_key; /* PKCS algorithm specific private key */ +} *SilcSILCPrivateKey; +/***/ + +/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_generate_key + * + * SYNOPSIS + * + * SilcBool silc_pkcs_silc_generate_key(const char *algorithm, + * const char *scheme, + * SilcUInt32 bits_key_len, + * SilcRng rng, + * SilcPublicKey *ret_public_key, + * SilcPrivateKey *ret_private_key) + * + * DESCRIPTION + * + * Generate a new SILC key pair of the algorithm type `algorithm' with + * the key length in bits of `bits_key_len'. The `scheme' may be NULL. + * Returns FALSE if key generation failed. + * + * EXAMPLE + * + * // Generate RSA key pair with 2048 bit key length, using PKCS #1 + * // no OID scheme. + * silc_pkcs_silc_generate_key("rsa", "pkcs1-no-oid", 2048, + * rng, &public_key, &private_key); + * + ***/ +SilcBool silc_pkcs_silc_generate_key(const char *algorithm, + const char *scheme, + SilcUInt32 bits_key_len, + const char *identifier, + SilcRng rng, + SilcPublicKey *ret_public_key, + SilcPrivateKey *ret_private_key); + +/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_decode_identifier + * + * SYNOPSIS + * + * char *silc_pkcs_silc_encode_identifier(char *username, char *host, + * char *realname, char *email, + * char *org, char *country) + * + * DESCRIPTION + * + * Encodes and returns SILC public key identifier. If some of the + * arguments are NULL those are not encoded into the identifier string. + * Protocol says that at least username and host must be provided. + * Caller must free the returned identifier string. + * + ***/ +char *silc_pkcs_silc_encode_identifier(char *username, char *host, + char *realname, char *email, + char *org, char *country); + +/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_decode_identifier + * + * SYNOPSIS + * + * SilcBool silc_pkcs_silc_decode_identifier(const char *identifier, + * SilcPublicKeyIdentifier ident); + * + * DESCRIPTION + * + * Decodes SILC protocol public key identifier `identifier' into the + * the `ident' structure. Returns FALSE if the identifier is not valid + * identifier string. + * + ***/ +SilcBool silc_pkcs_silc_decode_identifier(const char *identifier, + SilcPublicKeyIdentifier ident); + +#endif /* SILCPK_H */ diff --git a/lib/silccrypt/silcpk_i.h b/lib/silccrypt/silcpk_i.h new file mode 100644 index 00000000..38029658 --- /dev/null +++ b/lib/silccrypt/silcpk_i.h @@ -0,0 +1,93 @@ +/* + + silcpk_i.h + + Author: Pekka Riikonen + + Copyright (C) 2005 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef SILCPK_I_H +#define SILCPK_I_H + +/* Public and private key file headers */ +#define SILC_PKCS_PUBLIC_KEYFILE_BEGIN "-----BEGIN SILC PUBLIC KEY-----\n" +#define SILC_PKCS_PUBLIC_KEYFILE_END "\n-----END SILC PUBLIC KEY-----\n" +#define SILC_PKCS_PRIVATE_KEYFILE_BEGIN "-----BEGIN SILC PRIVATE KEY-----\n" +#define SILC_PKCS_PRIVATE_KEYFILE_END "\n-----END SILC PRIVATE KEY-----\n" + +const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key); +SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata, + SilcUInt32 filedata_len, + SilcPKCSFileEncoding encoding, + void **ret_public_key); +SilcBool silc_pkcs_silc_import_public_key(unsigned char *key, + SilcUInt32 key_len, + void **ret_public_key); +unsigned char * +silc_pkcs_silc_export_public_key_file(void *public_key, + SilcPKCSFileEncoding encoding, + SilcUInt32 *ret_len); +unsigned char *silc_pkcs_silc_export_public_key(void *public_key, + SilcUInt32 *ret_len); +SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key); +void *silc_pkcs_silc_public_key_copy(void *public_key); +SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2); +void silc_pkcs_silc_public_key_free(void *public_key); +SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata, + SilcUInt32 filedata_len, + const char *passphrase, + SilcUInt32 passphrase_len, + SilcPKCSFileEncoding encoding, + void **ret_private_key); +SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, + SilcUInt32 key_len, + void **ret_private_key); +unsigned char * +silc_pkcs_silc_export_private_key_file(void *private_key, + const char *passphrase, + SilcUInt32 passphrase_len, + SilcPKCSFileEncoding encoding, + SilcRng rng, + SilcUInt32 *ret_len); +unsigned char *silc_pkcs_silc_export_private_key(void *private_key, + SilcUInt32 *ret_len); +SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key); +void silc_pkcs_silc_private_key_free(void *private_key); +SilcBool silc_pkcs_silc_encrypt(void *public_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len); +SilcBool silc_pkcs_silc_decrypt(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len); +SilcBool silc_pkcs_silc_sign(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *signature, + SilcUInt32 signature_size, + SilcUInt32 *ret_signature_len, + SilcHash hash); +SilcBool silc_pkcs_silc_verify(void *public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, + SilcHash hash); + +#endif /* SILCPK_I_H */ diff --git a/lib/silccrypt/silcpkcs.c b/lib/silccrypt/silcpkcs.c index 240456ff..7aeb3d1c 100644 --- a/lib/silccrypt/silcpkcs.c +++ b/lib/silccrypt/silcpkcs.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2005 Pekka Riikonen + Copyright (C) 1997 - 2006 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 @@ -19,89 +19,136 @@ /* $Id$ */ #include "silc.h" - -#include "rsa.h" - -/* The main SILC PKCS structure. */ -struct SilcPKCSStruct { - void *context; /* Algorithm internal context */ - SilcPKCSObject *pkcs; /* Algorithm implementation */ - SilcUInt32 key_len; /* Key length in bits */ -}; +#include "silcpk_i.h" +#include "silcpkcs1_i.h" #ifndef SILC_EPOC /* Dynamically registered list of PKCS. */ SilcDList silc_pkcs_list = NULL; +SilcDList silc_pkcs_alg_list = NULL; #define SILC_PKCS_LIST silc_pkcs_list +#define SILC_PKCS_ALG_LIST silc_pkcs_alg_list #else #define SILC_PKCS_LIST TRUE +#define SILC_PKCS_ALG_LIST TRUE #endif /* SILC_EPOC */ /* Static list of PKCS for silc_pkcs_register_default(). */ const SilcPKCSObject silc_default_pkcs[] = { - /* RSA with PKCS #1 for SILC PKCS */ - { "rsa", SILC_PKCS_SILC, - silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key, - silc_rsa_get_private_key, silc_rsa_set_public_key, - silc_rsa_set_private_key, silc_rsa_context_len, - silc_pkcs1_encrypt, silc_pkcs1_decrypt, - silc_pkcs1_sign, silc_pkcs1_verify }, - - /* RSASSA-PKCS1-V1_5 for SSH2 PKCS */ -/* - { "rsa", SILC_PKCS_SSH2, - silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key, - silc_rsa_get_private_key, silc_rsa_set_public_key, - silc_rsa_set_private_key, silc_rsa_context_len, - silc_pkcs1_encrypt, silc_pkcs1_decrypt, - silc_pkcs1_sign, silc_pkcs1_verify }, -*/ + /* SILC PKCS */ + { + SILC_PKCS_SILC, + silc_pkcs_silc_get_algorithm, + silc_pkcs_silc_import_public_key_file, + silc_pkcs_silc_import_public_key, + silc_pkcs_silc_export_public_key_file, + silc_pkcs_silc_export_public_key, + silc_pkcs_silc_public_key_bitlen, + silc_pkcs_silc_public_key_copy, + silc_pkcs_silc_public_key_compare, + silc_pkcs_silc_public_key_free, + silc_pkcs_silc_import_private_key_file, + silc_pkcs_silc_import_private_key, + silc_pkcs_silc_export_private_key_file, + silc_pkcs_silc_export_private_key, + silc_pkcs_silc_private_key_bitlen, + silc_pkcs_silc_private_key_free, + silc_pkcs_silc_encrypt, + silc_pkcs_silc_decrypt, + silc_pkcs_silc_sign, + silc_pkcs_silc_verify, + }, + + { + 0, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL + } +}; + +/* Builtin PKCS algorithms */ +const SilcPKCSAlgorithm silc_default_pkcs_alg[] = +{ + /* PKCS #1, Version 1.5 without hash OIDs */ + { + "rsa", + "pkcs1-no-oid", + "sha1,md5", + silc_pkcs1_generate_key, + silc_pkcs1_import_public_key, + silc_pkcs1_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_no_oid, + silc_pkcs1_verify_no_oid + }, + + /* PKCS #1, Version 1.5 */ + { + "rsa", + "pkcs1", + "sha1,md5", + silc_pkcs1_generate_key, + silc_pkcs1_import_public_key, + silc_pkcs1_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 + }, - { NULL, 0, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL } + { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL + } }; -/* Register a new PKCS into SILC. This is used at the initialization of - the SILC. */ +/* Register a new PKCS into SILC. */ SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs) { #ifndef SILC_EPOC - SilcPKCSObject *new; + SilcPKCSObject *newpkcs; - SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name)); + SILC_LOG_DEBUG(("Registering new PKCS")); /* Check if exists already */ if (silc_pkcs_list) { SilcPKCSObject *entry; silc_dlist_start(silc_pkcs_list); while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) { - if (!strcmp(entry->name, pkcs->name) && - entry->type == pkcs->type) + if (entry->type == pkcs->type) return FALSE; } } - new = silc_calloc(1, sizeof(*new)); - new->name = strdup(pkcs->name); - new->type = pkcs->type; - new->init = pkcs->init; - new->clear_keys = pkcs->clear_keys; - new->get_public_key = pkcs->get_public_key; - new->get_private_key = pkcs->get_private_key; - new->set_public_key = pkcs->set_public_key; - new->set_private_key = pkcs->set_private_key; - new->context_len = pkcs->context_len; - new->encrypt = pkcs->encrypt; - new->decrypt = pkcs->decrypt; - new->sign = pkcs->sign; - new->verify = pkcs->verify; + newpkcs = silc_calloc(1, sizeof(*newpkcs)); + if (!newpkcs) + return FALSE; + *newpkcs = *pkcs; /* Add to list */ if (silc_pkcs_list == NULL) silc_pkcs_list = silc_dlist_init(); - silc_dlist_add(silc_pkcs_list, new); + silc_dlist_add(silc_pkcs_list, newpkcs); #endif /* SILC_EPOC */ return TRUE; @@ -123,7 +170,6 @@ SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs) while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) { if (pkcs == SILC_ALL_PKCS || entry == pkcs) { silc_dlist_del(silc_pkcs_list, entry); - silc_free(entry->name); silc_free(entry); if (silc_dlist_count(silc_pkcs_list) == 0) { @@ -139,132 +185,149 @@ SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs) return FALSE; } -/* Function that registers all the default PKCS (all builtin PKCS). - The application may use this to register the default PKCS if specific - PKCS in any specific order is not wanted. */ +/* Register algorithm */ -SilcBool silc_pkcs_register_default(void) +SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs) { #ifndef SILC_EPOC - int i; + SilcPKCSAlgorithm *newalg; - for (i = 0; silc_default_pkcs[i].name; i++) - silc_pkcs_register(&(silc_default_pkcs[i])); - -#endif /* SILC_EPOC */ - return TRUE; -} + SILC_LOG_DEBUG(("Registering new PKCS algorithm %s", + pkcs->name)); -SilcBool silc_pkcs_unregister_all(void) -{ -#ifndef SILC_EPOC - SilcPKCSObject *entry; + /* Check if exists already */ + if (silc_pkcs_alg_list) { + SilcPKCSAlgorithm *entry; + silc_dlist_start(silc_pkcs_alg_list); + while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) { + if (!strcmp(entry->name, pkcs->name) && + entry->scheme && pkcs->scheme && + !strcmp(entry->scheme, pkcs->scheme)) + return FALSE; + } + } - if (!silc_pkcs_list) + newalg = silc_calloc(1, sizeof(*newalg)); + if (!newalg) return FALSE; - silc_dlist_start(silc_pkcs_list); - while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) { - silc_pkcs_unregister(entry); - if (!silc_pkcs_list) - break; + *newalg = *pkcs; + newalg->name = strdup(pkcs->name); + if (!newalg->name) + return FALSE; + if (pkcs->scheme) { + newalg->scheme = strdup(pkcs->scheme); + if (!newalg->scheme) + return FALSE; } + newalg->hash = strdup(pkcs->hash); + if (!newalg->hash) + return FALSE; + + /* Add to list */ + if (silc_pkcs_alg_list == NULL) + silc_pkcs_alg_list = silc_dlist_init(); + silc_dlist_add(silc_pkcs_alg_list, newalg); + #endif /* SILC_EPOC */ return TRUE; } -/* Allocates a new SilcPKCS object. The new allocated object is returned - to the 'new_pkcs' argument. */ +/* Unregister algorithm */ -SilcBool silc_pkcs_alloc(const unsigned char *name, SilcPKCSType type, - SilcPKCS *new_pkcs) +SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs) { - SilcPKCSObject *entry = NULL; +#ifndef SILC_EPOC + SilcPKCSAlgorithm*entry; - SILC_LOG_DEBUG(("Allocating new PKCS object")); + SILC_LOG_DEBUG(("Unregistering PKCS algorithm")); -#ifndef SILC_EPOC - if (silc_pkcs_list) { - silc_dlist_start(silc_pkcs_list); - while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) { - if (!strcmp(entry->name, name) && entry->type == type) - break; - } - } -#else - { - /* On EPOC which don't have globals we check our constant hash list. */ - int i; - for (i = 0; silc_default_pkcs[i].name; i++) { - if (!strcmp(silc_default_pkcs[i].name, name) && - silc_default_pkcs[i].type == type) { - entry = (SilcPKCSObject *)&(silc_default_pkcs[i]); - break; + if (!silc_pkcs_alg_list) + return FALSE; + + silc_dlist_start(silc_pkcs_alg_list); + while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) { + if (pkcs == SILC_ALL_PKCS_ALG || entry == pkcs) { + silc_dlist_del(silc_pkcs_alg_list, entry); + silc_free(entry->name); + silc_free(entry->scheme); + silc_free(entry->hash); + silc_free(entry); + + if (silc_dlist_count(silc_pkcs_alg_list) == 0) { + silc_dlist_uninit(silc_pkcs_alg_list); + silc_pkcs_alg_list = NULL; } - } - } -#endif /* SILC_EPOC */ - if (entry) { - *new_pkcs = silc_calloc(1, sizeof(**new_pkcs)); - (*new_pkcs)->pkcs = entry; - (*new_pkcs)->context = silc_calloc(1, entry->context_len()); - return TRUE; + return TRUE; + } } +#endif /* SILC_EPOC */ return FALSE; } -/* Free's the PKCS object */ +/* Function that registers all the default PKCS and PKCS algorithms. */ -void silc_pkcs_free(SilcPKCS pkcs) +SilcBool silc_pkcs_register_default(void) { - if (pkcs) { - pkcs->pkcs->clear_keys(pkcs->context); - silc_free(pkcs->context); - } - silc_free(pkcs); -} +#ifndef SILC_EPOC + int i; + + for (i = 0; silc_default_pkcs[i].type; i++) + silc_pkcs_register(&(silc_default_pkcs[i])); -/* Return TRUE if PKCS algorithm `name' is supported. */ + for (i = 0; silc_default_pkcs_alg[i].name; i++) + silc_pkcs_algorithm_register(&(silc_default_pkcs_alg[i])); + +#endif /* SILC_EPOC */ + return TRUE; +} -SilcBool silc_pkcs_is_supported(const unsigned char *name) +SilcBool silc_pkcs_unregister_all(void) { #ifndef SILC_EPOC SilcPKCSObject *entry; + SilcPKCSAlgorithm *alg; if (silc_pkcs_list) { silc_dlist_start(silc_pkcs_list); while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) { - if (!strcmp(entry->name, name)) - return TRUE; + silc_pkcs_unregister(entry); + if (!silc_pkcs_list) + break; } } -#else - { - int i; - for (i = 0; silc_default_pkcs[i].name; i++) - if (!strcmp(silc_default_pkcs[i].name, name)) - return TRUE; + + if (silc_pkcs_alg_list) { + silc_dlist_start(silc_pkcs_alg_list); + while ((alg = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) { + silc_pkcs_algorithm_unregister(alg); + if (!silc_pkcs_alg_list) + break; + } } + #endif /* SILC_EPOC */ - return FALSE; + return TRUE; } /* Returns comma separated list of supported PKCS algorithms */ char *silc_pkcs_get_supported(void) { - SilcPKCSObject *entry; + SilcPKCSAlgorithm *entry; char *list = NULL; int len = 0; #ifndef SILC_EPOC - if (silc_pkcs_list) { - silc_dlist_start(silc_pkcs_list); - while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) { + if (silc_pkcs_alg_list) { + silc_dlist_start(silc_pkcs_alg_list); + while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) { 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)); @@ -275,10 +338,12 @@ char *silc_pkcs_get_supported(void) #else { int i; - for (i = 0; silc_default_pkcs[i].name; i++) { - entry = (SilcPKCSObject *)&(silc_default_pkcs[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; memcpy(list + (len - strlen(entry->name)), entry->name, strlen(entry->name)); @@ -293,626 +358,254 @@ char *silc_pkcs_get_supported(void) return list; } -/* Generate new key pair into the `pkcs' context. */ +/* Finds PKCS object */ -SilcBool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len, - SilcRng rng) +const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type) { - SilcBool ret = pkcs->pkcs->init(pkcs->context, bits_key_len, rng); - if (ret) - pkcs->key_len = bits_key_len; - return ret; -} - -/* Returns the length of the key */ + SilcPKCSObject *entry; -SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs) -{ - return pkcs->key_len; -} +#ifndef SILC_EPOC + if (silc_pkcs_list) { + silc_dlist_start(silc_pkcs_list); + while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) { + if (entry->type == 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_EPOC */ -const char *silc_pkcs_get_name(SilcPKCS pkcs) -{ - return pkcs->pkcs->name; + return NULL; } -/* Returns SILC style public key */ +/* Finds PKCS algorithms object */ -unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len) +const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm, + const char *scheme) { - return pkcs->pkcs->get_public_key(pkcs->context, len); -} + SilcPKCSAlgorithm *entry; -/* Returns SILC style private key */ +#ifndef SILC_EPOC + if (silc_pkcs_alg_list) { + silc_dlist_start(silc_pkcs_alg_list); + while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) { + if (!strcmp(entry->name, algorithm) && + (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme))) + 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_EPOC */ -unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len) -{ - return pkcs->pkcs->get_private_key(pkcs->context, len); + return NULL; } -/* Sets public key from SilcPublicKey. */ +/* Returns PKCS context */ -SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key) +const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPublicKey public_key) { - pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, - public_key->pk_len); - return pkcs->key_len; + return public_key->pkcs; } -/* Sets public key from data. */ +/* Returns PKCS algorithm context */ -SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk, - SilcUInt32 pk_len) +const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(SilcPublicKey public_key) { - pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len); - return pkcs->key_len; + return public_key->pkcs->get_algorithm(public_key->public_key); } -/* Sets private key from SilcPrivateKey. */ +/* Return algorithm name */ -SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key) +const char *silc_pkcs_get_name(SilcPublicKey public_key) { - SilcUInt32 key_len; - key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, - private_key->prv_len); - if (!pkcs->key_len) - pkcs->key_len = key_len; - return pkcs->key_len; + const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(public_key); + return pkcs->name; } -/* Sets private key from data. */ +/* Returns PKCS type */ -SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv, - SilcUInt32 prv_len) +SilcPKCSType silc_pkcs_get_type(SilcPublicKey public_key) { - SilcUInt32 key_len; - key_len = pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len); - if (!pkcs->key_len) - pkcs->key_len = key_len; - return pkcs->key_len; + return public_key->pkcs->type; } -/* Encrypts */ +/* Allocates new public key from the key data */ -SilcBool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 *dst_len) +SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type, + unsigned char *key, + SilcUInt32 key_len, + SilcPublicKey *ret_public_key) { - return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len); -} + const SilcPKCSObject *pkcs; + SilcPublicKey public_key; -/* Decrypts */ + if (!ret_public_key) + return FALSE; -SilcBool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 *dst_len) -{ - return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len); -} + /* Allocate public key context */ + public_key = silc_calloc(1, sizeof(*public_key)); + if (!public_key) + return FALSE; -/* Generates signature */ + public_key->pkcs = pkcs = silc_pkcs_find_pkcs(type); + if (!public_key->pkcs) { + silc_free(public_key); + return FALSE; + } -SilcBool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 *dst_len) -{ - return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len); -} + /* Import the PKCS public key */ + if (!pkcs->import_public_key(key, key_len, &public_key->public_key)) { + silc_free(public_key); + return FALSE; + } -/* Verifies signature */ + *ret_public_key = public_key; -SilcBool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, - SilcUInt32 signature_len, unsigned char *data, - SilcUInt32 data_len) -{ - return pkcs->pkcs->verify(pkcs->context, signature, signature_len, - data, data_len); + return TRUE; } -/* Generates signature with hash. The hash is signed. */ +/* Frees the public key */ -SilcBool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash, - unsigned char *src, SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 *dst_len) +void silc_pkcs_public_key_free(SilcPublicKey public_key) { - unsigned char hashr[SILC_HASH_MAXLEN]; - SilcUInt32 hash_len; - int ret; - - silc_hash_make(hash, src, src_len, hashr); - hash_len = silc_hash_len(hash); - - SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len); - - ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len); - memset(hashr, 0, sizeof(hashr)); - - return ret; + public_key->pkcs->public_key_free(public_key->public_key); } -/* Verifies signature with hash. The `data' is hashed and verified against - the `signature'. */ +/* Exports public key */ -SilcBool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, - unsigned char *signature, - SilcUInt32 signature_len, - unsigned char *data, - SilcUInt32 data_len) +unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key, + SilcUInt32 *ret_len) { - unsigned char hashr[SILC_HASH_MAXLEN]; - SilcUInt32 hash_len; - int ret; - - silc_hash_make(hash, data, data_len, hashr); - hash_len = silc_hash_len(hash); - - SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len); - - ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, - hashr, hash_len); - memset(hashr, 0, sizeof(hashr)); - - return ret; + return public_key->pkcs->export_public_key(public_key->public_key, + ret_len); } -/* Encodes and returns SILC public key identifier. If some of the - arguments is NULL those are not encoded into the identifier string. - Protocol says that at least username and host must be provided. */ +/* Return key length */ -char *silc_pkcs_encode_identifier(char *username, char *host, char *realname, - char *email, char *org, char *country) +SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key) { - SilcBuffer buf; - char *identifier; - SilcUInt32 len, tlen = 0; - - if (!username || !host) - return NULL; - - len = (username ? strlen(username) : 0) + - (host ? strlen(host) : 0) + - (realname ? strlen(realname) : 0) + - (email ? strlen(email) : 0) + - (org ? strlen(org) : 0) + - (country ? strlen(country) : 0); - - if (len < 3) - return NULL; - - len += 3 + 5 + 5 + 4 + 4 + 4; - buf = silc_buffer_alloc(len); - silc_buffer_pull_tail(buf, len); - - if (username) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING("UN="), - SILC_STR_UI32_STRING(username), - SILC_STR_END); - silc_buffer_pull(buf, 3 + strlen(username)); - tlen = 3 + strlen(username); - } - - if (host) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING(", "), - SILC_STR_UI32_STRING("HN="), - SILC_STR_UI32_STRING(host), - SILC_STR_END); - silc_buffer_pull(buf, 5 + strlen(host)); - tlen += 5 + strlen(host); - } - - if (realname) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING(", "), - SILC_STR_UI32_STRING("RN="), - SILC_STR_UI32_STRING(realname), - SILC_STR_END); - silc_buffer_pull(buf, 5 + strlen(realname)); - tlen += 5 + strlen(realname); - } - - if (email) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING(", "), - SILC_STR_UI32_STRING("E="), - SILC_STR_UI32_STRING(email), - SILC_STR_END); - silc_buffer_pull(buf, 4 + strlen(email)); - tlen += 4 + strlen(email); - } - - if (org) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING(", "), - SILC_STR_UI32_STRING("O="), - SILC_STR_UI32_STRING(org), - SILC_STR_END); - silc_buffer_pull(buf, 4 + strlen(org)); - tlen += 4 + strlen(org); - } - - if (country) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING(", "), - SILC_STR_UI32_STRING("C="), - SILC_STR_UI32_STRING(country), - SILC_STR_END); - silc_buffer_pull(buf, 4 + strlen(country)); - tlen += 4 + strlen(country); - } - - silc_buffer_push(buf, buf->data - buf->head); - identifier = silc_calloc(tlen + 1, sizeof(*identifier)); - memcpy(identifier, buf->data, tlen); - silc_buffer_free(buf); - - return identifier; + return public_key->pkcs->public_key_bitlen(public_key->public_key); } -/* Decodes the provided `identifier' and returns allocated context for - the identifier. */ +/* Returns internal PKCS public key context */ -SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier) +void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key) { - SilcPublicKeyIdentifier ident; - char *cp, *item; - int len; - - ident = silc_calloc(1, sizeof(*ident)); - - cp = identifier; - while (cp) { - len = strcspn(cp, ","); - if (len < 1) { - cp = NULL; - break; - } - if (len - 1 >= 0 && cp[len - 1] == '\\') { - while (cp) { - if (len + 1 > strlen(cp)) { - cp = NULL; - break; - } - cp += len + 1; - len = strcspn(cp, ",") + len; - if (len < 1) { - cp = NULL; - break; - } - if (len - 1 >= 0 && cp[len - 1] != '\\') - break; - } - } - - if (!cp) - break; - - item = silc_calloc(len + 1, sizeof(char)); - if (len > strlen(cp)) - break; - memcpy(item, cp, len); - - if (strstr(item, "UN=")) - ident->username = strdup(item + strcspn(cp, "=") + 1); - else if (strstr(item, "HN=")) - ident->host = strdup(item + strcspn(cp, "=") + 1); - else if (strstr(item, "RN=")) - ident->realname = strdup(item + strcspn(cp, "=") + 1); - else if (strstr(item, "E=")) - ident->email = strdup(item + strcspn(cp, "=") + 1); - else if (strstr(item, "O=")) - ident->org = strdup(item + strcspn(cp, "=") + 1); - else if (strstr(item, "C=")) - ident->country = strdup(item + strcspn(cp, "=") + 1); - - cp += len; - if (strlen(cp) < 1) - cp = NULL; - else - cp += 1; - - if (item) - silc_free(item); - } - - return ident; + if (public_key->pkcs->type != type) + return FALSE; + return public_key->public_key; } -/* Free's decoded public key identifier context. Call this to free the - context returned by the silc_pkcs_decode_identifier. */ -void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier) -{ - silc_free(identifier->username); - silc_free(identifier->host); - silc_free(identifier->realname); - silc_free(identifier->email); - silc_free(identifier->org); - silc_free(identifier->country); - silc_free(identifier); -} +/* Allocates new private key from key data */ -/* Allocates SILC style public key formed from sent arguments. All data - is duplicated. */ - -SilcPublicKey silc_pkcs_public_key_alloc(const char *name, - const char *identifier, - const unsigned char *pk, - SilcUInt32 pk_len) +SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type, + unsigned char *key, + SilcUInt32 key_len, + SilcPrivateKey *ret_private_key) { - SilcPublicKey public_key; - char *tmp = NULL; - - public_key = silc_calloc(1, sizeof(*public_key)); - public_key->name = strdup(name); - public_key->pk_len = pk_len; - public_key->pk = silc_memdup(pk, pk_len); - public_key->pk_type = SILC_SKE_PK_TYPE_SILC; - - if (!silc_utf8_valid(identifier, strlen(identifier))) { - int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0); - tmp = silc_calloc(len + 1, sizeof(*tmp)); - silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len); - identifier = tmp; - } - - public_key->identifier = strdup(identifier); - public_key->len = 2 + strlen(name) + 2 + strlen(identifier) + pk_len; - silc_free(tmp); + const SilcPKCSObject *pkcs; + SilcPrivateKey private_key; - return public_key; -} + if (!ret_private_key) + return FALSE; -/* Free's public key */ + /* Allocate private key context */ + private_key = silc_calloc(1, sizeof(*private_key)); + if (!private_key) + return FALSE; -void silc_pkcs_public_key_free(SilcPublicKey public_key) -{ - if (public_key) { - silc_free(public_key->name); - silc_free(public_key->identifier); - silc_free(public_key->pk); - silc_free(public_key); + private_key->pkcs = pkcs = silc_pkcs_find_pkcs(type); + if (!private_key->pkcs) { + silc_free(private_key); + return FALSE; } -} -/* Allocates SILC private key formed from sent arguments. All data is - duplicated. */ - -SilcPrivateKey silc_pkcs_private_key_alloc(const char *name, - const unsigned char *prv, - SilcUInt32 prv_len) -{ - SilcPrivateKey private_key; + /* Import the PKCS private key */ + if (!pkcs->import_private_key(key, key_len, &private_key->private_key)) { + silc_free(private_key); + return FALSE; + } - private_key = silc_calloc(1, sizeof(*private_key)); - private_key->name = strdup(name); - private_key->prv_len = prv_len; - private_key->prv = silc_memdup(prv, prv_len); + *ret_private_key = private_key; - return private_key; + return TRUE; } -/* Free's private key */ +/* Return key length */ -void silc_pkcs_private_key_free(SilcPrivateKey private_key) +SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key) { - if (private_key) { - silc_free(private_key->name); - if (private_key->prv) { - memset(private_key->prv, 0, private_key->prv_len); - silc_free(private_key->prv); - } - silc_free(private_key); - } + return private_key->pkcs->private_key_bitlen(private_key->private_key); } -/* Encodes SILC style public key from SilcPublicKey. Returns the encoded - data. */ +/* Frees the private key */ -unsigned char * -silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len) +void silc_pkcs_private_key_free(SilcPrivateKey private_key) { - return silc_pkcs_public_key_data_encode(public_key->pk, - public_key->pk_len, - public_key->name, - public_key->identifier, len); + private_key->pkcs->private_key_free(private_key->private_key); } -/* Encodes SILC style public key. Returns the encoded data. */ +/* Encrypts */ -unsigned char * -silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len, - char *pkcs, char *identifier, - SilcUInt32 *len) +SilcBool silc_pkcs_encrypt(SilcPublicKey public_key, + unsigned char *src, SilcUInt32 src_len, + unsigned char *dst, SilcUInt32 dst_size, + SilcUInt32 *dst_len) { - SilcBuffer buf; - unsigned char *ret; - SilcUInt32 totlen; - - totlen = 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len; - buf = silc_buffer_alloc_size(totlen + 4); - if (!buf) - return NULL; - - silc_buffer_format(buf, - SILC_STR_UI_INT(totlen), - SILC_STR_UI_SHORT(strlen(pkcs)), - SILC_STR_UI32_STRING(pkcs), - SILC_STR_UI_SHORT(strlen(identifier)), - SILC_STR_UI32_STRING(identifier), - SILC_STR_UI_XNSTRING(pk, pk_len), - SILC_STR_END); - - ret = silc_buffer_steal(buf, len); - silc_buffer_free(buf); - return ret; + return public_key->pkcs->encrypt(public_key->public_key, src, src_len, + dst, dst_size, dst_len); } -/* Decodes SILC style public key. Returns TRUE if the decoding was - successful. Allocates new public key as well. */ +/* Decrypts */ -SilcBool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len, - SilcPublicKey *public_key) +SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key, + unsigned char *src, SilcUInt32 src_len, + unsigned char *dst, SilcUInt32 dst_size, + SilcUInt32 *dst_len) { - SilcBufferStruct buf; - SilcPKCS alg; - SilcUInt16 pkcs_len, identifier_len; - SilcUInt32 totlen, key_len; - unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL; - int ret; - - silc_buffer_set(&buf, data, data_len); - - /* Get length */ - ret = silc_buffer_unformat(&buf, - SILC_STR_UI_INT(&totlen), - SILC_STR_END); - if (ret == -1) - return FALSE; - -#if 1 /* Backwards support, remove! */ - if (totlen == data_len) - totlen -= 4; -#endif - - if (totlen + 4 != data_len) - return FALSE; - - /* Get algorithm name and identifier */ - silc_buffer_pull(&buf, 4); - ret = - silc_buffer_unformat(&buf, - SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len), - SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len), - SILC_STR_END); - if (ret == -1) - goto err; - - if (pkcs_len < 1 || identifier_len < 3 || - pkcs_len + identifier_len > totlen) - goto err; - - /* See if we support this algorithm (check only if PKCS are registered) */ - if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) { - SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name)); - goto err; - } - - /* Protocol says that at least UN and HN must be provided as identifier, - check for these. */ - if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) { - SILC_LOG_DEBUG(("The public does not have the required UN= and HN= " - "identifiers")); - goto err; - } - - /* Get key data. We assume that rest of the buffer is key data. */ - silc_buffer_pull(&buf, 2 + pkcs_len + 2 + identifier_len); - key_len = silc_buffer_len(&buf); - ret = silc_buffer_unformat(&buf, - SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len), - SILC_STR_END); - if (ret == -1) - goto err; - - /* Try to set the key. If this fails the key must be malformed. This - code assumes that the PKCS routine checks the format of the key. - (check only if PKCS are registered) */ - if (SILC_PKCS_LIST) { - silc_pkcs_alloc(pkcs_name, SILC_PKCS_SILC, &alg); - if (!alg->pkcs->set_public_key(alg->context, key_data, key_len)) - goto err; - silc_pkcs_free(alg); - } - - if (public_key) { - *public_key = silc_calloc(1, sizeof(**public_key)); - (*public_key)->len = totlen; - (*public_key)->name = pkcs_name; - (*public_key)->identifier = ident; - (*public_key)->pk = key_data; - (*public_key)->pk_len = key_len; - (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC; - } - - return TRUE; - - err: - silc_free(pkcs_name); - silc_free(ident); - silc_free(key_data); - return FALSE; + return private_key->pkcs->decrypt(private_key->private_key, src, src_len, + dst, dst_size, dst_len); } -/* Encodes Public Key Payload for transmitting public keys and certificates. */ +/* Generates signature */ -SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key) +SilcBool silc_pkcs_sign(SilcPrivateKey private_key, + unsigned char *src, SilcUInt32 src_len, + unsigned char *dst, SilcUInt32 dst_size, + SilcUInt32 *dst_len, SilcHash hash) { - SilcBuffer buffer; - unsigned char *pk; - SilcUInt32 pk_len; - - if (!public_key) - return NULL; - - pk = silc_pkcs_public_key_encode(public_key, &pk_len); - if (!pk) - return NULL; - - buffer = silc_buffer_alloc_size(4 + pk_len); - if (!buffer) { - silc_free(pk); - return NULL; - } - - silc_buffer_format(buffer, - SILC_STR_UI_SHORT(pk_len), - SILC_STR_UI_SHORT(public_key->pk_type), - SILC_STR_UI_XNSTRING(pk, pk_len), - SILC_STR_END); - - silc_free(pk); - return buffer; + return private_key->pkcs->sign(private_key->private_key, src, src_len, + dst, dst_size, dst_len, hash); } -/* Decode Public Key Payload and decodes the public key inside it to - to `payload'. */ +/* Verifies signature */ -SilcBool silc_pkcs_public_key_payload_decode(unsigned char *data, - SilcUInt32 data_len, - SilcPublicKey *public_key) +SilcBool silc_pkcs_verify(SilcPublicKey public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, SilcHash hash) { - SilcBufferStruct buf; - SilcUInt16 pk_len, pk_type; - unsigned char *pk; - int ret; - - if (!public_key) - return FALSE; - - silc_buffer_set(&buf, data, data_len); - ret = silc_buffer_unformat(&buf, - SILC_STR_UI_SHORT(&pk_len), - SILC_STR_UI_SHORT(&pk_type), - SILC_STR_END); - if (ret < 0 || pk_len > data_len - 4) - return FALSE; - - /* For now we support only SILC public keys */ - if (pk_type != SILC_SKE_PK_TYPE_SILC) - return FALSE; - - silc_buffer_pull(&buf, 4); - ret = silc_buffer_unformat(&buf, - SILC_STR_UI_XNSTRING(&pk, pk_len), - SILC_STR_END); - silc_buffer_push(&buf, 4); - if (ret < 0) - return FALSE; - - if (!silc_pkcs_public_key_decode(pk, pk_len, public_key)) - return FALSE; - (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC; - - return TRUE; + return public_key->pkcs->verify(public_key->public_key, signature, + signature_len, data, data_len, hash); } /* Compares two public keys and returns TRUE if they are same key, and @@ -920,18 +613,10 @@ SilcBool silc_pkcs_public_key_payload_decode(unsigned char *data, SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2) { - if (key1 == key2) - return TRUE; - - if (key1->len == key2->len && - key1->name && key2->name && key1->identifier && key2->identifier && - !strcmp(key1->name, key2->name) && - !strcmp(key1->identifier, key2->identifier) && - !memcmp(key1->pk, key2->pk, key1->pk_len) && - key1->pk_len == key2->pk_len) - return TRUE; + if (key1->pkcs->type != key2->pkcs->type) + return FALSE; - return FALSE; + return key1->pkcs->public_key_compare(key1->public_key, key2->public_key); } /* Copies the public key indicated by `public_key' and returns new allocated @@ -943,604 +628,169 @@ SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key) if (!key) return NULL; - key->len = public_key->len; - key->name = silc_memdup(public_key->name, strlen(public_key->name)); - key->identifier = silc_memdup(public_key->identifier, - strlen(public_key->identifier)); - key->pk = silc_memdup(public_key->pk, public_key->pk_len); - key->pk_len = public_key->pk_len; - key->pk_type = public_key->pk_type; + key->pkcs = public_key->pkcs; + key->public_key = public_key->pkcs->public_key_copy(public_key->public_key); + if (!key->public_key) { + silc_free(key); + return NULL; + } return key; } -/* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */ - -unsigned char * -silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len) -{ - return silc_pkcs_private_key_data_encode(private_key->prv, - private_key->prv_len, - private_key->name, len); -} - -/* Encodes SILC private key. Returns the encoded data. */ +/* Loads any kind of public key */ -unsigned char * -silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len, - char *pkcs, SilcUInt32 *len) +SilcBool silc_pkcs_load_public_key(const char *filename, + SilcPublicKey *ret_public_key) { - SilcBuffer buf; - unsigned char *ret; - SilcUInt32 totlen; - - totlen = 2 + strlen(pkcs) + prv_len; - buf = silc_buffer_alloc_size(totlen); - if (!buf) - return NULL; - - silc_buffer_format(buf, - SILC_STR_UI_SHORT(strlen(pkcs)), - SILC_STR_UI32_STRING(pkcs), - SILC_STR_UI_XNSTRING(prv, prv_len), - SILC_STR_END); + unsigned char *data; + SilcUInt32 data_len; + SilcPublicKey public_key; + SilcPKCSType type; - ret = silc_buffer_steal(buf, len); - silc_buffer_free(buf); - return ret; -} + SILC_LOG_DEBUG(("Loading public key file '%s'", filename)); -/* Decodes SILC style private key. Returns TRUE if the decoding was - successful. Allocates new private key as well. */ + if (!ret_public_key) + return FALSE; -SilcBool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len, - SilcPrivateKey *private_key) -{ - SilcBufferStruct buf; - SilcPKCS alg; - SilcUInt16 pkcs_len; - SilcUInt32 key_len; - unsigned char *pkcs_name = NULL, *key_data = NULL; - int ret; - - silc_buffer_set(&buf, data, data_len); - - /* Get algorithm name and identifier */ - ret = - silc_buffer_unformat(&buf, - SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len), - SILC_STR_END); - if (ret == -1) { - SILC_LOG_DEBUG(("Cannot decode private key buffer")); - goto err; - } + data = silc_file_readfile(filename, &data_len); + if (!data) + return FALSE; - if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) { - SILC_LOG_DEBUG(("Malformed private key buffer")); - goto err; + /* Allocate public key context */ + *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key)); + if (!public_key) { + silc_free(data); + return FALSE; } - /* See if we support this algorithm (check only if PKCS are registered). */ - if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) { - SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name)); - goto err; - } + /* 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; - /* Get key data. We assume that rest of the buffer is key data. */ - silc_buffer_pull(&buf, 2 + pkcs_len); - key_len = silc_buffer_len(&buf); - ret = silc_buffer_unformat(&buf, - SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len), - SILC_STR_END); - if (ret == -1) - goto err; - - /* Try to set the key. If this fails the key must be malformed. This - code assumes that the PKCS routine checks the format of the key. - (check only if PKCS are registered) */ - if (SILC_PKCS_LIST) { - silc_pkcs_alloc(pkcs_name, SILC_PKCS_SILC, &alg); - if (!alg->pkcs->set_private_key(alg->context, key_data, key_len)) { - SILC_LOG_DEBUG(("Could not set private key data")); - goto err; - } - silc_pkcs_free(alg); - } + if (public_key->pkcs->import_public_key_file(data, data_len, + SILC_PKCS_FILE_BASE64, + &public_key->public_key)) + return TRUE; - if (private_key) { - *private_key = silc_calloc(1, sizeof(**private_key)); - (*private_key)->name = pkcs_name; - (*private_key)->prv = key_data; - (*private_key)->prv_len = key_len; + if (public_key->pkcs->import_public_key_file(data, data_len, + SILC_PKCS_FILE_BIN, + &public_key->public_key)) + return TRUE; } - return TRUE; - - err: - silc_free(pkcs_name); - silc_free(key_data); + silc_free(data); + silc_free(public_key); return FALSE; } -/* Internal routine to save public key */ +/* Saves public key into a file */ -static SilcBool silc_pkcs_save_public_key_internal(const char *filename, - unsigned char *data, - SilcUInt32 data_len, - SilcUInt32 encoding) +SilcBool silc_pkcs_save_public_key(const char *filename, + SilcPublicKey public_key, + SilcPKCSFileEncoding encoding) { - SilcBuffer buf; - SilcUInt32 len; - unsigned char *tmp = NULL; - - switch(encoding) { - case SILC_PKCS_FILE_BIN: - break; - case SILC_PKCS_FILE_PEM: - tmp = data = silc_pem_encode_file(data, data_len); - data_len = strlen(data); - break; - } + unsigned char *data; + SilcUInt32 data_len; - len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) + - strlen(SILC_PKCS_PUBLIC_KEYFILE_END)); - buf = silc_buffer_alloc_size(len); - if (!buf) { - silc_free(tmp); + /* Export the public key file */ + data = public_key->pkcs->export_public_key_file(public_key->public_key, + encoding, &data_len); + if (!data) return FALSE; - } - - silc_buffer_format(buf, - SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN), - SILC_STR_UI_XNSTRING(data, data_len), - SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END), - SILC_STR_END); - /* Save into file */ - if (silc_file_writefile(filename, buf->data, silc_buffer_len(buf))) { - silc_free(tmp); - silc_buffer_free(buf); + /* Write to file */ + if (silc_file_writefile(filename, data, data_len)) { + silc_free(data); return FALSE; } - silc_free(tmp); - silc_buffer_free(buf); + silc_free(data); return TRUE; } -/* Saves public key into file */ +/* Loads any kind of private key */ -SilcBool silc_pkcs_save_public_key(const char *filename, SilcPublicKey public_key, - SilcUInt32 encoding) +SilcBool silc_pkcs_load_private_key(const char *filename, + const unsigned char *passphrase, + SilcUInt32 passphrase_len, + SilcPrivateKey *ret_private_key) { unsigned char *data; SilcUInt32 data_len; - SilcBool ret; - - data = silc_pkcs_public_key_encode(public_key, &data_len); - ret = silc_pkcs_save_public_key_internal(filename, data, data_len, - encoding); - silc_free(data); - return ret; -} - -/* Saves public key into file */ - -SilcBool silc_pkcs_save_public_key_data(const char *filename, unsigned char *data, - SilcUInt32 data_len, SilcUInt32 encoding) -{ - return silc_pkcs_save_public_key_internal(filename, data, data_len, - encoding); -} - -#define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531 - -/* Internal routine to save private key. */ - -static SilcBool silc_pkcs_save_private_key_internal(const char *filename, - unsigned char *data, - SilcUInt32 data_len, - unsigned char *key, - SilcUInt32 key_len, - SilcUInt32 encoding) -{ - SilcCipher aes; - SilcHash sha1; - SilcHmac sha1hmac; - SilcBuffer buf, enc; - SilcUInt32 len, blocklen, padlen; - unsigned char tmp[32], keymat[64]; - int i; + SilcPrivateKey private_key; + SilcPKCSType type; - memset(tmp, 0, sizeof(tmp)); - memset(keymat, 0, sizeof(keymat)); + SILC_LOG_DEBUG(("Loading private key file '%s'", filename)); - /* Allocate the AES cipher */ - if (!silc_cipher_alloc("aes-256-cbc", &aes)) { - SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered")); - return FALSE; - } - blocklen = silc_cipher_get_block_len(aes); - if (blocklen * 2 > sizeof(tmp)) + if (!ret_private_key) return FALSE; - /* Allocate SHA1 hash */ - if (!silc_hash_alloc("sha1", &sha1)) { - SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered")); - silc_cipher_free(aes); + data = silc_file_readfile(filename, &data_len); + if (!data) return FALSE; - } - /* Allocate HMAC */ - if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) { - SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered")); - silc_hash_free(sha1); - silc_cipher_free(aes); + /* Allocate private key context */ + *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key)); + if (!private_key) { + silc_free(data); return FALSE; } - /* Derive the encryption key from the provided key material. The key - is 256 bits length, and derived by taking hash of the data, then - re-hashing the data and the previous digest, and using the first and - second digest as the key. */ - silc_hash_init(sha1); - silc_hash_update(sha1, key, key_len); - silc_hash_final(sha1, keymat); - silc_hash_init(sha1); - silc_hash_update(sha1, key, key_len); - silc_hash_update(sha1, keymat, 16); - silc_hash_final(sha1, keymat + 16); - - /* Set the key to the cipher */ - silc_cipher_set_key(aes, keymat, 256); - - /* Encode the buffer to be encrypted. Add padding to it too, at least - block size of the cipher. */ - - /* Allocate buffer for encryption */ - len = silc_hmac_len(sha1hmac); - padlen = 16 + (16 - ((data_len + 4) % blocklen)); - enc = silc_buffer_alloc_size(4 + 4 + data_len + padlen + len); - if (!enc) { - silc_hmac_free(sha1hmac); - silc_hash_free(sha1); - silc_cipher_free(aes); - 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; - /* Generate padding */ - for (i = 0; i < padlen; i++) - tmp[i] = silc_rng_global_get_byte_fast(); - - /* Put magic number */ - SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data); - silc_buffer_pull(enc, 4); - - /* Encode the buffer */ - silc_buffer_format(enc, - SILC_STR_UI_INT(data_len), - SILC_STR_UI_XNSTRING(data, data_len), - SILC_STR_UI_XNSTRING(tmp, padlen), - SILC_STR_END); - - /* Encrypt. */ - silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len, - silc_cipher_get_iv(aes)); - - silc_buffer_push(enc, 4); - - /* Compute HMAC over the encrypted data and append the MAC to data. - The key is the first digest of the original key material. */ - data_len = silc_buffer_len(enc) - len; - silc_hmac_init_with_key(sha1hmac, keymat, 16); - silc_hmac_update(sha1hmac, enc->data, data_len); - silc_buffer_pull(enc, data_len); - silc_hmac_final(sha1hmac, enc->data, NULL); - silc_buffer_push(enc, data_len); - - /* Cleanup */ - memset(keymat, 0, sizeof(keymat)); - memset(tmp, 0, sizeof(tmp)); - silc_hmac_free(sha1hmac); - silc_hash_free(sha1); - silc_cipher_free(aes); - - data = enc->data; - data_len = silc_buffer_len(enc); - - switch (encoding) { - case SILC_PKCS_FILE_BIN: - break; - case SILC_PKCS_FILE_PEM: - data = silc_pem_encode_file(data, data_len); - data_len = strlen(data); - break; - } + if (private_key->pkcs->import_private_key_file(data, data_len, + passphrase, + passphrase_len, + SILC_PKCS_FILE_BIN, + &private_key->private_key)) + return TRUE; - /* Encode the data and save to file */ - len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) + - strlen(SILC_PKCS_PRIVATE_KEYFILE_END)); - buf = silc_buffer_alloc_size(len); - silc_buffer_format(buf, - SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN), - SILC_STR_UI_XNSTRING(data, data_len), - SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END), - SILC_STR_END); - - /* Save into a file */ - if (silc_file_writefile_mode(filename, buf->data, - silc_buffer_len(buf), 0600)) { - silc_buffer_clear(buf); - silc_buffer_free(buf); - silc_buffer_clear(enc); - silc_buffer_free(enc); - return FALSE; + if (private_key->pkcs->import_private_key_file(data, data_len, + passphrase, + passphrase_len, + SILC_PKCS_FILE_BASE64, + &private_key->private_key)) + return TRUE; } - silc_buffer_clear(buf); - silc_buffer_free(buf); - silc_buffer_clear(enc); - silc_buffer_free(enc); - return TRUE; + silc_free(data); + silc_free(private_key); + return FALSE; } -/* Saves private key into file. */ +/* Saves private key into a file */ SilcBool silc_pkcs_save_private_key(const char *filename, - SilcPrivateKey private_key, - unsigned char *passphrase, - SilcUInt32 passphrase_len, - SilcUInt32 encoding) + SilcPrivateKey private_key, + const unsigned char *passphrase, + SilcUInt32 passphrase_len, + SilcPKCSFileEncoding encoding, + SilcRng rng) { unsigned char *data; SilcUInt32 data_len; - SilcBool ret; - - data = silc_pkcs_private_key_encode(private_key, &data_len); - ret = silc_pkcs_save_private_key_internal(filename, data, data_len, - passphrase, passphrase_len, - encoding); - memset(data, 0, data_len); - silc_free(data); - return ret; -} - -/* Loads public key from file and allocates new public key. Returns TRUE - if loading was successful. */ - -SilcBool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key, - SilcUInt32 encoding) -{ - unsigned char *cp, *old, *data, byte; - SilcUInt32 i, data_len, len; - - SILC_LOG_DEBUG(("Loading public key `%s' with %s encoding", filename, - encoding == SILC_PKCS_FILE_PEM ? "Base64" : - encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn")); - old = data = silc_file_readfile(filename, &data_len); + /* Export the private key file */ + data = private_key->pkcs->export_private_key_file(private_key->private_key, + passphrase, + passphrase_len, + encoding, rng, &data_len); if (!data) return FALSE; - /* Check start of file and remove header from the data. */ - len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN); - cp = data; - for (i = 0; i < len; i++) { - byte = cp[0]; - cp++; - if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) { - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - } - data = cp; - - /* Decode public key */ - if (public_key) { - len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) + - strlen(SILC_PKCS_PUBLIC_KEYFILE_END)); - - switch(encoding) { - case SILC_PKCS_FILE_BIN: - break; - case SILC_PKCS_FILE_PEM: - data = silc_pem_decode(data, len, &len); - memset(old, 0, data_len); - silc_free(old); - old = data; - data_len = len; - break; - } - - if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) { - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - } - - memset(old, 0, data_len); - silc_free(old); - return TRUE; -} - -/* Load private key from file and allocates new private key. Returns TRUE - if loading was successful. */ - -SilcBool silc_pkcs_load_private_key(const char *filename, - SilcPrivateKey *private_key, - unsigned char *passphrase, - SilcUInt32 passphrase_len, - SilcUInt32 encoding) -{ - SilcCipher aes; - SilcHash sha1; - SilcHmac sha1hmac; - SilcUInt32 blocklen; - unsigned char tmp[32], keymat[64]; - unsigned char *cp, *old, *data, byte; - SilcUInt32 i, data_len, len, magic, mac_len; - - SILC_LOG_DEBUG(("Loading private key `%s' with %s encoding", filename, - encoding == SILC_PKCS_FILE_PEM ? "Base64" : - encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn")); - - old = data = silc_file_readfile(filename, &data_len); - if (!data) + /* Write to file */ + if (silc_file_writefile(filename, data, data_len)) { + silc_free(data); return FALSE; - - /* Check start of file and remove header from the data. */ - len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN); - cp = data; - for (i = 0; i < len; i++) { - byte = cp[0]; - cp++; - if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) { - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - } - data = cp; - - /* Decode private key */ - len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) + - strlen(SILC_PKCS_PRIVATE_KEYFILE_END)); - - switch(encoding) { - case SILC_PKCS_FILE_BIN: - break; - case SILC_PKCS_FILE_PEM: - data = silc_pem_decode(data, len, &len); - if (!data) { - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - break; } - memset(tmp, 0, sizeof(tmp)); - memset(keymat, 0, sizeof(keymat)); - - /* Private key files without the specific magic number are assumed - to be the old-style private keys that are not encrypted. */ - SILC_GET32_MSB(magic, data); - if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) { - SILC_LOG_DEBUG(("Private key does not have correct magic!")); - - /* Now decode the actual private key */ - if (!silc_pkcs_private_key_decode(data, len, private_key)) { - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - - memset(old, 0, data_len); - silc_free(old); - return TRUE; - } - - /* Allocate the AES cipher */ - if (!silc_cipher_alloc("aes-256-cbc", &aes)) { - SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered")); - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - blocklen = silc_cipher_get_block_len(aes); - if (blocklen * 2 > sizeof(tmp)) { - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - - /* Allocate SHA1 hash */ - if (!silc_hash_alloc("sha1", &sha1)) { - SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered")); - silc_cipher_free(aes); - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - - /* Allocate HMAC */ - if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) { - SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered")); - silc_hash_free(sha1); - silc_cipher_free(aes); - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - - /* Derive the decryption key from the provided key material. The key - is 256 bits length, and derived by taking hash of the data, then - re-hashing the data and the previous digest, and using the first and - second digest as the key. */ - silc_hash_init(sha1); - silc_hash_update(sha1, passphrase, passphrase_len); - silc_hash_final(sha1, keymat); - silc_hash_init(sha1); - silc_hash_update(sha1, passphrase, passphrase_len); - silc_hash_update(sha1, keymat, 16); - silc_hash_final(sha1, keymat + 16); - - /* Set the key to the cipher */ - silc_cipher_set_key(aes, keymat, 256); - - /* First, verify the MAC of the private key data */ - mac_len = silc_hmac_len(sha1hmac); - silc_hmac_init_with_key(sha1hmac, keymat, 16); - silc_hmac_update(sha1hmac, data, len - mac_len); - silc_hmac_final(sha1hmac, tmp, NULL); - if (memcmp(tmp, data + (len - mac_len), mac_len)) { - SILC_LOG_DEBUG(("Integrity check for private key failed")); - memset(keymat, 0, sizeof(keymat)); - memset(tmp, 0, sizeof(tmp)); - silc_hmac_free(sha1hmac); - silc_hash_free(sha1); - silc_cipher_free(aes); - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - data += 4; - len -= 4; - - /* Decrypt the private key buffer */ - silc_cipher_decrypt(aes, data, data, len - mac_len, NULL); - SILC_GET32_MSB(i, data); - if (i > len) { - SILC_LOG_DEBUG(("Bad private key length in buffer!")); - memset(keymat, 0, sizeof(keymat)); - memset(tmp, 0, sizeof(tmp)); - silc_hmac_free(sha1hmac); - silc_hash_free(sha1); - silc_cipher_free(aes); - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - data += 4; - len = i; - - /* Cleanup */ - memset(keymat, 0, sizeof(keymat)); - memset(tmp, 0, sizeof(tmp)); - silc_hmac_free(sha1hmac); - silc_hash_free(sha1); - silc_cipher_free(aes); - - /* Now decode the actual private key */ - if (!silc_pkcs_private_key_decode(data, len, private_key)) { - memset(old, 0, data_len); - silc_free(old); - return FALSE; - } - - memset(old, 0, data_len); - silc_free(old); + silc_free(data); return TRUE; } diff --git a/lib/silccrypt/silcpkcs.h b/lib/silccrypt/silcpkcs.h index eeaa2405..b18747fb 100644 --- a/lib/silccrypt/silcpkcs.h +++ b/lib/silccrypt/silcpkcs.h @@ -17,47 +17,28 @@ */ -#ifndef SILCPKCS_H -#define SILCPKCS_H - /****h* silccrypt/SILC PKCS Interface * * DESCRIPTION * - * This is the interface for public key cryptosystems, and various - * utility functions related to public keys and private keys. This - * interface also defines the actual PKCS objects, public keys and - * private keys. The interface is generic PKCS interface, which has - * capability of supporting any kind of public key algorithm. This - * interface also implements the SILC Public Key and routines for - * encoding and decoding SILC Public Key (as defined by the SILC - * protocol specification). Interface or encrypting, decrypting, - * producing digital signatures and verifying digital signatures are - * also defined in this header. + * SILC PKCS API provides generic interface for performing various + * public key cryptography related operations with different types of + * public and private keys. Support for loading and saving of different + * types of public key and private keys are also provided. * ***/ -/****s* silccrypt/SilcPKCSAPI/SilcPKCS - * - * NAME - * - * typedef struct SilcPKCSStruct *SilcPKCS; - * - * DESCRIPTION - * - * This context is the actual PKCS context and is allocated - * by silc_pkcs_alloc and given as argument usually to all - * silc_pkcs_* functions. It is freed by the silc_pkcs_free - * function. - * - ***/ -typedef struct SilcPKCSStruct *SilcPKCS; +#ifndef SILCPKCS_H +#define SILCPKCS_H + +/* Forward declarations */ +typedef struct SilcPKCSObjectStruct SilcPKCSObject; /****d* silccrypt/SilcPKCSAPI/SilcPKCSType * * NAME * - * typedef enum { ... } SilcPKCSType + * typedef enum { ... } SilcPKCSType; * * DESCRIPTION * @@ -67,7 +48,7 @@ typedef struct SilcPKCSStruct *SilcPKCS; * SOURCE */ typedef enum { - SILC_PKCS_SILC = 1, /* SILC PKCS (mandatory) */ + SILC_PKCS_SILC = 1, /* SILC PKCS */ SILC_PKCS_SSH2 = 2, /* SSH2 PKCS (not supported) */ SILC_PKCS_X509V3 = 3, /* X.509v3 PKCS (not supported) */ SILC_PKCS_OPENPGP = 4, /* OpenPGP PKCS (not supported) */ @@ -75,190 +56,242 @@ typedef enum { } SilcPKCSType; /***/ -/* The default SILC PKCS (Public Key Cryptosystem) object to represent - any PKCS in SILC. */ -typedef struct SilcPKCSObjectStruct { - char *name; - SilcPKCSType type; - int (*init)(void *, SilcUInt32, SilcRng); - void (*clear_keys)(void *); - unsigned char *(*get_public_key)(void *, SilcUInt32 *); - unsigned char *(*get_private_key)(void *, SilcUInt32 *); - SilcUInt32 (*set_public_key)(void *, unsigned char *, SilcUInt32); - SilcUInt32 (*set_private_key)(void *, unsigned char *, SilcUInt32); - SilcUInt32 (*context_len)(); - int (*encrypt)(void *, unsigned char *, SilcUInt32, - unsigned char *, SilcUInt32 *); - int (*decrypt)(void *, unsigned char *, SilcUInt32, - unsigned char *, SilcUInt32 *); - int (*sign)(void *, unsigned char *, SilcUInt32, - unsigned char *, SilcUInt32 *); - int (*verify)(void *, unsigned char *, SilcUInt32, - unsigned char *, SilcUInt32); -} SilcPKCSObject; - /****s* silccrypt/SilcPKCSAPI/SilcPublicKey * * NAME * - * typedef struct { ... } *SilcPublicKey, SilcPublicKeyStruct; + * typedef struct { ... } *SilcPublicKey; * * DESCRIPTION * - * SILC style public key object. Public key is read from file to this - * object. Public keys received from network must be in this format as - * well. The format is defined by the SILC protocol specification. - * This object is allocated by silc_pkcs_public_key_alloc and freed - * by silc_pkcs_public_key_free. The object is given as argument to - * all silc_pkcs_public_key_* functions. + * This context represents any kind of PKCS public key. It can be + * allocated by silc_pkcs_public_key_alloc and is freed by the + * silc_pkcs_public_key_free. The PKCS specific public key context + * can be retrieved by calling silc_pkcs_get_context. * * SOURCE */ typedef struct { - SilcUInt16 pk_type; /* Public key type (SilcSKEPKType) */ - SilcUInt32 len; - char *name; - char *identifier; - unsigned char *pk; - SilcUInt32 pk_len; -} *SilcPublicKey, SilcPublicKeyStruct; + const SilcPKCSObject *pkcs; /* PKCS */ + void *public_key; /* PKCS specific public key */ +} *SilcPublicKey; /***/ -/****s* silccrypt/SilcPKCSAPI/SilcPublicKeyIdentifier +/****s* silccrypt/SilcPKCSAPI/SilcPrivateKey * * NAME * - * typedef struct { ... } *SilcPublicKeyIdentifier, - * SilcPublicKeyIdentifierStruct; + * typedef struct { ... } *SilcPrivateKey; * * DESCRIPTION * - * Decoded SILC Public Key identifier. Note that some of the fields - * may be NULL. This context is allocated by the function - * silc_pkcs_decode_identifier and freed by silc_pkcs_free_identifier. - * The identifier in SilcPublicKey is the `identifier' field, which - * can be given as argument to silc_pkcs_decode_identifier. + * This context represents any kind of PKCS private key. * * SOURCE */ typedef struct { - char *username; - char *host; - char *realname; - char *email; - char *org; - char *country; -} *SilcPublicKeyIdentifier, SilcPublicKeyIdentifierStruct; + const SilcPKCSObject *pkcs; /* PKCS */ + void *private_key; /* PKCS specific private key */ +} *SilcPrivateKey; /***/ -/****s* silccrypt/SilcPKCSAPI/SilcPrivateKey +/****d* silccrypt/SilcPKCSAPI/SilcPKCSFileEncoding * * NAME * - * typedef struct { ... } *SilcPrivateKey, SilcPrivateKeyStruct; + * typedef enum { ... } SilcPKCSType * * DESCRIPTION * - * SILC style private key object. Public key is read from file to this - * object. This object is allocated by silc_pkcs_private_key_alloc and - * freed by silc_pkcs_private_key_free. The object is given as argument - * to all silc_pkcs_private_key_* functions. + * Public and private key file encoding types. * - ***/ + * SOURCE + */ +typedef enum { + SILC_PKCS_FILE_BIN, /* Binary encoding */ + SILC_PKCS_FILE_BASE64 /* Base64 encoding */ +} SilcPKCSFileEncoding; +/***/ + +/* The PKCS Algorithm object to represent any PKCS algorithm. */ typedef struct { + /* Algorithm name and scheme */ char *name; - unsigned char *prv; - SilcUInt32 prv_len; -} *SilcPrivateKey, SilcPrivateKeyStruct; - -/* Public and private key file headers */ -#define SILC_PKCS_PUBLIC_KEYFILE_BEGIN "-----BEGIN SILC PUBLIC KEY-----\n" -#define SILC_PKCS_PUBLIC_KEYFILE_END "\n-----END SILC PUBLIC KEY-----\n" -#define SILC_PKCS_PRIVATE_KEYFILE_BEGIN "-----BEGIN SILC PRIVATE KEY-----\n" -#define SILC_PKCS_PRIVATE_KEYFILE_END "\n-----END SILC PRIVATE KEY-----\n" + char *scheme; + + /* Supported hash functions, comma separated list */ + char *hash; + + /* Generate new key pair. Returns PKCS algorithm specific public key + and private key contexts. */ + SilcBool (*generate_key)(SilcUInt32 keylen, + SilcRng rng, + void **ret_public_key, + void **ret_private_key); + + /* Public key routines */ + SilcBool (*import_public_key)(unsigned char *key, + SilcUInt32 key_len, + void **ret_public_key); + unsigned char *(*export_public_key)(void *public_key, + SilcUInt32 *ret_len); + SilcUInt32 (*public_key_bitlen)(void *public_key); + void *(*public_key_copy)(void *public_key); + SilcBool (*public_key_compare)(void *key1, void *key2); + void (*public_key_free)(void *public_key); + + /* Private key routines */ + SilcBool (*import_private_key)(unsigned char *key, + SilcUInt32 key_len, + void **ret_private_key); + unsigned char *(*export_private_key)(void *private_key, + SilcUInt32 *ret_len); + SilcUInt32 (*private_key_bitlen)(void *public_key); + void (*private_key_free)(void *private_key); + + /* Encrypt and decrypt operations */ + SilcBool (*encrypt)(void *public_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len); + SilcBool (*decrypt)(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len); + + /* Signature and verification operations */ + SilcBool (*sign)(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *signature, + SilcUInt32 signature_size, + SilcUInt32 *ret_signature_len, + SilcHash hash); + SilcBool (*verify)(void *public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, + SilcHash hash); +} SilcPKCSAlgorithm; + +/* The PKCS (Public Key Cryptosystem) object to represent any PKCS. */ +struct SilcPKCSObjectStruct { + /* PKCS type */ + SilcPKCSType type; -/* Public and private key file encoding types */ -#define SILC_PKCS_FILE_BIN 0 -#define SILC_PKCS_FILE_PEM 1 + /* Public key routines */ + + /* Returns PKCS algorithm context from public key */ + const SilcPKCSAlgorithm *(*get_algorithm)(void *public_key); + + /* Imports from public key file */ + SilcBool (*import_public_key_file)(unsigned char *filedata, + SilcUInt32 filedata_len, + SilcPKCSFileEncoding encoding, + void **ret_public_key); + + /* Imports from public key binary data */ + SilcBool (*import_public_key)(unsigned char *key, + SilcUInt32 key_len, + void **ret_public_key); + + /* Exports public key to file */ + unsigned char *(*export_public_key_file)(void *public_key, + SilcPKCSFileEncoding encoding, + SilcUInt32 *ret_len); + + /* Export public key as binary data */ + unsigned char *(*export_public_key)(void *public_key, + SilcUInt32 *ret_len); + + /* Returns key length in bits */ + SilcUInt32 (*public_key_bitlen)(void *public_key); + + /* Copy public key */ + void *(*public_key_copy)(void *public_key); + + /* Compares public keys */ + SilcBool (*public_key_compare)(void *key1, void *key2); + + /* Free public key */ + void (*public_key_free)(void *public_key); + + /* Private key routines */ + + /* Imports from private key file */ + SilcBool (*import_private_key_file)(unsigned char *filedata, + SilcUInt32 filedata_len, + const char *passphrase, + SilcUInt32 passphrase_len, + SilcPKCSFileEncoding encoding, + void **ret_private_key); + + /* Imports from private key binary data */ + SilcBool (*import_private_key)(unsigned char *key, + SilcUInt32 key_len, + void **ret_private_key); + + /* Exports private key to file */ + unsigned char *(*export_private_key_file)(void *private_key, + const char *passphrase, + SilcUInt32 passphrase_len, + SilcPKCSFileEncoding encoding, + SilcRng rng, + SilcUInt32 *ret_len); + + /* Export private key as binary data */ + unsigned char *(*export_private_key)(void *private_key, + SilcUInt32 *ret_len); + + /* Returns key length in bits */ + SilcUInt32 (*private_key_bitlen)(void *private_key); + + /* Free private key */ + void (*private_key_free)(void *private_key); + + /* Encrypt and decrypt operations */ + SilcBool (*encrypt)(void *public_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len); + SilcBool (*decrypt)(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len); + + /* Signature and verification operations */ + SilcBool (*sign)(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *signature, + SilcUInt32 signature_size, + SilcUInt32 *ret_signature_len, + SilcHash hash); + SilcBool (*verify)(void *public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, + SilcHash hash); +}; /* Marks for all PKCS in silc. This can be used in silc_pkcs_unregister to unregister all PKCS at once. */ #define SILC_ALL_PKCS ((SilcPKCSObject *)1) +#define SILC_ALL_PKCS_ALG ((SilcPKCSAlgorithm *)1) -/* Static list of PKCS for silc_pkcs_register_default(). */ +/* Static lists of PKCS and PKCS algorithms. */ extern DLLAPI const SilcPKCSObject silc_default_pkcs[]; - -/* Default PKXS in the SILC protocol */ -#define SILC_DEFAULT_PKCS "rsa" - -/* Macros */ - -/* Macros used to implement the SILC PKCS API */ - -/* XXX: This needs slight redesigning. These needs to be made even - more generic. I don't like that the actual prime generation is done - in PKCS_API_INIT. The primes used in key generation should be sent - as argument to the init function. By doing this we would achieve - that PKCS could be used as SIM's. The only requirement would be - that they are compiled against GMP (well, actually even that would - not be a requirement, but the most generic case anyway). The new init - would look something like this: - - #define SILC_PKCS_API_INIT(pkcs) \ - inline int silc_##pkcs##_init(void *context, SilcUInt32 keylen, \ - void *p1, void *p2) - - Now we wouldn't have to send the SilcRng object since the primes are - provided as arguments. To send them as void * they could actually be - used as in anyway for real (MP_INT (SilcMPInt) or even something else - (the pointer could be kludged to be something else in the module)) - (Plus, the SilcRng object management in prime generation would be - simpler and better what it is now (in silcprimegen.c, that is)). -*/ - -#define SILC_PKCS_API_INIT(pkcs) \ -int silc_##pkcs##_init(void *context, SilcUInt32 keylen, \ - SilcRng rng) -#define SILC_PKCS_API_CLEAR_KEYS(pkcs) \ -void silc_##pkcs##_clear_keys(void *context) -#define SILC_PKCS_API_GET_PUBLIC_KEY(pkcs) \ -unsigned char *silc_##pkcs##_get_public_key(void *context, \ - SilcUInt32 *ret_len) -#define SILC_PKCS_API_GET_PRIVATE_KEY(pkcs) \ -unsigned char *silc_##pkcs##_get_private_key(void *context, \ - SilcUInt32 *ret_len) -#define SILC_PKCS_API_SET_PUBLIC_KEY(pkcs) \ -SilcUInt32 silc_##pkcs##_set_public_key(void *context, unsigned char *key_data, \ - SilcUInt32 key_len) -#define SILC_PKCS_API_SET_PRIVATE_KEY(pkcs) \ -SilcUInt32 silc_##pkcs##_set_private_key(void *context, unsigned char *key_data, \ - SilcUInt32 key_len) -#define SILC_PKCS_API_CONTEXT_LEN(pkcs) \ -SilcUInt32 silc_##pkcs##_context_len() -#define SILC_PKCS_API_ENCRYPT(pkcs) \ -int silc_##pkcs##_encrypt(void *context, \ - unsigned char *src, \ - SilcUInt32 src_len, \ - unsigned char *dst, \ - SilcUInt32 *dst_len) -#define SILC_PKCS_API_DECRYPT(pkcs) \ -int silc_##pkcs##_decrypt(void *context, \ - unsigned char *src, \ - SilcUInt32 src_len, \ - unsigned char *dst, \ - SilcUInt32 *dst_len) -#define SILC_PKCS_API_SIGN(pkcs) \ -int silc_##pkcs##_sign(void *context, \ - unsigned char *src, \ - SilcUInt32 src_len, \ - unsigned char *dst, \ - SilcUInt32 *dst_len) -#define SILC_PKCS_API_VERIFY(pkcs) \ -int silc_##pkcs##_verify(void *context, \ - unsigned char *signature, \ - SilcUInt32 signature_len, \ - unsigned char *data, \ - SilcUInt32 data_len) +extern DLLAPI const SilcPKCSAlgorithm silc_default_pkcs_alg[]; /* Prototypes */ @@ -294,75 +327,61 @@ SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs); ***/ SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_register_default - * - * SYNOPSIS - * - * SilcBool silc_pkcs_register_default(void); - * - * DESCRIPTION - * - * Registers all the default PKCS (all builtin PKCS). The application may - * use this to register the default PKCS if specific PKCS in any specific - * order is not wanted. Returns FALSE on error. - * - ***/ -SilcBool silc_pkcs_register_default(void); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_unregister_all +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_algorithm_register * * SYNOPSIS * - * SilcBool silc_pkcs_unregister_all(void); + * SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs); * * DESCRIPTION * - * Returns FALSE on error. + * Registers a new PKCS Algorithm into the SILC. This function is used + * at the initialization of the SILC. All registered PKCS algorithms + * should be unregistered with silc_pkcs_unregister. * ***/ -SilcBool silc_pkcs_unregister_all(void); +SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_alloc +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_algorithm_unregister * * SYNOPSIS * - * SilcBool silc_pkcs_alloc(const unsigned char *name, - * SilcPKCSType type, SilcPKCS *new_pkcs); + * SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs); * * DESCRIPTION * - * Allocates a new SilcPKCS object. The new allocated object is returned - * to the 'new_pkcs' argument. Returns FALSE on error. + * Unregister a PKCS from the SILC. Returns FALSE on error. * ***/ -SilcBool silc_pkcs_alloc(const unsigned char *name, - SilcPKCSType type, SilcPKCS *new_pkcs); +SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_free +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_register_default * * SYNOPSIS * - * void silc_pkcs_free(SilcPKCS pkcs); + * SilcBool silc_pkcs_register_default(void); * * DESCRIPTION * - * Frees the PKCS object. + * Registers all the default PKCS (all builtin PKCS) and PKCS algorithms. + * The application may use this to register the default PKCS if specific + * PKCS in any specific order is not wanted. Returns FALSE on error. * ***/ -void silc_pkcs_free(SilcPKCS pkcs); +SilcBool silc_pkcs_register_default(void); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_is_supported +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_unregister_all * * SYNOPSIS * - * SilcBool silc_pkcs_is_supported(const unsigned char *name); + * SilcBool silc_pkcs_unregister_all(void); * * DESCRIPTION * - * Returns TRUE if PKCS algorithm `name' is supported. + * Unregister all PKCS and PKCS algorithms. Returns FALSE on error. * ***/ -SilcBool silc_pkcs_is_supported(const unsigned char *name); +SilcBool silc_pkcs_unregister_all(void); /****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_supported * @@ -377,318 +396,126 @@ SilcBool silc_pkcs_is_supported(const unsigned char *name); ***/ char *silc_pkcs_get_supported(void); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_generate_key - * - * SYNOPSIS - * - * SilcBool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len, - * SilcRng rng); - * - * DESCRIPTION - * - * Generate new key pair into the `pkcs' context. Returns FALSE on error. - * If the `rng' is NULL global SILC RNG will be used. - * - ***/ -SilcBool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len, - SilcRng rng); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_key_len - * - * SYNOPSIS - * - * SilcUInt32 silc_pkcs_get_key_len(SilcPKCS self); - * - * DESCRIPTION - * - * Returns the length of the key in bits. - * - ***/ -SilcUInt32 silc_pkcs_get_key_len(SilcPKCS self); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_name - * - * SYNOPSIS - * - * const char *silc_pkcs_get_name(SilcPKCS pkcs); - * - * DESCRIPTION - * - * Returns PKCS name. - * - ***/ -const char *silc_pkcs_get_name(SilcPKCS pkcs); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_public_key - * - * SYNOPSIS - * - * unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len); - * - * DESCRIPTION - * - * Returns SILC style public key for the PKCS. Note that this is not - * the SILC Public Key, but the raw public key data from the PKCS. - * The caller must free the returned data. - * - ***/ -unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_private_key - * - * SYNOPSIS - * - * unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, - * SilcUInt32 *len); - * - * DESCRIPTION - * - * Returns SILC style private key. Note that this is not SilcPrivateKey - * but the raw private key bits from the PKCS. The caller must free the - * returned data and SHOULD zero the memory area before freeing. - * - ***/ -unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_set - * - * SYNOPSIS - * - * SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, - * SilcPublicKey public_key); - * - * DESCRIPTION - * - * Sets public key from SilcPublicKey. Returns the length of the key in - * bits. - * - ***/ -SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_data_set +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_find_pkcs * * SYNOPSIS * - * SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, - * unsigned char *pk, - * SilcUInt32 pk_len); + * const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPKCSType type); * * DESCRIPTION * - * Sets public key from data. Returns the length of the key. + * Finds PKCS context by the PKCS type. * ***/ -SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk, - SilcUInt32 pk_len); +const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_set +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_find_algorithm * * SYNOPSIS * - * SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, - * SilcPrivateKey private_key); + * const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm, + * const char *scheme); * * DESCRIPTION * - * Sets private key from SilcPrivateKey. Returns the length of the key - * in bits. + * Finds PKCS algorithm context by the algorithm name `algorithm' and + * the algorithm scheme `scheme'. The `scheme' may be NULL. * ***/ -SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, - SilcPrivateKey private_key); +const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm, + const char *scheme); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_data_set +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_pkcs * * SYNOPSIS * - * SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, - * unsigned char *prv, - * SilcUInt32 prv_len); + * const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPublicKey public_key); * * DESCRIPTION * - * Sets private key from data. Returns the length of the key. + * Returns the PKCS object from `public_key'. * ***/ -SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv, - SilcUInt32 prv_len); +const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPublicKey public_key); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_encrypt +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_algorithm * * SYNOPSIS * - * SilcBool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, - * SilcUInt32 src_len, unsigned char *dst, - * SilcUInt32 *dst_len); + * const SilcPKCSObject *silc_pkcs_get_algorithm(SilcPublicKey public_key); * * DESCRIPTION * - * Encrypts. Returns FALSE on error. + * Returns the PKCS algorithm object from `public_key'. * ***/ -SilcBool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, - SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 *dst_len); +const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(SilcPublicKey public_key); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_decrypt - * - * SYNOPSIS - * - * SilcBool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, - * SilcUInt32 src_len, unsigned char *dst, - * SilcUInt32 *dst_len); - * - * DESCRIPTION - * - * Decrypts. Returns FALSE on error. - * - ***/ -SilcBool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, - SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 *dst_len); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign - * - * SYNOPSIS - * - * SilcBool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, - * SilcUInt32 src_len, unsigned char *dst, - * SilcUInt32 *dst_len); - * - * DESCRIPTION - * - * Generates signature. Returns FALSE on error. - * - ***/ -SilcBool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 *dst_len); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify - * - * SYNOPSIS - * - * SilcBool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, - * SilcUInt32 signature_len, unsigned char *data, - * SilcUInt32 data_len); - * - * DESCRIPTION - * - * Verifies signature. Returns FALSE on error. The 'signature' is - * verified against the 'data'. - * - ***/ -SilcBool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, - SilcUInt32 signature_len, unsigned char *data, - SilcUInt32 data_len); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign_with_hash - * - * SYNOPSIS - * - * SilcBool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash, - * unsigned char *src, SilcUInt32 src_len, - * unsigned char *dst, SilcUInt32 *dst_len); - * - * DESCRIPTION - * - * Generates signature with hash. The hash is signed. Returns FALSE on - * error. - * - ***/ -SilcBool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash, - unsigned char *src, SilcUInt32 src_len, - unsigned char *dst, SilcUInt32 *dst_len); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify_with_hash +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_name * * SYNOPSIS * - * SilcBool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, - * unsigned char *signature, - * SilcUInt32 signature_len, - * unsigned char *data, - * SilcUInt32 data_len); + * const char *silc_pkcs_get_name(SilcPublicKey public_key) * * DESCRIPTION * - * Verifies signature with hash. The `data' is hashed and verified against - * the `signature'. Returns FALSE on error. + * Returns PKCS algorithm name from the public key. * ***/ -SilcBool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, - unsigned char *signature, - SilcUInt32 signature_len, - unsigned char *data, - SilcUInt32 data_len); +const char *silc_pkcs_get_name(SilcPublicKey public_key); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_encode_identifier +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_type * * SYNOPSIS * - * char *silc_pkcs_encode_identifier(char *username, char *host, - * char *realname, char *email, - * char *org, char *country); + * SilcPKCSType silc_pkcs_get_type(SilcPublicKey public_key); * * DESCRIPTION * - * Encodes and returns SILC public key identifier. If some of the - * arguments is NULL those are not encoded into the identifier string. - * Protocol says that at least username and host must be provided. + * Returns PKCS type from the public key. * ***/ -char *silc_pkcs_encode_identifier(char *username, char *host, char *realname, - char *email, char *org, char *country); +SilcPKCSType silc_pkcs_get_type(SilcPublicKey public_key); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_decode_identifier +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_context * * SYNOPSIS * - * SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier); + * void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key); * * DESCRIPTION * - * Decodes the provided `identifier' and returns allocated context for - * the identifier. + * Returns the internal PKCS `type' specific public key context from the + * `public_key'. The caller needs to explicitly type cast it to correct + * type. Returns NULL on error. * - ***/ -SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_free_identifier - * - * SYNOPSIS - * - * void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier); - * - * DESCRIPTION - * - * Frees decoded public key identifier context. Call this to free the - * context returned by the silc_pkcs_decode_identifier. + * For SILC_PKCS_SILC the returned context is SilcSILCPublicKey. * ***/ -void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier); +void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key); /****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_alloc * * SYNOPSIS * - * SilcPublicKey silc_pkcs_public_key_alloc(const char *name, - * const char *identifier, - * const unsigned char *pk, - * SilcUInt32 pk_len); + * SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type, + * unsigned char *key, + * SilcUInt32 key_len + * SilcPublicKey *ret_public_key); * * DESCRIPTION * - * Allocates SILC style public key formed from sent arguments. The - * 'name' is the algorithm (PKCS) name, the 'identifier' is the public - * key identifier generated with silc_pkcs_encode_identifier, and the - * 'pk' and 'pk_len' are the raw public key data returned for example - * by silc_pkcs_get_public_key. + * Allocates SilcPublicKey of the type of `type' from the key data + * `key' of length of `key_len' bytes. Returns FALSE if the `key' + * is malformed or unsupported public key type. This function can be + * used to create public key from any kind of PKCS public keys that + * the implementation supports. * ***/ -SilcPublicKey silc_pkcs_public_key_alloc(const char *name, - const char *identifier, - const unsigned char *pk, - SilcUInt32 pk_len); +SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type, + unsigned char *key, + SilcUInt32 key_len, + SilcPublicKey *ret_public_key); /****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_free * @@ -698,304 +525,278 @@ SilcPublicKey silc_pkcs_public_key_alloc(const char *name, * * DESCRIPTION * - * Frees public key and all data in it. + * Frees the public key. * ***/ void silc_pkcs_public_key_free(SilcPublicKey public_key); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_alloc +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_export * * SYNOPSIS * - * SilcPrivateKey silc_pkcs_private_key_alloc(const char *name, - * const unsigned char *prv, - * SilcUInt32 prv_len); + * unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key, + * SilcUInt32 *ret_len); * * DESCRIPTION * - * Allocates SILC private key formed from sent arguments. The 'name' - * is the algorithm name, and the 'prv' and 'prv_len' are the raw - * private key bits returned by silc_pkcs_get_private_key. + * Encodes the `public_key' into a binary format and returns it. Returns + * NULL on error. Caller must free the returned buffer. * ***/ -SilcPrivateKey silc_pkcs_private_key_alloc(const char *name, - const unsigned char *prv, - SilcUInt32 prv_len); +unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key, + SilcUInt32 *ret_len); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_free +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_get_len * * SYNOPSIS * - * void silc_pkcs_private_key_free(SilcPrivateKey private_key); + * SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key); * * DESCRIPTION * - * Frees private key and all data in it. The private key is zeroed - * before it is freed. + * Returns the key length in bits from the public key. * ***/ -void silc_pkcs_private_key_free(SilcPrivateKey private_key); +SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_encode +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_compare * * SYNOPSIS * - * unsigned char * - * silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len); + * SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, + * SilcPublicKey key2); * * DESCRIPTION * - * Encodes SILC style public key from SilcPublicKey. Returns the encoded - * data. + * Compares two public keys and returns TRUE if they are same key, and + * FALSE if they are not same. * ***/ -unsigned char * -silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len); +SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_data_encode +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_copy * * SYNOPSIS * - * unsigned char * - * silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len, - * char *pkcs, char *identifier, - * SilcUInt32 *len); + * SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key); * * DESCRIPTION * - * Encodes SILC style public key. Returns the encoded data. + * Copies the public key indicated by `public_key' and returns new + * allocated public key which is indentical to the `public_key'. * ***/ -unsigned char * -silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len, - char *pkcs, char *identifier, - SilcUInt32 *len); +SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_decode +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_alloc * * SYNOPSIS * - * SilcBool silc_pkcs_public_key_decode(unsigned char *data, - * SilcUInt32 data_len, - * SilcPublicKey *public_key); + * SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type, + * unsigned char *key, + * SilcUInt32 key_len, + * SilcPrivateKey *ret_private_key); * * DESCRIPTION * - * Decodes SILC style public key. Returns TRUE if the decoding was - * successful. Allocates new public key as well. + * Allocates SilcPrivateKey of the type of `type' from the key data + * `key' of length of `key_len' bytes. Returns FALSE if the `key' + * is malformed or unsupported private key type. * ***/ -SilcBool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len, - SilcPublicKey *public_key); +SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type, + unsigned char *key, + SilcUInt32 key_len, + SilcPrivateKey *ret_private_key); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_payload_encode +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_get_len * * SYNOPSIS * - * SilcBool silc_pkcs_public_key_payload_encode(SilcPublicKey public_key); + * SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key); * * DESCRIPTION * - * Encodes the Public Key Payload from the public key indicated by - * `public_key' of type of `pk_type'. The type is SilcSKEPKType. - * Returns the encoded payload buffer. + * Returns the key length in bits from the public key. * ***/ -SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key); +SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_payload_decode +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_free * * SYNOPSIS * - * SilcBool silc_pkcs_public_key_payload_decode(unsigned char *data, - * SilcUInt32 data_len, - * SilcPublicKey *public_key); + * void silc_pkcs_private_key_free(SilcPrivateKey private_key; * * DESCRIPTION * - * Decodes Public Key Payload from `data' of `data_len' bytes in length - * data buffer into `public_key' pointer. Returns FALSE if the payload - * cannot be decoded. + * Frees the private key. * ***/ -SilcBool silc_pkcs_public_key_payload_decode(unsigned char *data, - SilcUInt32 data_len, - SilcPublicKey *public_key); +void silc_pkcs_private_key_free(SilcPrivateKey private_key); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_compare +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_encrypt * * SYNOPSIS * - * SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, - * SilcPublicKey key2); + * SilcBool silc_pkcs_encrypt(SilcPublicKey public_key, + * unsigned char *src, SilcUInt32 src_len, + * unsigned char *dst, SilcUInt32 dst_size, + * SilcUInt32 *dst_len); * * DESCRIPTION * - * Compares two public keys and returns TRUE if they are same key, and - * FALSE if they are not same. + * Encrypts with the public key. Returns FALSE on error. * ***/ -SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2); +SilcBool silc_pkcs_encrypt(SilcPublicKey public_key, + unsigned char *src, SilcUInt32 src_len, + unsigned char *dst, SilcUInt32 dst_size, + SilcUInt32 *dst_len); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_copy +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_decrypt * * SYNOPSIS * - * SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key); + * SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key, + * unsigned char *src, SilcUInt32 src_len, + * unsigned char *dst, SilcUInt32 dst_size, + * SilcUInt32 *dst_len); * * DESCRIPTION * - * Copies the public key indicated by `public_key' and returns new allocated - * public key which is indentical to the `public_key'. + * Decrypts with the private key. Returns FALSE on error. * ***/ -SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key); +SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key, + unsigned char *src, SilcUInt32 src_len, + unsigned char *dst, SilcUInt32 dst_size, + SilcUInt32 *dst_len); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_encode +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign * * SYNOPSIS * - * unsigned char * - * silc_pkcs_private_key_encode(SilcPrivateKey private_key, - * SilcUInt32 *len); + * SilcBool silc_pkcs_sign(SilcPrivateKey private_key, + * unsigned char *src, SilcUInt32 src_len, + * unsigned char *dst, SilcUInt32 dst_size, + * SilcUInt32 *dst_len, SilcHash hash); * * DESCRIPTION * - * Encodes SILC private key from SilcPrivateKey. Returns the encoded data. + * Generates signature with the private key. Returns FALSE on error. + * If `hash' is non-NULL the `src' will be hashed before signing. * ***/ -unsigned char * -silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len); +SilcBool silc_pkcs_sign(SilcPrivateKey private_key, + unsigned char *src, SilcUInt32 src_len, + unsigned char *dst, SilcUInt32 dst_size, + SilcUInt32 *dst_len, SilcHash hash); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_data_encode +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify * * SYNOPSIS * - * unsigned char * - * silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len, - * char *pkcs, SilcUInt32 *len); + * SilcBool silc_pkcs_verify(SilcPublicKey public_key, + * unsigned char *signature, + * SilcUInt32 signature_len, + * unsigned char *data, + * SilcUInt32 data_len, SilcHash hash); * * DESCRIPTION * - * Encodes SILC private key. Returns the encoded data. + * Verifies signature. Returns FALSE on error. The 'signature' is + * verified against the 'data'. If the `hash' is non-NULL then the `data' + * will hashed before verification. If the `hash' is NULL, then the + * hash algorithm to be used is retrieved from the signature. If it + * isn't present in the signature the verification is done as is without + * hashing. * ***/ -unsigned char * -silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len, - char *pkcs, SilcUInt32 *len); +SilcBool silc_pkcs_verify(SilcPublicKey public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, SilcHash hash); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_decode +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_public_key * * SYNOPSIS * - * SilcBool silc_pkcs_private_key_decode(unsigned char *data, - * SilcUInt32 data_len, - * SilcPrivateKey *private_key); + * SilcBool silc_pkcs_load_public_key(const char *filename, + * SilcPublicKey *ret_public_key); * * DESCRIPTION * - * Decodes SILC style private key. Returns TRUE if the decoding was - * successful. Allocates new private key as well. + * Loads public key from file and allocates new public key. Returns TRUE + * if loading was successful. * ***/ -SilcBool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len, - SilcPrivateKey *private_key); +SilcBool silc_pkcs_load_public_key(const char *filename, + SilcPublicKey *ret_public_key); /****f* silccrypt/SilcPKCSAPI/silc_pkcs_save_public_key * * SYNOPSIS * * SilcBool silc_pkcs_save_public_key(const char *filename, - * SilcPublicKey public_key, - * SilcUInt32 encoding); + * SilcPublicKey public_key, + * SilcPKCSFileEncoding encoding); * * DESCRIPTION * - * Saves public key into file. Returns FALSE on error. + * Saves public key into file with specified encoding. Returns FALSE + * on error. * ***/ -SilcBool silc_pkcs_save_public_key(const char *filename, SilcPublicKey public_key, - SilcUInt32 encoding); +SilcBool silc_pkcs_save_public_key(const char *filename, + SilcPublicKey public_key, + SilcPKCSFileEncoding encoding); -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_save_public_key_data +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_private_key * * SYNOPSIS * - * SilcBool silc_pkcs_save_public_key_data(const char *filename, - * unsigned char *data, - * SilcUInt32 data_len, - * SilcUInt32 encoding); + * SilcBool silc_pkcs_load_private_key(const char *filename, + * const unsigned char *passphrase, + * SilcUInt32 passphrase_len, + * SilcPrivateKey *ret_private_key); * * DESCRIPTION * - * Saves public key into file. The public key is already encoded as - * data when calling this function. Returns FALSE on error. + * Loads private key from file and allocates new private key. Returns TRUE + * if loading was successful. The `passphrase' is used as decryption + * key of the private key file, in case it is encrypted. * ***/ -SilcBool silc_pkcs_save_public_key_data(const char *filename, unsigned char *data, - SilcUInt32 data_len, SilcUInt32 encoding); +SilcBool silc_pkcs_load_private_key(const char *filename, + const unsigned char *passphrase, + SilcUInt32 passphrase_len, + SilcPrivateKey *ret_private_key); /****f* silccrypt/SilcPKCSAPI/silc_pkcs_save_private_key * * SYNOPSIS * * SilcBool silc_pkcs_save_private_key(const char *filename, - * SilcPrivateKey private_key, - * unsigned char *passphrase, - * SilcUInt32 passphrase_len, - * SilcUInt32 encoding); + * SilcPrivateKey private_key, + * const unsigned char *passphrase, + * SilcUInt32 passphrase_len, + * SilcPKCSFileEncoding encoding, + * SilcRng rng); * * DESCRIPTION * * Saves private key into file. The private key is encrypted into - * the file with the `passphrase' as a key. The encryption algorithm - * is AES with 256 bit key in CBC mode. Returns FALSE on error. + * the file with the `passphrase' as a key, if PKCS supports encrypted + * private keys. Returns FALSE on error. * ***/ SilcBool silc_pkcs_save_private_key(const char *filename, - SilcPrivateKey private_key, - unsigned char *passphrase, - SilcUInt32 passphrase_len, - SilcUInt32 encoding); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_public_key - * - * SYNOPSIS - * - * SilcBool silc_pkcs_load_public_key(const char *filename, - * SilcPublicKey *public_key, - * SilcUInt32 encoding); - * - * DESCRIPTION - * - * Loads public key from file and allocates new public key. Returns TRUE - * if loading was successful. - * - ***/ -SilcBool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key, - SilcUInt32 encoding); - -/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_private_key - * - * SYNOPSIS - * - * SilcBool silc_pkcs_load_private_key(const char *filename, - * SilcPrivateKey *private_key, - * unsigned char *passphrase, - * SilcUInt32 passphrase_len, - * SilcUInt32 encoding); - * - * DESCRIPTION - * - * Loads private key from file and allocates new private key. Returns TRUE - * if loading was successful. The `passphrase' is used as decryption - * key of the private key file. - * - ***/ -SilcBool silc_pkcs_load_private_key(const char *filename, - SilcPrivateKey *private_key, - unsigned char *passphrase, - SilcUInt32 passphrase_len, - SilcUInt32 encoding); + SilcPrivateKey private_key, + const unsigned char *passphrase, + SilcUInt32 passphrase_len, + SilcPKCSFileEncoding encoding, + SilcRng rng); #endif /* !SILCPKCS_H */ diff --git a/lib/silccrypt/silcpkcs1.c b/lib/silccrypt/silcpkcs1.c index bfdded05..57f25e67 100644 --- a/lib/silccrypt/silcpkcs1.c +++ b/lib/silccrypt/silcpkcs1.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2003 Pekka Riikonen + Copyright (C) 2003 - 2006 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 @@ -19,7 +19,9 @@ /* $Id$ */ #include "silc.h" -#include "silcpkcs1.h" +#include "rsa.h" + +/************************** PKCS #1 message format ***************************/ /* Minimum padding in block */ #define SILC_PKCS1_MIN_PADDING 8 @@ -34,11 +36,11 @@ success. */ SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt, - const unsigned char *data, - SilcUInt32 data_len, - unsigned char *dest_data, - SilcUInt32 dest_data_size, - SilcRng rng) + const unsigned char *data, + SilcUInt32 data_len, + unsigned char *dest_data, + SilcUInt32 dest_data_size, + SilcRng rng) { SilcInt32 padlen; int i; @@ -46,7 +48,8 @@ SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt, SILC_LOG_DEBUG(("PKCS#1 encoding, bt %d", bt)); if (!data || !dest_data || - dest_data_size < 3 || dest_data_size < data_len) { + dest_data_size < SILC_PKCS1_MIN_PADDING + 3 || + dest_data_size < data_len) { SILC_LOG_DEBUG(("Data to be encoded is too long")); return FALSE; } @@ -97,11 +100,11 @@ SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt, Returns TRUE on success. */ SilcBool silc_pkcs1_decode(SilcPkcs1BlockType bt, - const unsigned char *data, - SilcUInt32 data_len, - unsigned char *dest_data, - SilcUInt32 dest_data_size, - SilcUInt32 *dest_len) + const unsigned char *data, + SilcUInt32 data_len, + unsigned char *dest_data, + SilcUInt32 dest_data_size, + SilcUInt32 *dest_len) { int i = 0; @@ -158,3 +161,537 @@ SilcBool silc_pkcs1_decode(SilcPkcs1BlockType bt, return TRUE; } + + +/***************************** PKCS #1 PKCS API ******************************/ + +/* Generates RSA key pair. */ + +SilcBool silc_pkcs1_generate_key(SilcUInt32 keylen, + SilcRng rng, + void **ret_public_key, + void **ret_private_key) +{ + SilcUInt32 prime_bits = keylen / 2; + SilcMPInt p, q; + SilcBool found = FALSE; + + if (keylen < 768 || keylen > 16384) + return FALSE; + + silc_mp_init(&p); + silc_mp_init(&q); + + /* Find p and q */ + while (!found) { + silc_math_gen_prime(&p, prime_bits, FALSE, rng); + silc_math_gen_prime(&q, prime_bits, FALSE, rng); + if ((silc_mp_cmp(&p, &q)) != 0) + found = TRUE; + } + + /* If p is smaller than q, switch them */ + if ((silc_mp_cmp(&p, &q)) > 0) { + SilcMPInt hlp; + silc_mp_init(&hlp); + + silc_mp_set(&hlp, &p); + silc_mp_set(&p, &q); + silc_mp_set(&q, &hlp); + + silc_mp_uninit(&hlp); + } + + /* Generate the actual keys */ + if (!rsa_generate_keys(keylen, &p, &q, ret_public_key, ret_private_key)) + return FALSE; + + silc_mp_uninit(&p); + silc_mp_uninit(&q); + + return TRUE; +} + +/* Import PKCS #1 compliant public key */ + +SilcBool silc_pkcs1_import_public_key(unsigned char *key, + SilcUInt32 key_len, + void **ret_public_key) +{ + SilcAsn1 asn1 = NULL; + SilcBufferStruct alg_key; + RsaPublicKey *pubkey; + + if (!ret_public_key) + return FALSE; + + asn1 = silc_asn1_alloc(); + if (!asn1) + return FALSE; + + /* Allocate RSA public key */ + *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey)); + if (!pubkey) + goto err; + + /* Parse the PKCS #1 public key */ + silc_buffer_set(&alg_key, key, key_len); + if (!silc_asn1_decode(asn1, &alg_key, + SILC_ASN1_OPTS(SILC_ASN1_ALLOC), + SILC_ASN1_SEQUENCE, + SILC_ASN1_INT(&pubkey->n), + SILC_ASN1_INT(&pubkey->e), + SILC_ASN1_END, SILC_ASN1_END)) + goto err; + + /* Set key length */ + pubkey->bits = silc_mp_sizeinbase(&pubkey->n, 2); + + silc_asn1_free(asn1); + + return TRUE; + + err: + silc_asn1_free(asn1); + return FALSE; +} + +/* Export PKCS #1 compliant public key */ + +unsigned char *silc_pkcs1_export_public_key(void *public_key, + SilcUInt32 *ret_len) +{ + RsaPublicKey *key = public_key; + SilcAsn1 asn1 = NULL; + SilcBufferStruct alg_key; + unsigned char *ret; + + asn1 = silc_asn1_alloc(); + if (!asn1) + goto err; + + /* Encode to PKCS #1 public key */ + memset(&alg_key, 0, sizeof(alg_key)); + if (!silc_asn1_encode(asn1, &alg_key, + SILC_ASN1_OPTS(SILC_ASN1_ALLOC), + SILC_ASN1_SEQUENCE, + SILC_ASN1_INT(&key->n), + SILC_ASN1_INT(&key->e), + SILC_ASN1_END, SILC_ASN1_END)) + goto err; + + ret = silc_buffer_steal(&alg_key, ret_len); + silc_asn1_free(asn1); + + return ret; + + err: + if (asn1) + silc_asn1_free(asn1); + return NULL; +} + +/* Returns key length */ + +SilcUInt32 silc_pkcs1_public_key_bitlen(void *public_key) +{ + RsaPublicKey *key = public_key; + return key->bits; +} + +/* Copy public key */ + +void *silc_pkcs1_public_key_copy(void *public_key) +{ + RsaPublicKey *key = public_key, *new_key; + + new_key = silc_calloc(1, sizeof(*new_key)); + if (!new_key) + return NULL; + + silc_mp_init(&new_key->n); + silc_mp_init(&new_key->e); + silc_mp_set(&new_key->n, &key->n); + silc_mp_set(&new_key->e, &key->e); + new_key->bits = key->bits; + + return new_key; +} + +/* Compare public keys */ + +SilcBool silc_pkcs1_public_key_compare(void *key1, void *key2) +{ + RsaPublicKey *k1 = key1, *k2 = key2; + + if (k1->bits != k2->bits) + return FALSE; + if (silc_mp_cmp(&k1->e, &k2->e) != 0) + return FALSE; + if (silc_mp_cmp(&k1->n, &k2->n) != 0) + return FALSE; + + return TRUE; +} + +/* Frees public key */ + +void silc_pkcs1_public_key_free(void *public_key) +{ + RsaPublicKey *key = public_key; + + silc_mp_uninit(&key->n); + silc_mp_uninit(&key->e); + silc_free(key); +} + +/* Import PKCS #1 compliant private key */ + +SilcBool silc_pkcs1_import_private_key(unsigned char *key, + SilcUInt32 key_len, + void **ret_private_key) +{ + SilcAsn1 asn1; + SilcBufferStruct alg_key; + RsaPrivateKey *privkey; + + if (!ret_private_key) + return FALSE; + + asn1 = silc_asn1_alloc(); + if (!asn1) + return FALSE; + + /* Allocate RSA private key */ + *ret_private_key = privkey = silc_calloc(1, sizeof(*privkey)); + if (!privkey) + goto err; + + /* Parse the PKCS #1 private key */ + silc_buffer_set(&alg_key, key, key_len); + if (!silc_asn1_decode(asn1, &alg_key, + SILC_ASN1_OPTS(SILC_ASN1_ALLOC), + SILC_ASN1_SEQUENCE, + SILC_ASN1_INT(NULL), + SILC_ASN1_INT(&privkey->n), + SILC_ASN1_INT(&privkey->e), + SILC_ASN1_INT(&privkey->d), + SILC_ASN1_INT(&privkey->p), + SILC_ASN1_INT(&privkey->q), + SILC_ASN1_INT(&privkey->dP), + SILC_ASN1_INT(&privkey->dQ), + SILC_ASN1_INT(&privkey->qP), + SILC_ASN1_END, SILC_ASN1_END)) + goto err; + + /* Set key length */ + privkey->bits = silc_mp_sizeinbase(&privkey->n, 2); + + silc_asn1_free(asn1); + + return TRUE; + + err: + silc_asn1_free(asn1); + return FALSE; +} + +/* Export PKCS #1 compliant private key */ + +unsigned char *silc_pkcs1_export_private_key(void *private_key, + SilcUInt32 *ret_len) +{ + RsaPrivateKey *key = private_key; + SilcAsn1 asn1; + SilcBufferStruct alg_key; + SilcMPInt version; + unsigned char *ret; + + asn1 = silc_asn1_alloc(); + if (!asn1) + return FALSE; + + /* Encode to PKCS #1 private key */ + silc_mp_init(&version); + silc_mp_set_ui(&version, 0); + memset(&alg_key, 0, sizeof(alg_key)); + if (!silc_asn1_encode(asn1, &alg_key, + SILC_ASN1_OPTS(SILC_ASN1_ALLOC), + SILC_ASN1_SEQUENCE, + SILC_ASN1_INT(&version), + SILC_ASN1_INT(&key->n), + SILC_ASN1_INT(&key->e), + SILC_ASN1_INT(&key->d), + SILC_ASN1_INT(&key->p), + SILC_ASN1_INT(&key->q), + SILC_ASN1_INT(&key->dP), + SILC_ASN1_INT(&key->dQ), + SILC_ASN1_INT(&key->qP), + SILC_ASN1_END, SILC_ASN1_END)) + goto err; + silc_mp_uninit(&version); + + ret = silc_buffer_steal(&alg_key, ret_len); + silc_asn1_free(asn1); + + return ret; + + err: + silc_asn1_free(asn1); + return NULL; +} + +/* Returns key length */ + +SilcUInt32 silc_pkcs1_private_key_bitlen(void *private_key) +{ + RsaPrivateKey *key = private_key; + return key->bits; +} + +/* Frees private key */ + +void silc_pkcs1_private_key_free(void *private_key) +{ + RsaPrivateKey *key = private_key; + + silc_mp_uninit(&key->n); + silc_mp_uninit(&key->e); + silc_mp_uninit(&key->d); + silc_mp_uninit(&key->dP); + silc_mp_uninit(&key->dQ); + silc_mp_uninit(&key->qP); + silc_mp_uninit(&key->p); + silc_mp_uninit(&key->q); + silc_free(key); +} + +/* PKCS #1 RSA routines */ + +SilcBool silc_pkcs1_encrypt(void *public_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len) +{ + RsaPublicKey *key = public_key; + SilcMPInt mp_tmp; + SilcMPInt mp_dst; + unsigned char padded[2048 + 1]; + SilcUInt32 len = (key->bits + 7) / 8; + + if (sizeof(padded) < len) + return FALSE; + if (dst_size < len) + return FALSE; + + /* Pad data */ + if (!silc_pkcs1_encode(SILC_PKCS1_BT_PUB, src, src_len, + padded, len, NULL)) + return FALSE; + + silc_mp_init(&mp_tmp); + silc_mp_init(&mp_dst); + + /* Data to MP */ + silc_mp_bin2mp(padded, len, &mp_tmp); + + /* Encrypt */ + rsa_public_operation(key, &mp_tmp, &mp_dst); + + /* MP to data */ + silc_mp_mp2bin_noalloc(&mp_dst, dst, len); + *ret_dst_len = len; + + memset(padded, 0, sizeof(padded)); + silc_mp_uninit(&mp_tmp); + silc_mp_uninit(&mp_dst); + + return TRUE; +} + +SilcBool silc_pkcs1_decrypt(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len) +{ + RsaPrivateKey *key = private_key; + SilcMPInt mp_tmp; + SilcMPInt mp_dst; + unsigned char *padded, unpadded[2048 + 1]; + SilcUInt32 padded_len; + + if (dst_size < (key->bits + 7) / 8) + return FALSE; + + silc_mp_init(&mp_tmp); + silc_mp_init(&mp_dst); + + /* Data to MP */ + silc_mp_bin2mp(src, src_len, &mp_tmp); + + /* Decrypt */ + rsa_private_operation(key, &mp_tmp, &mp_dst); + + /* MP to data */ + padded = silc_mp_mp2bin(&mp_dst, (key->bits + 7) / 8, &padded_len); + + /* Unpad data */ + if (!silc_pkcs1_decode(SILC_PKCS1_BT_PUB, padded, padded_len, + unpadded, sizeof(unpadded), ret_dst_len)) { + memset(padded, 0, padded_len); + silc_free(padded); + silc_mp_uninit(&mp_tmp); + silc_mp_uninit(&mp_dst); + return FALSE; + } + + /* Copy to destination */ + memcpy(dst, unpadded, *ret_dst_len); + + memset(padded, 0, padded_len); + memset(unpadded, 0, sizeof(unpadded)); + silc_free(padded); + silc_mp_uninit(&mp_tmp); + silc_mp_uninit(&mp_dst); + + return TRUE; +} + +SilcBool silc_pkcs1_sign(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *signature, + SilcUInt32 signature_size, + SilcUInt32 *ret_signature_len, + SilcHash hash) +{ + return FALSE; +} + +SilcBool silc_pkcs1_verify(void *public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, + SilcHash hash) +{ + return FALSE; +} + +/* PKCS #1 sign without hash oid */ + +SilcBool silc_pkcs1_sign_no_oid(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *signature, + SilcUInt32 signature_size, + SilcUInt32 *ret_signature_len, + SilcHash hash) +{ + RsaPrivateKey *key = private_key; + SilcMPInt mp_tmp; + SilcMPInt mp_dst; + unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN]; + SilcUInt32 len = (key->bits + 7) / 8; + + if (sizeof(padded) < len) + return FALSE; + if (signature_size < len) + return FALSE; + + /* Compute hash if requested */ + if (hash) { + silc_hash_make(hash, src, src_len, hashr); + src = hashr; + src_len = silc_hash_len(hash); + } + + /* Pad data */ + if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, src, src_len, + padded, len, NULL)) + return FALSE; + + silc_mp_init(&mp_tmp); + silc_mp_init(&mp_dst); + + /* Data to MP */ + silc_mp_bin2mp(padded, len, &mp_tmp); + + /* Sign */ + rsa_private_operation(key, &mp_tmp, &mp_dst); + + /* MP to data */ + silc_mp_mp2bin_noalloc(&mp_dst, signature, len); + *ret_signature_len = len; + + memset(padded, 0, sizeof(padded)); + silc_mp_uninit(&mp_tmp); + silc_mp_uninit(&mp_dst); + if (hash) + memset(hashr, 0, sizeof(hashr)); + + return TRUE; +} + +/* PKCS #1 verify without hash oid */ + +SilcBool silc_pkcs1_verify_no_oid(void *public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, + SilcHash hash) +{ + RsaPublicKey *key = public_key; + int ret = TRUE; + SilcMPInt mp_tmp2; + SilcMPInt mp_dst; + unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN]; + SilcUInt32 verify_len, len = (key->bits + 7) / 8; + + silc_mp_init(&mp_tmp2); + silc_mp_init(&mp_dst); + + /* Format the signature into MP int */ + silc_mp_bin2mp(signature, signature_len, &mp_tmp2); + + /* Verify */ + rsa_public_operation(key, &mp_tmp2, &mp_dst); + + /* MP to data */ + verify = silc_mp_mp2bin(&mp_dst, len, &verify_len); + + /* Unpad data */ + if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len, + unpadded, sizeof(unpadded), &len)) { + memset(verify, 0, verify_len); + silc_free(verify); + silc_mp_uninit(&mp_tmp2); + silc_mp_uninit(&mp_dst); + return FALSE; + } + + /* Hash data if requested */ + if (hash) { + silc_hash_make(hash, data, data_len, hashr); + data = hashr; + } + + /* Compare */ + if (memcmp(data, unpadded, len)) + ret = FALSE; + + memset(verify, 0, verify_len); + memset(unpadded, 0, sizeof(unpadded)); + silc_free(verify); + silc_mp_uninit(&mp_tmp2); + silc_mp_uninit(&mp_dst); + if (hash) + memset(hashr, 0, sizeof(hashr)); + + return ret; +} diff --git a/lib/silccrypt/silcpkcs1.h b/lib/silccrypt/silcpkcs1.h index 9b113297..30cee1cd 100644 --- a/lib/silccrypt/silcpkcs1.h +++ b/lib/silccrypt/silcpkcs1.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2003 Pekka Riikonen + Copyright (C) 2003 - 2005 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 @@ -78,11 +78,11 @@ typedef enum { * ***/ SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt, - const unsigned char *data, - SilcUInt32 data_len, - unsigned char *dest_data, - SilcUInt32 dest_data_size, - SilcRng rng); + const unsigned char *data, + SilcUInt32 data_len, + unsigned char *dest_data, + SilcUInt32 dest_data_size, + SilcRng rng); /****f* silccrypt/SilcPKCS1API/silc_pkcs1_decode * @@ -106,10 +106,10 @@ SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt, * ***/ SilcBool silc_pkcs1_decode(SilcPkcs1BlockType bt, - const unsigned char *data, - SilcUInt32 data_len, - unsigned char *dest_data, - SilcUInt32 dest_data_size, - SilcUInt32 *dest_len); + const unsigned char *data, + SilcUInt32 data_len, + unsigned char *dest_data, + SilcUInt32 dest_data_size, + SilcUInt32 *dest_len); #endif /* SILCPKCS1_H */ diff --git a/lib/silccrypt/silcpkcs1_i.h b/lib/silccrypt/silcpkcs1_i.h new file mode 100644 index 00000000..6c050491 --- /dev/null +++ b/lib/silccrypt/silcpkcs1_i.h @@ -0,0 +1,82 @@ +/* + + silcpkcs1_i.h + + Author: Pekka Riikonen + + Copyright (C); 2006 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef SILCPKCS1_I_H +#define SILCPKCS1_I_H + +SilcBool silc_pkcs1_generate_key(SilcUInt32 keylen, + SilcRng rng, + void **ret_public_key, + void **ret_private_key); +SilcBool silc_pkcs1_import_public_key(unsigned char *key, + SilcUInt32 key_len, + void **ret_public_key); +unsigned char *silc_pkcs1_export_public_key(void *public_key, + SilcUInt32 *ret_len); +SilcUInt32 silc_pkcs1_public_key_bitlen(void *public_key); +void *silc_pkcs1_public_key_copy(void *public_key); +SilcBool silc_pkcs1_public_key_compare(void *key1, void *key2); +void silc_pkcs1_public_key_free(void *public_key); +SilcBool silc_pkcs1_import_private_key(unsigned char *key, + SilcUInt32 key_len, + void **ret_private_key); +unsigned char *silc_pkcs1_export_private_key(void *private_key, + SilcUInt32 *ret_len); +SilcUInt32 silc_pkcs1_private_key_bitlen(void *private_key); +void silc_pkcs1_private_key_free(void *private_key); +SilcBool silc_pkcs1_encrypt(void *public_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len); +SilcBool silc_pkcs1_decrypt(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *dst, + SilcUInt32 dst_size, + SilcUInt32 *ret_dst_len); +SilcBool silc_pkcs1_sign(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *signature, + SilcUInt32 signature_size, + SilcUInt32 *ret_signature_len, + SilcHash hash); +SilcBool silc_pkcs1_verify(void *public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, + SilcHash hash); +SilcBool silc_pkcs1_sign_no_oid(void *private_key, + unsigned char *src, + SilcUInt32 src_len, + unsigned char *signature, + SilcUInt32 signature_size, + SilcUInt32 *ret_signature_len, + SilcHash hash); +SilcBool silc_pkcs1_verify_no_oid(void *public_key, + unsigned char *signature, + SilcUInt32 signature_len, + unsigned char *data, + SilcUInt32 data_len, + SilcHash hash); + +#endif /* SILCPKCS1_I_H */ diff --git a/lib/silcmath/mpbin.c b/lib/silcmath/mpbin.c index 02b7e941..76f90e77 100644 --- a/lib/silcmath/mpbin.c +++ b/lib/silcmath/mpbin.c @@ -34,6 +34,8 @@ unsigned char *silc_mp_mp2bin(SilcMPInt *val, SilcUInt32 len, size = (len ? len : ((silc_mp_sizeinbase(val, 2) + 7) / 8)); ret = silc_calloc(size, sizeof(*ret)); + if (!ret) + return NULL; silc_mp_init(&tmp); silc_mp_set(&tmp, val); diff --git a/lib/silcmath/silcmath.h b/lib/silcmath/silcmath.h index b1b59d19..08a08c0c 100644 --- a/lib/silcmath/silcmath.h +++ b/lib/silcmath/silcmath.h @@ -1,15 +1,15 @@ /* silcmath.h - + Author: Pekka Riikonen - - Copyright (C) 1997 - 2001 Pekka Riikonen - + + Copyright (C) 1997 - 2005 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 the Free Software Foundation; version 2 of the License. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -36,15 +36,15 @@ * * SYNOPSIS * - * int silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits, SilcBool verbose, - * SilcRng); + * SilcBool silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits, + * SilcBool verbose, SilcRng rng); * * DESCRIPTION * - * Find appropriate prime. It generates a number by taking random bytes. - * It then tests the number that it's not divisible by any of the small - * primes and then it performs Fermat's prime test. I thank Rieks Joosten - * (r.joosten@pijnenburg.nl) for such a good help with prime tests. + * Find appropriate prime. It generates a number by taking random bytes. + * It then tests the number that it's not divisible by any of the small + * primes and then it performs Fermat's prime test. I thank Rieks Joosten + * (r.joosten@pijnenburg.nl) for such a good help with prime tests. * * If argument verbose is TRUE this will display some status information * about the progress of generation. If the `rng' is NULL then global @@ -63,7 +63,7 @@ SilcBool silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits, * * DESCRIPTION * - * Performs primality testings for given number. Returns TRUE if the + * Performs primality testings for given number. Returns TRUE if the * number is probably a prime. * ***/ diff --git a/lib/silcmath/silcmp.h b/lib/silcmath/silcmp.h index 4b7bff9f..aaff0412 100644 --- a/lib/silcmath/silcmp.h +++ b/lib/silcmath/silcmp.h @@ -662,7 +662,7 @@ unsigned char *silc_mp_mp2bin(SilcMPInt *val, SilcUInt32 len, * DESCRIPTION * * Same as silc_mp_mp2bin but does not allocate any memory. The - * encoded data is returned into `dst' and it's length to the `ret_len'. + * encoded data is returned into `dst' of size of `dst_len'. * ***/ void silc_mp_mp2bin_noalloc(SilcMPInt *val, unsigned char *dst, diff --git a/lib/silcserver/server.c b/lib/silcserver/server.c index cf325a44..974e14d9 100644 --- a/lib/silcserver/server.c +++ b/lib/silcserver/server.c @@ -634,13 +634,6 @@ SilcServer silc_server_alloc(void *app_context, SilcServerParams params, server->params->server_info->public_key = NULL; server->params->server_info->private_key = NULL; - /* Allocate PKCS context for local public and private keys */ - if (!silc_pkcs_alloc(server->public_key->name, SILC_PKCS_SILC, - &server->pkcs)) - goto err; - silc_pkcs_public_key_set(server->pkcs, server->public_key); - silc_pkcs_private_key_set(server->pkcs, server->private_key); - /* Create network listener(s) */ server->listeners = silc_dlist_init(); if (!server->listeners) diff --git a/lib/silcserver/server_internal.h b/lib/silcserver/server_internal.h index 5e1b90e9..64a971b6 100644 --- a/lib/silcserver/server_internal.h +++ b/lib/silcserver/server_internal.h @@ -330,7 +330,6 @@ struct SilcServerStruct { SilcUInt16 cmd_ident; /* Server public key */ - SilcPKCS pkcs; SilcPublicKey public_key; SilcPrivateKey private_key; diff --git a/lib/silcserver/server_st_accept.c b/lib/silcserver/server_st_accept.c index 38e4acdc..b6e63884 100644 --- a/lib/silcserver/server_st_accept.c +++ b/lib/silcserver/server_st_accept.c @@ -27,9 +27,8 @@ static void silc_server_accept_verify_key(SilcSKE ske, - const unsigned char *pk_data, - SilcUInt32 pk_len, SilcSKEPKType pk_type, + SilcPublicKey public_key, void *context, SilcSKEVerifyCbCompletion completion, void *completion_context) diff --git a/lib/silcserver/server_st_command.c b/lib/silcserver/server_st_command.c index 36c3d9ea..70f5e2d0 100644 --- a/lib/silcserver/server_st_command.c +++ b/lib/silcserver/server_st_command.c @@ -183,8 +183,8 @@ void silc_server_command_free(SilcServerCommand cmd) silc_mutex_lock(thread->server->lock); - /* Check for double free */ #if defined(SILC_DEBUG) + /* Check for double free */ assert(cmd->packet != NULL); #endif /* SILC_DEBUG */ diff --git a/lib/silcserver/server_st_command_reply.c b/lib/silcserver/server_st_command_reply.c index 5fd7c34f..83ddfd06 100644 --- a/lib/silcserver/server_st_command_reply.c +++ b/lib/silcserver/server_st_command_reply.c @@ -451,7 +451,7 @@ SILC_FSM_STATE(silc_server_st_command_reply_getkey) tmp = silc_argument_get_arg_type(args, 3, &len); if (!tmp) goto out; - if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key)) + if (!silc_public_key_payload_decode(tmp, len, &public_key)) goto out; /* Store the public key */ diff --git a/lib/silcserver/server_st_packet.c b/lib/silcserver/server_st_packet.c index dc1e6d57..765e7126 100644 --- a/lib/silcserver/server_st_packet.c +++ b/lib/silcserver/server_st_packet.c @@ -303,14 +303,6 @@ SILC_FSM_STATE(silc_server_st_packet_received) return SILC_FSM_CONTINUE; break; - case SILC_PACKET_CONNECTION_AUTH_REQUEST: - /** Packet CONNECTION_AUTH_REQUEST */ - if (packet->flags & SILC_PACKET_FLAG_LIST) - break; - silc_fsm_next(fsm, silc_server_st_packet_connection_auth_request); - return SILC_FSM_CONTINUE; - break; - case SILC_PACKET_HEARTBEAT: case SILC_PACKET_SUCCESS: case SILC_PACKET_FAILURE: diff --git a/lib/silcserver/tests/test_silcserver.c b/lib/silcserver/tests/test_silcserver.c index 5c27a3ee..a1953a64 100644 --- a/lib/silcserver/tests/test_silcserver.c +++ b/lib/silcserver/tests/test_silcserver.c @@ -26,7 +26,7 @@ int main(int argc, char **argv) if (argc > 1 && !strcmp(argv[1], "-d")) { silc_log_debug(TRUE); silc_log_debug_hexdump(TRUE); - silc_log_set_debug_string("*server*,*skr*,*ske*,*connauth*,*packet*,*stream*,*net*"); + silc_log_set_debug_string("*server*,*skr*,*ske*,*connauth*,*packet*,*stream*,*net*,*pkcs*,*asn1*"); } SILC_LOG_DEBUG(("Allocating scheduler")); @@ -49,11 +49,10 @@ int main(int argc, char **argv) goto err; info->server_name = strdup("test server"); - if (!silc_load_key_pair("test.pub", "test.prv", "", NULL, + if (!silc_load_key_pair("test.pub", "test.prv", "", &info->public_key, &info->private_key)) { if (!silc_create_key_pair("rsa", 2048, "test.pub", "test.prv", NULL, "", - NULL, &info->public_key, &info->private_key, FALSE)) { goto err; diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c index c230e36b..c0e8d7f1 100644 --- a/lib/silcske/silcske.c +++ b/lib/silcske/silcske.c @@ -224,7 +224,7 @@ silc_ske_select_security_properties(SilcSKE ske, SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item)); - if (silc_pkcs_is_supported(item) == TRUE) { + if (silc_pkcs_find_algorithm(item, NULL)) { SILC_LOG_DEBUG(("Found PKCS alg `%s'", item)); payload->pkcs_alg_len = len; @@ -635,6 +635,8 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, return SILC_SKE_STATUS_ERROR; } + SILC_LOG_HEXDUMP(("hash buf"), buf->data, silc_buffer_len(buf)); + memset(e, 0, e_len); silc_free(e); } @@ -707,8 +709,6 @@ void silc_ske_free(SilcSKE ske) if (ske->prop) { if (ske->prop->group) silc_ske_group_free(ske->prop->group); - if (ske->prop->pkcs) - silc_pkcs_free(ske->prop->pkcs); if (ske->prop->cipher) silc_cipher_free(ske->prop->cipher); if (ske->prop->hash) @@ -876,8 +876,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase1) prop->group = group; - if (silc_pkcs_alloc(payload->pkcs_alg_list, ske->pk_type, - &prop->pkcs) == FALSE) { + if (silc_pkcs_find_algorithm(payload->pkcs_alg_list, NULL) == NULL) { status = SILC_SKE_STATUS_UNKNOWN_PKCS; goto err; } @@ -907,8 +906,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase1) silc_ske_group_free(group); - if (prop->pkcs) - silc_pkcs_free(prop->pkcs); if (prop->cipher) silc_cipher_free(prop->cipher); if (prop->hash) @@ -1016,10 +1013,8 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase2) SILC_LOG_DEBUG(("Signing HASH_i value")); /* Sign the hash value */ - silc_pkcs_private_key_data_set(ske->prop->pkcs, ske->private_key->prv, - ske->private_key->prv_len); - if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 || - !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) { + if (!silc_pkcs_sign(ske->private_key, hash, hash_len, sign, + sizeof(sign) - 1, &sign_len, NULL)) { /** Error computing signature */ silc_mp_uninit(x); silc_free(x); @@ -1106,14 +1101,24 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase3) silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group); ske->KEY = KEY; - if (payload->pk_data && ske->callbacks->verify_key) { + /* Decode the remote's public key */ + if (payload->pk_data && + !silc_pkcs_public_key_alloc(payload->pk_type, + payload->pk_data, payload->pk_len, + &ske->prop->public_key)) { + SILC_LOG_ERROR(("Unsupported/malformed public key received")); + status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY; + goto err; + } + + if (ske->prop->public_key && ske->callbacks->verify_key) { SILC_LOG_DEBUG(("Verifying public key")); /** Waiting public key verification */ silc_fsm_next(fsm, silc_ske_st_initiator_phase4); - SILC_FSM_CALL(ske->callbacks->verify_key(ske, payload->pk_data, - payload->pk_len, + SILC_FSM_CALL(ske->callbacks->verify_key(ske, payload->pk_type, + ske->prop->public_key, ske->callbacks->context, silc_ske_pk_verified, NULL)); /* NOT REACHED */ @@ -1149,7 +1154,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4) SilcSKEKEPayload payload; unsigned char hash[SILC_HASH_MAXLEN]; SilcUInt32 hash_len; - SilcPublicKey public_key = NULL; int key_len, block_len; if (ske->aborted) { @@ -1168,15 +1172,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4) payload = ske->ke2_payload; - if (payload->pk_data) { - /* Decode the public key */ - if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len, - &public_key)) { - SILC_LOG_ERROR(("Unsupported/malformed public key received")); - status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY; - goto err; - } - + if (ske->prop->public_key) { SILC_LOG_DEBUG(("Public key is authentic")); /* Compute the hash value */ @@ -1190,9 +1186,8 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4) SILC_LOG_DEBUG(("Verifying signature (HASH)")); /* Verify signature */ - silc_pkcs_public_key_set(ske->prop->pkcs, public_key); - if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data, - payload->sign_len, hash, hash_len) == FALSE) { + if (!silc_pkcs_verify(ske->prop->public_key, payload->sign_data, + payload->sign_len, hash, hash_len, NULL)) { SILC_LOG_ERROR(("Signature verification failed, incorrect signature")); status = SILC_SKE_STATUS_INCORRECT_SIGNATURE; goto err; @@ -1200,7 +1195,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4) SILC_LOG_DEBUG(("Signature is Ok")); - silc_pkcs_public_key_free(public_key); memset(hash, 'F', hash_len); } @@ -1234,9 +1228,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4) silc_free(ske->KEY); ske->KEY = NULL; - if (public_key) - silc_pkcs_public_key_free(public_key); - if (ske->hash) { memset(ske->hash, 'F', hash_len); silc_free(ske->hash); @@ -1475,8 +1466,7 @@ SILC_FSM_STATE(silc_ske_st_responder_phase2) /* XXX these shouldn't be allocated before we know the remote's public key type. It's unnecessary to allocate these because the select_security_properties has succeeded already. */ - if (silc_pkcs_alloc(ske->start_payload->pkcs_alg_list, - SILC_PKCS_SILC, &prop->pkcs) == FALSE) { + if (!silc_pkcs_find_algorithm(ske->start_payload->pkcs_alg_list, NULL)) { status = SILC_SKE_STATUS_UNKNOWN_PKCS; goto err; } @@ -1517,8 +1507,6 @@ SILC_FSM_STATE(silc_ske_st_responder_phase2) if (group) silc_ske_group_free(group); - if (prop->pkcs) - silc_pkcs_free(prop->pkcs); if (prop->cipher) silc_cipher_free(prop->cipher); if (prop->hash) @@ -1590,14 +1578,27 @@ SILC_FSM_STATE(silc_ske_st_responder_phase3) return SILC_FSM_CONTINUE; } - if (recv_payload->pk_data && ske->callbacks->verify_key) { + /* Decode the remote's public key */ + if (recv_payload->pk_data && + !silc_pkcs_public_key_alloc(recv_payload->pk_type, + recv_payload->pk_data, + recv_payload->pk_len, + &ske->prop->public_key)) { + /** Error decoding public key */ + SILC_LOG_ERROR(("Unsupported/malformed public key received")); + ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + if (ske->prop->public_key && ske->callbacks->verify_key) { SILC_LOG_DEBUG(("Verifying public key")); /** Waiting public key verification */ silc_fsm_next(fsm, silc_ske_st_responder_phase4); - SILC_FSM_CALL(ske->callbacks->verify_key(ske, recv_payload->pk_data, - recv_payload->pk_len, + SILC_FSM_CALL(ske->callbacks->verify_key(ske, recv_payload->pk_type, + ske->prop->public_key, ske->callbacks->context, silc_ske_pk_verified, NULL)); /* NOT REACHED */ @@ -1638,21 +1639,9 @@ SILC_FSM_STATE(silc_ske_st_responder_phase4) Authentication flag is set. */ if (ske->start_payload && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) { - SilcPublicKey public_key = NULL; unsigned char hash[SILC_HASH_MAXLEN]; SilcUInt32 hash_len; - /* Decode the public key */ - if (!silc_pkcs_public_key_decode(recv_payload->pk_data, - recv_payload->pk_len, - &public_key)) { - /** Error decoding public key */ - SILC_LOG_ERROR(("Unsupported/malformed public key received")); - ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY; - silc_fsm_next(fsm, silc_ske_st_responder_error); - return SILC_FSM_CONTINUE; - } - SILC_LOG_DEBUG(("Public key is authentic")); /* Compute the hash value */ @@ -1667,9 +1656,8 @@ SILC_FSM_STATE(silc_ske_st_responder_phase4) SILC_LOG_DEBUG(("Verifying signature (HASH_i)")); /* Verify signature */ - silc_pkcs_public_key_set(ske->prop->pkcs, public_key); - if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data, - recv_payload->sign_len, hash, hash_len) == FALSE) { + if (!silc_pkcs_verify(ske->prop->public_key, recv_payload->sign_data, + recv_payload->sign_len, hash, hash_len, NULL)) { /** Incorrect signature */ SILC_LOG_ERROR(("Signature verification failed, incorrect signature")); ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE; @@ -1679,7 +1667,6 @@ SILC_FSM_STATE(silc_ske_st_responder_phase4) SILC_LOG_DEBUG(("Signature is Ok")); - silc_pkcs_public_key_free(public_key); memset(hash, 'F', hash_len); } @@ -1769,10 +1756,8 @@ SILC_FSM_STATE(silc_ske_st_responder_phase5) SILC_LOG_DEBUG(("Signing HASH value")); /* Sign the hash value */ - silc_pkcs_private_key_data_set(ske->prop->pkcs, ske->private_key->prv, - ske->private_key->prv_len); - if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 || - !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) { + if (!silc_pkcs_sign(ske->private_key, hash, hash_len, sign, + sizeof(sign) - 1, &sign_len, NULL)) { /** Error computing signature */ status = SILC_SKE_STATUS_SIGNATURE_ERROR; silc_fsm_next(fsm, silc_ske_st_responder_error); diff --git a/lib/silcske/silcske.h b/lib/silcske/silcske.h index 6efd1d45..ffe9f7c4 100644 --- a/lib/silcske/silcske.h +++ b/lib/silcske/silcske.h @@ -121,8 +121,7 @@ typedef struct { SilcCipher cipher; /* Selected cipher */ SilcHmac hmac; /* Selected HMAC */ SilcHash hash; /* Selected hash algorithm */ - SilcPKCS pkcs; /* Selected PKCS and remote's - public key/certificate */ + SilcPublicKey public_key; /* Remote public key */ } *SilcSKESecurityProperties; /***/ @@ -229,9 +228,8 @@ typedef void (*SilcSKEVerifyCbCompletion)(SilcSKE ske, * SYNOPSIS * * typedef void (*SilcSKEVerifyCb)(SilcSKE ske, - * const unsigned char *pk_data, - * SilcUInt32 pk_len, * SilcSKEPKType pk_type, + * SilcPublicKey public_key, * void *context, * SilcSKEVerifyCbCompletion completion, * void *completion_context); @@ -247,9 +245,8 @@ typedef void (*SilcSKEVerifyCbCompletion)(SilcSKE ske, * ***/ typedef void (*SilcSKEVerifyCb)(SilcSKE ske, - const unsigned char *pk_data, - SilcUInt32 pk_len, SilcSKEPKType pk_type, + SilcPublicKey public_key, void *context, SilcSKEVerifyCbCompletion completion, void *completion_context); diff --git a/lib/silcskr/silcskr.c b/lib/silcskr/silcskr.c index 1d17c62f..8efc9ca7 100644 --- a/lib/silcskr/silcskr.c +++ b/lib/silcskr/silcskr.c @@ -82,8 +82,7 @@ static void silc_skr_type_string(SilcSKRFindType type, void *data, break; case SILC_SKR_FIND_PUBLIC_KEY: - snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type], - ((SilcPublicKey)data)->identifier); + snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data); break; default: @@ -131,18 +130,11 @@ static void silc_skr_destructor(void *key, void *context, void *user_context) /* Destroy key */ entry->refcnt--; - if (entry->refcnt == 0) { - switch (entry->key.pk_type) { - case SILC_PKCS_SILC: - silc_pkcs_public_key_free(entry->key.key); - break; - - default: - break; - } + if (entry->refcnt > 0) + return; - silc_free(entry); - } + silc_pkcs_public_key_free(entry->key.key); + silc_free(entry); } /* Hash table hash function for key entries */ @@ -285,11 +277,16 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, SilcSKRKeyUsage usage, void *key_context) { - SilcPublicKeyIdentifier ident = NULL; SilcSKRKeyInternal key; SilcSKRStatus status = SILC_SKR_ERROR; + SilcPublicKeyIdentifier ident; + SilcSILCPublicKey silc_pubkey; + + /* Get the SILC public key */ + silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key); + ident = &silc_pubkey->identifier; - SILC_LOG_DEBUG(("Adding SILC public key [%s]", public_key->identifier)); + SILC_LOG_DEBUG(("Adding SILC public key [%s]", ident->username)); silc_mutex_lock(skr->lock); @@ -298,7 +295,7 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, public_key, NULL, key_context, 0)) { silc_mutex_unlock(skr->lock); SILC_LOG_DEBUG(("Key already added")); - return status; + return status | SILC_SKR_ALREADY_EXIST; } /* Allocate key entry */ @@ -309,17 +306,9 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, } key->key.usage = usage; - key->key.pk_type = public_key->pk_type; key->key.key = public_key; key->key.key_context = key_context; - ident = silc_pkcs_decode_identifier(public_key->identifier); - if (!ident) { - silc_mutex_unlock(skr->lock); - silc_pkcs_free_identifier(ident); - return status | SILC_SKR_NO_MEMORY; - } - /* Add key specifics */ if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, @@ -328,7 +317,7 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, key->refcnt++; if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE, - SILC_32_TO_PTR(public_key->pk_type), key)) + SILC_32_TO_PTR(SILC_PKCS_SILC), key)) goto err; key->refcnt++; @@ -383,12 +372,10 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, silc_mutex_unlock(skr->lock); - silc_free(ident); return SILC_SKR_OK; err: silc_mutex_unlock(skr->lock); - silc_free(ident); return status; } @@ -403,7 +390,7 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, SilcSKRKeyInternal key; SilcSKRStatus status = SILC_SKR_ERROR; - SILC_LOG_DEBUG(("Adding SILC public key [%s]", public_key->identifier)); + SILC_LOG_DEBUG(("Adding SILC public key")); silc_mutex_lock(skr->lock); @@ -412,7 +399,7 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, public_key, NULL, key_context, 0)) { silc_mutex_unlock(skr->lock); SILC_LOG_DEBUG(("Key already added")); - return status; + return status | SILC_SKR_ALREADY_EXIST; } /* Allocate key entry */ @@ -423,7 +410,6 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, } key->key.usage = usage; - key->key.pk_type = public_key->pk_type; key->key.key = public_key; key->key.key_context = key_context; @@ -567,12 +553,16 @@ SilcSKRStatus silc_skr_add_public_key(SilcSKR skr, SilcSKRKeyUsage usage, void *key_context) { + SilcPKCSType type; + if (!public_key) return SILC_SKR_ERROR; + type = silc_pkcs_get_type(public_key); + SILC_LOG_DEBUG(("Adding public key to repository")); - switch (public_key->pk_type) { + switch (type) { case SILC_PKCS_SILC: return silc_skr_add_silc(skr, public_key, usage, key_context); @@ -592,12 +582,16 @@ SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr, SilcSKRKeyUsage usage, void *key_context) { + SilcPKCSType type; + if (!public_key) return SILC_SKR_ERROR; + type = silc_pkcs_get_type(public_key); + SILC_LOG_DEBUG(("Adding public key to repository")); - switch (public_key->pk_type) { + switch (type) { case SILC_PKCS_SILC: return silc_skr_add_silc_simple(skr, public_key, usage, key_context); @@ -809,36 +803,3 @@ SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find, return NULL; } - -/* Helper function to find specificly SILC style public keys */ - -SilcAsyncOperation silc_skr_find_silc(SilcSKR skr, - SilcPublicKey public_key, - SilcSKRFindCallback callback, - void *callback_context) -{ - SilcSKRFind find = NULL; - SilcAsyncOperation op; - - SILC_LOG_DEBUG(("Finding SILC public key")); - - if (!public_key || public_key->pk_type != SILC_PKCS_SILC) - goto err; - - find = silc_skr_find_alloc(); - if (!find) - goto err; - - if (!silc_skr_find_set_public_key(find, public_key)) - goto err; - - op = silc_skr_find(skr, find, callback, callback_context); - - return op; - - err: - if (find) - silc_skr_find_free(find); - callback(skr, NULL, SILC_SKR_ERROR, NULL, callback_context); - return NULL; -} diff --git a/lib/silcskr/silcskr.h b/lib/silcskr/silcskr.h index a2e9abfd..c0ede323 100644 --- a/lib/silcskr/silcskr.h +++ b/lib/silcskr/silcskr.h @@ -95,26 +95,20 @@ typedef enum { * * NAME * - * typedef struct SilcSKRKeyStruct { ... } *SilcSKRKey + * typedef struct SilcSKRKeyStruct { ... } *SilcSKRKey; * * DESCRIPTION * - * This context holds the public key cryptosystem key type and the key - * context that has been saved in the key repository. This context is - * returned in the SilcSKRFindCallback list. Each entry in the list is - * SilcSKRKey. - * - * The key context saved in SilcSKRKey is based on the PKCS type and - * caller can explicitly type cast the key to correct type based on the - * PKCS type. + * This context holds the public key, optional public key specific + * context and public key usage bits. This context is returned in + * the SilcSKRFindCallback list. Each entry in the list is SIlcSKRKey. * * SOURCE * */ typedef struct SilcSKRKeyStruct { SilcSKRKeyUsage usage; /* Key usage */ - SilcPKCSType pk_type; /* PKCS type */ - void *key; /* SILC_PKCS_SILC: SilcPublicKey */ + SilcPublicKey key; /* Public key */ void *key_context; /* Optional key specific context */ } *SilcSKRKey; /***/ @@ -251,7 +245,7 @@ void silc_skr_uninit(SilcSKR skr); * * // Add a key to repository * if (silc_skr_add_public_key(repository, public_key, - * SILC_SKR_USAGW_ANY, NULL) != SILC_SKR_OK) + * SILC_SKR_USAGE_ANY, NULL) != SILC_SKR_OK) * goto error; * ***/ @@ -494,39 +488,14 @@ SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage); * `find'. As the finding procedure may be asynchronous this returns * SilcAsyncOperation that may be used to control (like abort) the * operation. The `callback' with `callback_context' will be called - * to return found keys. If this returns NULL, operation cannot be - * controlled, however it is not an error. + * to return found keys. If this returns NULL the finding was not + * asynchronous, and the `callback' has been called already. * ***/ SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find, SilcSKRFindCallback callback, void *callback_context); -/****f* silcskr/SilcSKRAPI/silc_skr_find_silc - * - * SYNOPSIS - * - * SilcAsyncOperation silc_skr_find_silc(SilcSKR skr, - * SilcPublicKey public_key, - * SilcSKRFindCallback callback, - * void *callback_context); - * - * DESCRIPTION - * - * A helper function that can be used to find specificly SILC style - * public keys from the repository. This returns found key(s) by - * the `public_key'. As the finding procedure may be asynchronous - * this returns SilcAsyncOperation that may be used to control (like - * abort) the operation. The `callback' with `callback_context' will - * be called to return found keys. If this returns NULL, operation - * cannot be controlled, however it is not an error. - * - ***/ -SilcAsyncOperation silc_skr_find_silc(SilcSKR skr, - SilcPublicKey public_key, - SilcSKRFindCallback callback, - void *callback_context); - #include "silcskr_i.h" #endif /* SILCSKR_H */ diff --git a/lib/silcutil/silcapputil.c b/lib/silcutil/silcapputil.c index d1d6739f..ff85ccf1 100644 --- a/lib/silcutil/silcapputil.c +++ b/lib/silcutil/silcapputil.c @@ -42,8 +42,8 @@ static char *silc_create_pk_identifier(void) /* Create default email address, whether it is right or not */ snprintf(email, sizeof(email), "%s@%s", username, hostname); - ident = silc_pkcs_encode_identifier(username, hostname, realname, email, - NULL, NULL); + ident = silc_pkcs_silc_encode_identifier(username, hostname, realname, + email, NULL, NULL); if (realname) silc_free(realname); silc_free(hostname); @@ -55,22 +55,16 @@ static char *silc_create_pk_identifier(void) /* Generate key pair */ SilcBool silc_create_key_pair(const char *pkcs_name, - SilcUInt32 key_len_bits, - const char *pub_filename, - const char *prv_filename, - const char *pub_identifier, - const char *passphrase, - SilcPKCS *return_pkcs, - SilcPublicKey *return_public_key, - SilcPrivateKey *return_private_key, - SilcBool interactive) + SilcUInt32 key_len_bits, + const char *pub_filename, + const char *prv_filename, + const char *pub_identifier, + const char *passphrase, + SilcPublicKey *return_public_key, + SilcPrivateKey *return_private_key, + SilcBool interactive) { - SilcPKCS pkcs; - SilcPublicKey pub_key; - SilcPrivateKey prv_key; SilcRng rng; - unsigned char *key; - SilcUInt32 key_len; char line[256]; char *pkfile = pub_filename ? strdup(pub_filename) : NULL; char *prvfile = prv_filename ? strdup(prv_filename) : NULL; @@ -103,7 +97,7 @@ New pair of keys will be created. Please, answer to following questions.\n\ } } - if (!silc_pkcs_is_supported(alg)) { + if (!silc_pkcs_find_algorithm(alg, NULL)) { fprintf(stderr, "Unknown PKCS algorithm `%s' or crypto library" "is not initialized", alg); return FALSE; @@ -197,34 +191,18 @@ New pair of keys will be created. Please, answer to following questions.\n\ } /* Generate keys */ - silc_pkcs_alloc(alg, SILC_PKCS_SILC, &pkcs); - silc_pkcs_generate_key(pkcs, key_len_bits, rng); + if (!silc_pkcs_silc_generate_key(alg, "pkcs1-no-oid", key_len_bits, + identifier, rng, return_public_key, + return_private_key)) + return FALSE; /* Save public key into file */ - key = silc_pkcs_get_public_key(pkcs, &key_len); - pub_key = silc_pkcs_public_key_alloc(silc_pkcs_get_name(pkcs), - identifier, key, key_len); - silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM); - if (return_public_key) - *return_public_key = pub_key; - else - silc_pkcs_public_key_free(pub_key); - memset(key, 0, key_len); - silc_free(key); + silc_pkcs_save_public_key(pkfile, *return_public_key, SILC_PKCS_FILE_BASE64); /* Save private key into file */ - key = silc_pkcs_get_private_key(pkcs, &key_len); - prv_key = silc_pkcs_private_key_alloc(silc_pkcs_get_name(pkcs), - key, key_len); - silc_pkcs_save_private_key(prvfile, prv_key, - (unsigned char *)pass, strlen(pass), - SILC_PKCS_FILE_BIN); - if (return_private_key) - *return_private_key = prv_key; - else - silc_pkcs_private_key_free(prv_key); - memset(key, 0, key_len); - silc_free(key); + silc_pkcs_save_private_key(prvfile, *return_private_key, + (const unsigned char *)pass, strlen(pass), + SILC_PKCS_FILE_BIN, rng); printf("Public key has been saved into `%s'.\n", pkfile); printf("Private key has been saved into `%s'.\n", prvfile); @@ -233,11 +211,6 @@ New pair of keys will be created. Please, answer to following questions.\n\ getchar(); } - if (return_pkcs) - *return_pkcs = pkcs; - else - silc_pkcs_free(pkcs); - silc_rng_free(rng); silc_free(alg); silc_free(pkfile); @@ -252,25 +225,21 @@ New pair of keys will be created. Please, answer to following questions.\n\ /* Load key pair */ SilcBool silc_load_key_pair(const char *pub_filename, - const char *prv_filename, - const char *passphrase, - SilcPKCS *return_pkcs, - SilcPublicKey *return_public_key, - SilcPrivateKey *return_private_key) + const char *prv_filename, + const char *passphrase, + SilcPublicKey *return_public_key, + SilcPrivateKey *return_private_key) { char *pass = passphrase ? strdup(passphrase) : NULL; SILC_LOG_DEBUG(("Loading public and private keys")); - if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key, - SILC_PKCS_FILE_PEM) == FALSE) - if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key, - SILC_PKCS_FILE_BIN) == FALSE) { - if (pass) - memset(pass, 0, strlen(pass)); - silc_free(pass); - return FALSE; - } + if (!silc_pkcs_load_public_key(pub_filename, return_public_key)) { + if (pass) + memset(pass, 0, strlen(pass)); + silc_free(pass); + return FALSE; + } if (!pass) { pass = silc_get_input("Private key passphrase: ", TRUE); @@ -278,21 +247,12 @@ SilcBool silc_load_key_pair(const char *pub_filename, pass = strdup(""); } - if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key, - (unsigned char *)pass, strlen(pass), - SILC_PKCS_FILE_BIN) == FALSE) - if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key, - (unsigned char *)pass, strlen(pass), - SILC_PKCS_FILE_PEM) == FALSE) { - memset(pass, 0, strlen(pass)); - silc_free(pass); - return FALSE; - } - - if (return_pkcs) { - silc_pkcs_alloc((*return_public_key)->name, SILC_PKCS_SILC, return_pkcs); - silc_pkcs_public_key_set(*return_pkcs, *return_public_key); - silc_pkcs_private_key_set(*return_pkcs, *return_private_key); + if (!silc_pkcs_load_private_key(prv_filename, + (const unsigned char *)pass, strlen(pass), + return_private_key)) { + memset(pass, 0, strlen(pass)); + silc_free(pass); + return FALSE; } memset(pass, 0, strlen(pass)); @@ -305,34 +265,36 @@ SilcBool silc_load_key_pair(const char *pub_filename, SilcBool silc_show_public_key(const char *pub_filename) { SilcPublicKey public_key; + SilcSILCPublicKey silc_pubkey; SilcPublicKeyIdentifier ident; char *fingerprint, *babbleprint; unsigned char *pk; SilcUInt32 pk_len; - SilcPKCS pkcs; SilcUInt32 key_len = 0; - if (silc_pkcs_load_public_key((char *)pub_filename, &public_key, - SILC_PKCS_FILE_PEM) == FALSE) - if (silc_pkcs_load_public_key((char *)pub_filename, &public_key, - SILC_PKCS_FILE_BIN) == FALSE) { - fprintf(stderr, "Could not load public key file `%s'\n", pub_filename); - return FALSE; - } + if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) { + fprintf(stderr, "Could not load public key file `%s'\n", pub_filename); + return FALSE; + } - ident = silc_pkcs_decode_identifier(public_key->identifier); + silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key); + if (!silc_pubkey) { + silc_pkcs_public_key_free(public_key); + return FALSE; + } + ident = &silc_pubkey->identifier; + key_len = silc_pkcs_public_key_get_len(public_key); pk = silc_pkcs_public_key_encode(public_key, &pk_len); + if (!pk) { + silc_pkcs_public_key_free(public_key); + return FALSE; + } fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); - if (silc_pkcs_alloc(public_key->name, SILC_PKCS_SILC, &pkcs)) { - key_len = silc_pkcs_public_key_set(pkcs, public_key); - silc_pkcs_free(pkcs); - } - printf("Public key file : %s\n", pub_filename); - printf("Algorithm : %s\n", public_key->name); + printf("Algorithm : %s\n", silc_pkcs_get_name(public_key)); if (key_len) printf("Key length (bits) : %d\n", (unsigned int)key_len); if (ident->realname) @@ -356,7 +318,6 @@ SilcBool silc_show_public_key(const char *pub_filename) silc_free(babbleprint); silc_free(pk); silc_pkcs_public_key_free(public_key); - silc_pkcs_free_identifier(ident); return TRUE; } @@ -364,12 +325,12 @@ SilcBool silc_show_public_key(const char *pub_filename) /* Change private key passphrase */ SilcBool silc_change_private_key_passphrase(const char *prv_filename, - const char *old_passphrase, - const char *new_passphrase) + const char *old_passphrase, + const char *new_passphrase) { SilcPrivateKey private_key; - SilcBool base64 = FALSE; char *pass; + SilcRng rng; pass = old_passphrase ? strdup(old_passphrase) : NULL; if (!pass) { @@ -378,18 +339,13 @@ SilcBool silc_change_private_key_passphrase(const char *prv_filename, pass = strdup(""); } - if (silc_pkcs_load_private_key((char *)prv_filename, &private_key, - (unsigned char *)pass, strlen(pass), - SILC_PKCS_FILE_BIN) == FALSE) { - base64 = TRUE; - if (silc_pkcs_load_private_key((char *)prv_filename, &private_key, - (unsigned char *)pass, strlen(pass), - SILC_PKCS_FILE_PEM) == FALSE) { - memset(pass, 0, strlen(pass)); - silc_free(pass); - fprintf(stderr, "Could not load private key `%s' file\n", prv_filename); - return FALSE; - } + if (!silc_pkcs_load_private_key(prv_filename, + (const unsigned char *)pass, strlen(pass), + &private_key)) { + memset(pass, 0, strlen(pass)); + silc_free(pass); + fprintf(stderr, "Could not load private key `%s' file\n", prv_filename); + return FALSE; } memset(pass, 0, strlen(pass)); @@ -416,9 +372,12 @@ SilcBool silc_change_private_key_passphrase(const char *prv_filename, } } + rng = silc_rng_alloc(); + silc_rng_init(rng); + silc_pkcs_save_private_key((char *)prv_filename, private_key, (unsigned char *)pass, strlen(pass), - base64 ? SILC_PKCS_FILE_PEM : SILC_PKCS_FILE_BIN); + SILC_PKCS_FILE_BIN, rng); fprintf(stdout, "\nPassphrase changed\n"); @@ -426,5 +385,7 @@ SilcBool silc_change_private_key_passphrase(const char *prv_filename, silc_free(pass); silc_pkcs_private_key_free(private_key); + silc_rng_free(rng); + return TRUE; } diff --git a/lib/silcutil/silcapputil.h b/lib/silcutil/silcapputil.h index 8b903931..fd171735 100644 --- a/lib/silcutil/silcapputil.h +++ b/lib/silcutil/silcapputil.h @@ -1,10 +1,10 @@ /* - silcapputil.h + silcapputil.h Author: Pekka Riikonen - Copyright (C) 2002 Pekka Riikonen + Copyright (C) 2002 - 2005 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 @@ -40,15 +40,14 @@ * SYNOPSIS * * SilcBool silc_create_key_pair(const char *pkcs_name, - * SilcUInt32 key_len_bits, - * const char *pub_filename, - * const char *prv_filename, - * const char *pub_identifier, - * const char *passphrase, - * SilcPKCS *return_pkcs, - * SilcPublicKey *return_public_key, - * SilcPrivateKey *return_private_key, - * SilcBool interactive); + * SilcUInt32 key_len_bits, + * const char *pub_filename, + * const char *prv_filename, + * const char *pub_identifier, + * const char *passphrase, + * SilcPublicKey *return_public_key, + * SilcPrivateKey *return_private_key, + * SilcBool interactive); * * DESCRIPTION * @@ -65,12 +64,6 @@ * private key file. It is recommended that you would protect your * private key file with a passphrase. * - * The routine returns FALSE if error occurs during key generation. - * Function returns TRUE when success and returns the created SilcPKCS - * object, which can be used to perform public key cryptography into - * `return_pkcs' pointer, created public key into `return_public_key', - * and created private key into `return_private_key' pointer. - * * If the `interactive' is TRUE then this asks the user (by blocking * the process for input) some questions about key generation (like * public key algorithm, key length, filenames, etc). If all @@ -85,45 +78,40 @@ * ***/ SilcBool silc_create_key_pair(const char *pkcs_name, - SilcUInt32 key_len_bits, - const char *pub_filename, - const char *prv_filename, - const char *pub_identifier, - const char *passphrase, - SilcPKCS *return_pkcs, - SilcPublicKey *return_public_key, - SilcPrivateKey *return_private_key, - SilcBool interactive); + SilcUInt32 key_len_bits, + const char *pub_filename, + const char *prv_filename, + const char *pub_identifier, + const char *passphrase, + SilcPublicKey *return_public_key, + SilcPrivateKey *return_private_key, + SilcBool interactive); /****f* silcutil/SilcAppUtil/silc_load_key_pair * * SYNOPSIS * * SilcBool silc_load_key_pair(const char *pub_filename, - * const char *prv_filename, - * const char *passphrase, - * SilcPKCS *return_pkcs, - * SilcPublicKey *return_public_key, - * SilcPrivateKey *return_private_key); + * const char *prv_filename, + * const char *passphrase, + * SilcPublicKey *return_public_key, + * SilcPrivateKey *return_private_key); * * DESCRIPTION * * This routine can be used to load the public key and private key * from files. This retuns FALSE it either of the key could not be * loaded. This function returns TRUE on success and returns the - * public key into `return_public_key' pointer, private key into - * `return_private_key' pointer and the SilcPKCS object to the - * `return_pkcs'. The SilcPKCS can be used to perform public key - * cryptographic operations. The `passphrase' is the passphrase - * which will be used to decrypt the private key file. + * public key into `return_public_key' pointer and private key into + * `return_private_key'. The `passphrase' is the passphrase which + * will be used to decrypt the private key file. * ***/ SilcBool silc_load_key_pair(const char *pub_filename, - const char *prv_filename, - const char *passphrase, - SilcPKCS *return_pkcs, - SilcPublicKey *return_public_key, - SilcPrivateKey *return_private_key); + const char *prv_filename, + const char *passphrase, + SilcPublicKey *return_public_key, + SilcPrivateKey *return_private_key); /****f* silcutil/SilcAppUtil/silc_show_public_key * @@ -145,8 +133,8 @@ SilcBool silc_show_public_key(const char *pub_filename); * SYNOPSIS * * SilcBool silc_change_private_key_passphrase(const char *prv_filename, - * const char *old_passphrase, - * const char *new_passphrase); + * const char *old_passphrase, + * const char *new_passphrase); * * DESCRIPTION * @@ -157,7 +145,7 @@ SilcBool silc_show_public_key(const char *pub_filename); * ***/ SilcBool silc_change_private_key_passphrase(const char *prv_filename, - const char *old_passphrase, - const char *new_passphrase); + const char *old_passphrase, + const char *new_passphrase); #endif /* SILCAPPUTIL_H */ diff --git a/lib/silcutil/silcutil.c b/lib/silcutil/silcutil.c index 86b2f850..e0e664fa 100644 --- a/lib/silcutil/silcutil.c +++ b/lib/silcutil/silcutil.c @@ -593,14 +593,23 @@ SilcUInt32 silc_hash_data(void *key, void *user_context) return h; } -/* Hashed SILC Public key. */ +/* Hash public key of any type. */ SilcUInt32 silc_hash_public_key(void *key, void *user_context) { - SilcPublicKey pk = (SilcPublicKey)key; - return (pk->len + (silc_hash_string(pk->name, NULL) ^ - silc_hash_string(pk->identifier, NULL) ^ - silc_hash_data(pk->pk, SILC_32_TO_PTR(pk->pk_len)))); + SilcPublicKey public_key = key; + unsigned char *pk; + SilcUInt32 pk_len; + SilcUInt32 hash = 0; + + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + if (!pk) + return hash; + + hash = silc_hash_data(pk, SILC_32_TO_PTR(pk_len)); + silc_free(pk); + + return hash; } /* Compares two strings. It may be used as SilcHashTable comparison @@ -633,7 +642,8 @@ SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context) /* Compare two Client ID's entirely and not just the hash from the ID. */ -SilcBool silc_hash_client_id_compare(void *key1, void *key2, void *user_context) +SilcBool silc_hash_client_id_compare(void *key1, void *key2, + void *user_context) { return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT); } @@ -660,7 +670,8 @@ SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context) /* 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) +SilcBool silc_hash_public_key_compare(void *key1, void *key2, + void *user_context) { return silc_pkcs_public_key_compare(key1, key2); } diff --git a/lib/silcutil/silcutil.h b/lib/silcutil/silcutil.h index 1e2a68ea..2f7ca306 100644 --- a/lib/silcutil/silcutil.h +++ b/lib/silcutil/silcutil.h @@ -290,7 +290,7 @@ SilcUInt32 silc_hash_data(void *key, void *user_context); * * DESCRIPTION * - * Hashed SILC Public key. + * Hash public key of any type. * ***/ SilcUInt32 silc_hash_public_key(void *key, void *user_context); -- 2.24.0