From f3e0f2b9e635609e9740dcd96935e9eca007d55d Mon Sep 17 00:00:00 2001 From: Jim Hague Date: Tue, 20 Nov 2018 16:51:17 +0000 Subject: [PATCH] Split OpenSSL specific bits of keyraw.hc into keyraw-internal.hc. All usage is internal to val_secalgo.c, which is already in openssl. --- src/Makefile.in | 19 +- src/gldns/keyraw.c | 332 -------------------------------- src/gldns/keyraw.h | 83 +------- src/openssl/keyraw-internal.c | 348 ++++++++++++++++++++++++++++++++++ src/openssl/keyraw-internal.h | 110 +++++++++++ 5 files changed, 471 insertions(+), 421 deletions(-) create mode 100644 src/openssl/keyraw-internal.c create mode 100644 src/openssl/keyraw-internal.h diff --git a/src/Makefile.in b/src/Makefile.in index 4e1085a8..8da886c5 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -94,7 +94,7 @@ COMPAT_OBJ=$(LIBOBJS:.o=.lo) UTIL_OBJ=rbtree.lo lruhash.lo lookup3.lo locks.lo JSMN_OBJ=jsmn.lo -TLS_OBJ=tls.lo pubkey-pinning.lo val_secalgo.lo +TLS_OBJ=tls.lo pubkey-pinning.lo keyraw-internal.lo val_secalgo.lo YXML_OBJ=yxml.lo YAML_OBJ=convert_yaml_to_json.lo @@ -308,8 +308,8 @@ anchor.lo anchor.o: $(srcdir)/anchor.c config.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/tls.h $(srcdir)/openssl/tls-internal.h \ $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/yxml/yxml.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/str2wire.h \ - $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/keyraw.h $(srcdir)/general.h $(srcdir)/util-internal.h \ - $(srcdir)/platform.h + $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/keyraw.h $(srcdir)/openssl/keyraw-internal.h \ + $(srcdir)/general.h $(srcdir)/util-internal.h $(srcdir)/platform.h const-info.lo const-info.o: $(srcdir)/const-info.c \ getdns/getdns.h \ getdns/getdns_extra.h \ @@ -352,8 +352,8 @@ dnssec.lo dnssec.o: $(srcdir)/dnssec.c config.h \ $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/openssl/tls-internal.h $(srcdir)/util-internal.h \ $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h \ - $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h $(srcdir)/general.h $(srcdir)/dict.h $(srcdir)/list.h \ - $(srcdir)/util/val_secalgo.h $(srcdir)/util/orig-headers/val_secalgo.h + $(srcdir)/gldns/keyraw.h $(srcdir)/openssl/keyraw-internal.h $(srcdir)/gldns/parseutil.h $(srcdir)/general.h \ + $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/util/val_secalgo.h $(srcdir)/util/orig-headers/val_secalgo.h general.lo general.o: $(srcdir)/general.c config.h \ $(srcdir)/general.h getdns/getdns.h \ $(srcdir)/types-internal.h \ @@ -447,7 +447,7 @@ gbuffer.lo gbuffer.o: $(srcdir)/gldns/gbuffer.c \ config.h $(srcdir)/gldns/gbuffer.h keyraw.lo keyraw.o: $(srcdir)/gldns/keyraw.c \ config.h $(srcdir)/gldns/keyraw.h \ - $(srcdir)/gldns/rrdef.h + $(srcdir)/openssl/keyraw-internal.h parse.lo parse.o: $(srcdir)/gldns/parse.c \ config.h $(srcdir)/gldns/parse.h \ $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h @@ -463,7 +463,7 @@ str2wire.lo str2wire.o: $(srcdir)/gldns/str2wire.c \ wire2str.lo wire2str.o: $(srcdir)/gldns/wire2str.c \ config.h $(srcdir)/gldns/wire2str.h \ $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/parseutil.h \ - $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/keyraw.h + $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/keyraw.h $(srcdir)/openssl/keyraw-internal.h arc4_lock.lo arc4_lock.o: $(srcdir)/compat/arc4_lock.c \ config.h arc4random.lo arc4random.o: $(srcdir)/compat/arc4random.c \ @@ -509,6 +509,9 @@ rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c \ $(srcdir)/util/auxiliary/util/fptr_wlist.h $(srcdir)/util/rbtree.h \ $(srcdir)/util/orig-headers/rbtree.h jsmn.lo jsmn.o: $(srcdir)/jsmn/jsmn.c $(srcdir)/jsmn/jsmn.h +keyraw-internal.lo keyraw-internal.o: $(srcdir)/openssl/keyraw-internal.c \ + config.h $(srcdir)/gldns/keyraw.h \ + $(srcdir)/openssl/keyraw-internal.h $(srcdir)/gldns/rrdef.h pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/openssl/pubkey-pinning.c \ config.h $(srcdir)/debug.h \ getdns/getdns.h $(srcdir)/context.h \ @@ -533,7 +536,7 @@ val_secalgo.lo val_secalgo.o: $(srcdir)/openssl/val_secalgo.c \ $(srcdir)/util/orig-headers/val_secalgo.h $(srcdir)/util/auxiliary/validator/val_nsec3.h \ $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/util/auxiliary/sldns/rrdef.h \ $(srcdir)/gldns/rrdef.h $(srcdir)/util/auxiliary/sldns/keyraw.h $(srcdir)/gldns/keyraw.h \ - $(srcdir)/util/auxiliary/sldns/sbuffer.h $(srcdir)/gldns/gbuffer.h + $(srcdir)/openssl/keyraw-internal.h $(srcdir)/util/auxiliary/sldns/sbuffer.h $(srcdir)/gldns/gbuffer.h yxml.lo yxml.o: $(srcdir)/yxml/yxml.c $(srcdir)/yxml/yxml.h libev.lo libev.o: $(srcdir)/extension/libev.c \ config.h $(srcdir)/types-internal.h \ diff --git a/src/gldns/keyraw.c b/src/gldns/keyraw.c index db84743e..e59189e0 100644 --- a/src/gldns/keyraw.c +++ b/src/gldns/keyraw.c @@ -14,26 +14,6 @@ #include "gldns/keyraw.h" #include "gldns/rrdef.h" -#ifdef HAVE_SSL -#include -#include -#include -#include -#include -#ifdef HAVE_OPENSSL_ENGINE_H -# include -#endif -#ifdef HAVE_OPENSSL_BN_H -#include -#endif -#ifdef HAVE_OPENSSL_RSA_H -#include -#endif -#ifdef HAVE_OPENSSL_DSA_H -#include -#endif -#endif /* HAVE_SSL */ - size_t gldns_rr_dnskey_key_size_raw(const unsigned char* keydata, const size_t len, int alg) @@ -126,315 +106,3 @@ uint16_t gldns_calc_keytag_raw(const uint8_t* key, size_t keysize) return (uint16_t) (ac32 & 0xFFFF); } } - -#ifdef HAVE_SSL -#ifdef USE_GOST -/** store GOST engine reference loaded into OpenSSL library */ -ENGINE* gldns_gost_engine = NULL; - -int -gldns_key_EVP_load_gost_id(void) -{ - static int gost_id = 0; - const EVP_PKEY_ASN1_METHOD* meth; - ENGINE* e; - - if(gost_id) return gost_id; - - /* see if configuration loaded gost implementation from other engine*/ - meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1); - if(meth) { - EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); - return gost_id; - } - - /* see if engine can be loaded already */ - e = ENGINE_by_id("gost"); - if(!e) { - /* load it ourself, in case statically linked */ - ENGINE_load_builtin_engines(); - ENGINE_load_dynamic(); - e = ENGINE_by_id("gost"); - } - if(!e) { - /* no gost engine in openssl */ - return 0; - } - if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { - ENGINE_finish(e); - ENGINE_free(e); - return 0; - } - - meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1); - if(!meth) { - /* algo not found */ - ENGINE_finish(e); - ENGINE_free(e); - return 0; - } - /* Note: do not ENGINE_finish and ENGINE_free the acquired engine - * on some platforms this frees up the meth and unloads gost stuff */ - gldns_gost_engine = e; - - EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); - return gost_id; -} - -void gldns_key_EVP_unload_gost(void) -{ - if(gldns_gost_engine) { - ENGINE_finish(gldns_gost_engine); - ENGINE_free(gldns_gost_engine); - gldns_gost_engine = NULL; - } -} -#endif /* USE_GOST */ - -DSA * -gldns_key_buf2dsa_raw(unsigned char* key, size_t len) -{ - uint8_t T; - uint16_t length; - uint16_t offset; - DSA *dsa; - BIGNUM *Q; BIGNUM *P; - BIGNUM *G; BIGNUM *Y; - - if(len == 0) - return NULL; - T = (uint8_t)key[0]; - length = (64 + T * 8); - offset = 1; - - if (T > 8) { - return NULL; - } - if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length) - return NULL; - - Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL); - offset += SHA_DIGEST_LENGTH; - - P = BN_bin2bn(key+offset, (int)length, NULL); - offset += length; - - G = BN_bin2bn(key+offset, (int)length, NULL); - offset += length; - - Y = BN_bin2bn(key+offset, (int)length, NULL); - - /* create the key and set its properties */ - if(!Q || !P || !G || !Y || !(dsa = DSA_new())) { - BN_free(Q); - BN_free(P); - BN_free(G); - BN_free(Y); - return NULL; - } - if (!DSA_set0_pqg(dsa, P, Q, G)) { - /* QPG not yet attached, need to free */ - BN_free(Q); - BN_free(P); - BN_free(G); - - DSA_free(dsa); - BN_free(Y); - return NULL; - } - if (!DSA_set0_key(dsa, Y, NULL)) { - /* QPG attached, cleaned up by DSA_fre() */ - DSA_free(dsa); - BN_free(Y); - return NULL; - } - - return dsa; -} - -RSA * -gldns_key_buf2rsa_raw(unsigned char* key, size_t len) -{ - uint16_t offset; - uint16_t exp; - uint16_t int16; - RSA *rsa; - BIGNUM *modulus; - BIGNUM *exponent; - - if (len == 0) - return NULL; - if (key[0] == 0) { - if(len < 3) - return NULL; - memmove(&int16, key+1, 2); - exp = ntohs(int16); - offset = 3; - } else { - exp = key[0]; - offset = 1; - } - - /* key length at least one */ - if(len < (size_t)offset + exp + 1) - return NULL; - - /* Exponent */ - exponent = BN_new(); - if(!exponent) return NULL; - (void) BN_bin2bn(key+offset, (int)exp, exponent); - offset += exp; - - /* Modulus */ - modulus = BN_new(); - if(!modulus) { - BN_free(exponent); - return NULL; - } - /* length of the buffer must match the key length! */ - (void) BN_bin2bn(key+offset, (int)(len - offset), modulus); - - rsa = RSA_new(); - if(!rsa) { - BN_free(exponent); - BN_free(modulus); - return NULL; - } - if (!RSA_set0_key(rsa, modulus, exponent, NULL)) { - BN_free(exponent); - BN_free(modulus); - RSA_free(rsa); - return NULL; - } - - return rsa; -} - -#ifdef USE_GOST -EVP_PKEY* -gldns_gost2pkey_raw(unsigned char* key, size_t keylen) -{ - /* prefix header for X509 encoding */ - uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, - 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, - 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, - 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40}; - unsigned char encoded[37+64]; - const unsigned char* pp; - if(keylen != 64) { - /* key wrong size */ - return NULL; - } - - /* create evp_key */ - memmove(encoded, asn, 37); - memmove(encoded+37, key, 64); - pp = (unsigned char*)&encoded[0]; - - return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded)); -} -#endif /* USE_GOST */ - -#ifdef USE_ECDSA -EVP_PKEY* -gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo) -{ - unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */ - const unsigned char* pp = buf; - EVP_PKEY *evp_key; - EC_KEY *ec; - /* check length, which uncompressed must be 2 bignums */ - if(algo == GLDNS_ECDSAP256SHA256) { - if(keylen != 2*256/8) return NULL; - ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - } else if(algo == GLDNS_ECDSAP384SHA384) { - if(keylen != 2*384/8) return NULL; - ec = EC_KEY_new_by_curve_name(NID_secp384r1); - } else ec = NULL; - if(!ec) return NULL; - if(keylen+1 > sizeof(buf)) { /* sanity check */ - EC_KEY_free(ec); - return NULL; - } - /* prepend the 0x02 (from docs) (or actually 0x04 from implementation - * of openssl) for uncompressed data */ - buf[0] = POINT_CONVERSION_UNCOMPRESSED; - memmove(buf+1, key, keylen); - if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) { - EC_KEY_free(ec); - return NULL; - } - evp_key = EVP_PKEY_new(); - if(!evp_key) { - EC_KEY_free(ec); - return NULL; - } - if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) { - EVP_PKEY_free(evp_key); - EC_KEY_free(ec); - return NULL; - } - return evp_key; -} -#endif /* USE_ECDSA */ - -#ifdef USE_ED25519 -EVP_PKEY* -gldns_ed255192pkey_raw(const unsigned char* key, size_t keylen) -{ - /* ASN1 for ED25519 is 302a300506032b6570032100 <32byteskey> */ - uint8_t pre[] = {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, - 0x70, 0x03, 0x21, 0x00}; - int pre_len = 12; - uint8_t buf[256]; - EVP_PKEY *evp_key; - /* pp gets modified by d2i() */ - const unsigned char* pp = (unsigned char*)buf; - if(keylen != 32 || keylen + pre_len > sizeof(buf)) - return NULL; /* wrong length */ - memmove(buf, pre, pre_len); - memmove(buf+pre_len, key, keylen); - evp_key = d2i_PUBKEY(NULL, &pp, (int)(pre_len+keylen)); - return evp_key; -} -#endif /* USE_ED25519 */ - -#ifdef USE_ED448 -EVP_PKEY* -gldns_ed4482pkey_raw(const unsigned char* key, size_t keylen) -{ - /* ASN1 for ED448 is 3043300506032b6571033a00 <57byteskey> */ - uint8_t pre[] = {0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, - 0x71, 0x03, 0x3a, 0x00}; - int pre_len = 12; - uint8_t buf[256]; - EVP_PKEY *evp_key; - /* pp gets modified by d2i() */ - const unsigned char* pp = (unsigned char*)buf; - if(keylen != 57 || keylen + pre_len > sizeof(buf)) - return NULL; /* wrong length */ - memmove(buf, pre, pre_len); - memmove(buf+pre_len, key, keylen); - evp_key = d2i_PUBKEY(NULL, &pp, (int)(pre_len+keylen)); - return evp_key; -} -#endif /* USE_ED448 */ - -int -gldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest, - const EVP_MD* md) -{ - EVP_MD_CTX* ctx; - ctx = EVP_MD_CTX_create(); - if(!ctx) - return 0; - if(!EVP_DigestInit_ex(ctx, md, NULL) || - !EVP_DigestUpdate(ctx, data, len) || - !EVP_DigestFinal_ex(ctx, dest, NULL)) { - EVP_MD_CTX_destroy(ctx); - return 0; - } - EVP_MD_CTX_destroy(ctx); - return 1; -} -#endif /* HAVE_SSL */ diff --git a/src/gldns/keyraw.h b/src/gldns/keyraw.h index a847887c..caefad01 100644 --- a/src/gldns/keyraw.h +++ b/src/gldns/keyraw.h @@ -20,13 +20,11 @@ #ifndef GLDNS_KEYRAW_H #define GLDNS_KEYRAW_H +#include "keyraw-internal.h" + #ifdef __cplusplus extern "C" { #endif -#if GLDNS_BUILD_CONFIG_HAVE_SSL -# include -# include -#endif /* GLDNS_BUILD_CONFIG_HAVE_SSL */ /** * get the length of the keydata in bits @@ -46,83 +44,6 @@ size_t gldns_rr_dnskey_key_size_raw(const unsigned char *keydata, */ uint16_t gldns_calc_keytag_raw(const uint8_t* key, size_t keysize); -#if GLDNS_BUILD_CONFIG_HAVE_SSL -/** - * Get the PKEY id for GOST, loads GOST into openssl as a side effect. - * Only available if GOST is compiled into the library and openssl. - * \return the gost id for EVP_CTX creation. - */ -int gldns_key_EVP_load_gost_id(void); - -/** Release the engine reference held for the GOST engine. */ -void gldns_key_EVP_unload_gost(void); - -/** - * Like gldns_key_buf2dsa, but uses raw buffer. - * \param[in] key the uncompressed wireformat of the key. - * \param[in] len length of key data - * \return a DSA * structure with the key material - */ -DSA *gldns_key_buf2dsa_raw(unsigned char* key, size_t len); - -/** - * Converts a holding buffer with key material to EVP PKEY in openssl. - * Only available if ldns was compiled with GOST. - * \param[in] key data to convert - * \param[in] keylen length of the key data - * \return the key or NULL on error. - */ -EVP_PKEY* gldns_gost2pkey_raw(unsigned char* key, size_t keylen); - -/** - * Converts a holding buffer with key material to EVP PKEY in openssl. - * Only available if ldns was compiled with ECDSA. - * \param[in] key data to convert - * \param[in] keylen length of the key data - * \param[in] algo precise algorithm to initialize ECC group values. - * \return the key or NULL on error. - */ -EVP_PKEY* gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo); - -/** - * Like gldns_key_buf2rsa, but uses raw buffer. - * \param[in] key the uncompressed wireformat of the key. - * \param[in] len length of key data - * \return a RSA * structure with the key material - */ -RSA *gldns_key_buf2rsa_raw(unsigned char* key, size_t len); - -/** - * Converts a holding buffer with key material to EVP PKEY in openssl. - * Only available if ldns was compiled with ED25519. - * \param[in] key the uncompressed wireformat of the key. - * \param[in] len length of key data - * \return the key or NULL on error. - */ -EVP_PKEY* gldns_ed255192pkey_raw(const unsigned char* key, size_t len); - -/** - * Converts a holding buffer with key material to EVP PKEY in openssl. - * Only available if ldns was compiled with ED448. - * \param[in] key the uncompressed wireformat of the key. - * \param[in] len length of key data - * \return the key or NULL on error. - */ -EVP_PKEY* gldns_ed4482pkey_raw(const unsigned char* key, size_t len); - -/** - * Utility function to calculate hash using generic EVP_MD pointer. - * \param[in] data the data to hash. - * \param[in] len length of data. - * \param[out] dest the destination of the hash, must be large enough. - * \param[in] md the message digest to use. - * \return true if worked, false on failure. - */ -int gldns_digest_evp(unsigned char* data, unsigned int len, - unsigned char* dest, const EVP_MD* md); - -#endif /* GLDNS_BUILD_CONFIG_HAVE_SSL */ - #ifdef __cplusplus } #endif diff --git a/src/openssl/keyraw-internal.c b/src/openssl/keyraw-internal.c new file mode 100644 index 00000000..75c53c00 --- /dev/null +++ b/src/openssl/keyraw-internal.c @@ -0,0 +1,348 @@ +/* + * keyraw.c - raw key operations and conversions - OpenSSL version + * + * (c) NLnet Labs, 2004-2008 + * + * See the file LICENSE for the license + */ +/** + * \file + * Implementation of raw DNSKEY functions (work on wire rdata). + */ + +#include "config.h" +#include "gldns/keyraw.h" +#include "gldns/rrdef.h" + +#ifdef HAVE_SSL +#include +#include +#include +#include +#include +#ifdef HAVE_OPENSSL_ENGINE_H +# include +#endif +#ifdef HAVE_OPENSSL_BN_H +#include +#endif +#ifdef HAVE_OPENSSL_RSA_H +#include +#endif +#ifdef HAVE_OPENSSL_DSA_H +#include +#endif +#endif /* HAVE_SSL */ + +#ifdef HAVE_SSL +#ifdef USE_GOST + +/** store GOST engine reference loaded into OpenSSL library */ +ENGINE* gldns_gost_engine = NULL; + +int +gldns_key_EVP_load_gost_id(void) +{ + static int gost_id = 0; + const EVP_PKEY_ASN1_METHOD* meth; + ENGINE* e; + + if(gost_id) return gost_id; + + /* see if configuration loaded gost implementation from other engine*/ + meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1); + if(meth) { + EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); + return gost_id; + } + + /* see if engine can be loaded already */ + e = ENGINE_by_id("gost"); + if(!e) { + /* load it ourself, in case statically linked */ + ENGINE_load_builtin_engines(); + ENGINE_load_dynamic(); + e = ENGINE_by_id("gost"); + } + if(!e) { + /* no gost engine in openssl */ + return 0; + } + if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { + ENGINE_finish(e); + ENGINE_free(e); + return 0; + } + + meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1); + if(!meth) { + /* algo not found */ + ENGINE_finish(e); + ENGINE_free(e); + return 0; + } + /* Note: do not ENGINE_finish and ENGINE_free the acquired engine + * on some platforms this frees up the meth and unloads gost stuff */ + gldns_gost_engine = e; + + EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); + return gost_id; +} + +void gldns_key_EVP_unload_gost(void) +{ + if(gldns_gost_engine) { + ENGINE_finish(gldns_gost_engine); + ENGINE_free(gldns_gost_engine); + gldns_gost_engine = NULL; + } +} +#endif /* USE_GOST */ + +DSA * +gldns_key_buf2dsa_raw(unsigned char* key, size_t len) +{ + uint8_t T; + uint16_t length; + uint16_t offset; + DSA *dsa; + BIGNUM *Q; BIGNUM *P; + BIGNUM *G; BIGNUM *Y; + + if(len == 0) + return NULL; + T = (uint8_t)key[0]; + length = (64 + T * 8); + offset = 1; + + if (T > 8) { + return NULL; + } + if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length) + return NULL; + + Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL); + offset += SHA_DIGEST_LENGTH; + + P = BN_bin2bn(key+offset, (int)length, NULL); + offset += length; + + G = BN_bin2bn(key+offset, (int)length, NULL); + offset += length; + + Y = BN_bin2bn(key+offset, (int)length, NULL); + + /* create the key and set its properties */ + if(!Q || !P || !G || !Y || !(dsa = DSA_new())) { + BN_free(Q); + BN_free(P); + BN_free(G); + BN_free(Y); + return NULL; + } + if (!DSA_set0_pqg(dsa, P, Q, G)) { + /* QPG not yet attached, need to free */ + BN_free(Q); + BN_free(P); + BN_free(G); + + DSA_free(dsa); + BN_free(Y); + return NULL; + } + if (!DSA_set0_key(dsa, Y, NULL)) { + /* QPG attached, cleaned up by DSA_fre() */ + DSA_free(dsa); + BN_free(Y); + return NULL; + } + + return dsa; +} + +RSA * +gldns_key_buf2rsa_raw(unsigned char* key, size_t len) +{ + uint16_t offset; + uint16_t exp; + uint16_t int16; + RSA *rsa; + BIGNUM *modulus; + BIGNUM *exponent; + + if (len == 0) + return NULL; + if (key[0] == 0) { + if(len < 3) + return NULL; + memmove(&int16, key+1, 2); + exp = ntohs(int16); + offset = 3; + } else { + exp = key[0]; + offset = 1; + } + + /* key length at least one */ + if(len < (size_t)offset + exp + 1) + return NULL; + + /* Exponent */ + exponent = BN_new(); + if(!exponent) return NULL; + (void) BN_bin2bn(key+offset, (int)exp, exponent); + offset += exp; + + /* Modulus */ + modulus = BN_new(); + if(!modulus) { + BN_free(exponent); + return NULL; + } + /* length of the buffer must match the key length! */ + (void) BN_bin2bn(key+offset, (int)(len - offset), modulus); + + rsa = RSA_new(); + if(!rsa) { + BN_free(exponent); + BN_free(modulus); + return NULL; + } + if (!RSA_set0_key(rsa, modulus, exponent, NULL)) { + BN_free(exponent); + BN_free(modulus); + RSA_free(rsa); + return NULL; + } + + return rsa; +} + +#ifdef USE_GOST +EVP_PKEY* +gldns_gost2pkey_raw(unsigned char* key, size_t keylen) +{ + /* prefix header for X509 encoding */ + uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, + 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, + 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, + 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40}; + unsigned char encoded[37+64]; + const unsigned char* pp; + if(keylen != 64) { + /* key wrong size */ + return NULL; + } + + /* create evp_key */ + memmove(encoded, asn, 37); + memmove(encoded+37, key, 64); + pp = (unsigned char*)&encoded[0]; + + return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded)); +} +#endif /* USE_GOST */ + +#ifdef USE_ECDSA +EVP_PKEY* +gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo) +{ + unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */ + const unsigned char* pp = buf; + EVP_PKEY *evp_key; + EC_KEY *ec; + /* check length, which uncompressed must be 2 bignums */ + if(algo == GLDNS_ECDSAP256SHA256) { + if(keylen != 2*256/8) return NULL; + ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + } else if(algo == GLDNS_ECDSAP384SHA384) { + if(keylen != 2*384/8) return NULL; + ec = EC_KEY_new_by_curve_name(NID_secp384r1); + } else ec = NULL; + if(!ec) return NULL; + if(keylen+1 > sizeof(buf)) { /* sanity check */ + EC_KEY_free(ec); + return NULL; + } + /* prepend the 0x02 (from docs) (or actually 0x04 from implementation + * of openssl) for uncompressed data */ + buf[0] = POINT_CONVERSION_UNCOMPRESSED; + memmove(buf+1, key, keylen); + if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) { + EC_KEY_free(ec); + return NULL; + } + evp_key = EVP_PKEY_new(); + if(!evp_key) { + EC_KEY_free(ec); + return NULL; + } + if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) { + EVP_PKEY_free(evp_key); + EC_KEY_free(ec); + return NULL; + } + return evp_key; +} +#endif /* USE_ECDSA */ + +#ifdef USE_ED25519 +EVP_PKEY* +gldns_ed255192pkey_raw(const unsigned char* key, size_t keylen) +{ + /* ASN1 for ED25519 is 302a300506032b6570032100 <32byteskey> */ + uint8_t pre[] = {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, + 0x70, 0x03, 0x21, 0x00}; + int pre_len = 12; + uint8_t buf[256]; + EVP_PKEY *evp_key; + /* pp gets modified by d2i() */ + const unsigned char* pp = (unsigned char*)buf; + if(keylen != 32 || keylen + pre_len > sizeof(buf)) + return NULL; /* wrong length */ + memmove(buf, pre, pre_len); + memmove(buf+pre_len, key, keylen); + evp_key = d2i_PUBKEY(NULL, &pp, (int)(pre_len+keylen)); + return evp_key; +} +#endif /* USE_ED25519 */ + +#ifdef USE_ED448 +EVP_PKEY* +gldns_ed4482pkey_raw(const unsigned char* key, size_t keylen) +{ + /* ASN1 for ED448 is 3043300506032b6571033a00 <57byteskey> */ + uint8_t pre[] = {0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, + 0x71, 0x03, 0x3a, 0x00}; + int pre_len = 12; + uint8_t buf[256]; + EVP_PKEY *evp_key; + /* pp gets modified by d2i() */ + const unsigned char* pp = (unsigned char*)buf; + if(keylen != 57 || keylen + pre_len > sizeof(buf)) + return NULL; /* wrong length */ + memmove(buf, pre, pre_len); + memmove(buf+pre_len, key, keylen); + evp_key = d2i_PUBKEY(NULL, &pp, (int)(pre_len+keylen)); + return evp_key; +} +#endif /* USE_ED448 */ + +int +gldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest, + const EVP_MD* md) +{ + EVP_MD_CTX* ctx; + ctx = EVP_MD_CTX_create(); + if(!ctx) + return 0; + if(!EVP_DigestInit_ex(ctx, md, NULL) || + !EVP_DigestUpdate(ctx, data, len) || + !EVP_DigestFinal_ex(ctx, dest, NULL)) { + EVP_MD_CTX_destroy(ctx); + return 0; + } + EVP_MD_CTX_destroy(ctx); + return 1; +} +#endif /* HAVE_SSL */ diff --git a/src/openssl/keyraw-internal.h b/src/openssl/keyraw-internal.h new file mode 100644 index 00000000..92717c95 --- /dev/null +++ b/src/openssl/keyraw-internal.h @@ -0,0 +1,110 @@ +/* + * keyraw.h -- raw key and signature access and conversion - OpenSSL + * + * Copyright (c) 2005-2008, NLnet Labs. All rights reserved. + * + * See LICENSE for the license. + * + */ + +/** + * \file + * + * raw key and signature access and conversion + * + * Since those functions heavily rely op cryptographic operations, + * this module is dependent on openssl. + * + */ + +#ifndef GLDNS_KEYRAW_INTERNAL_H +#define GLDNS_KEYRAW_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif +#if GLDNS_BUILD_CONFIG_HAVE_SSL +# include +# include + +/** + * Get the PKEY id for GOST, loads GOST into openssl as a side effect. + * Only available if GOST is compiled into the library and openssl. + * \return the gost id for EVP_CTX creation. + */ +int gldns_key_EVP_load_gost_id(void); + +/** Release the engine reference held for the GOST engine. */ +void gldns_key_EVP_unload_gost(void); + +/** + * Like gldns_key_buf2dsa, but uses raw buffer. + * \param[in] key the uncompressed wireformat of the key. + * \param[in] len length of key data + * \return a DSA * structure with the key material + */ +DSA *gldns_key_buf2dsa_raw(unsigned char* key, size_t len); + +/** + * Converts a holding buffer with key material to EVP PKEY in openssl. + * Only available if ldns was compiled with GOST. + * \param[in] key data to convert + * \param[in] keylen length of the key data + * \return the key or NULL on error. + */ +EVP_PKEY* gldns_gost2pkey_raw(unsigned char* key, size_t keylen); + +/** + * Converts a holding buffer with key material to EVP PKEY in openssl. + * Only available if ldns was compiled with ECDSA. + * \param[in] key data to convert + * \param[in] keylen length of the key data + * \param[in] algo precise algorithm to initialize ECC group values. + * \return the key or NULL on error. + */ +EVP_PKEY* gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo); + +/** + * Like gldns_key_buf2rsa, but uses raw buffer. + * \param[in] key the uncompressed wireformat of the key. + * \param[in] len length of key data + * \return a RSA * structure with the key material + */ +RSA *gldns_key_buf2rsa_raw(unsigned char* key, size_t len); + +/** + * Converts a holding buffer with key material to EVP PKEY in openssl. + * Only available if ldns was compiled with ED25519. + * \param[in] key the uncompressed wireformat of the key. + * \param[in] len length of key data + * \return the key or NULL on error. + */ +EVP_PKEY* gldns_ed255192pkey_raw(const unsigned char* key, size_t len); + +/** + * Converts a holding buffer with key material to EVP PKEY in openssl. + * Only available if ldns was compiled with ED448. + * \param[in] key the uncompressed wireformat of the key. + * \param[in] len length of key data + * \return the key or NULL on error. + */ +EVP_PKEY* gldns_ed4482pkey_raw(const unsigned char* key, size_t len); + +/** + * Utility function to calculate hash using generic EVP_MD pointer. + * \param[in] data the data to hash. + * \param[in] len length of data. + * \param[out] dest the destination of the hash, must be large enough. + * \param[in] md the message digest to use. + * \return true if worked, false on failure. + */ +int gldns_digest_evp(unsigned char* data, unsigned int len, + unsigned char* dest, const EVP_MD* md); + +#endif /* GLDNS_BUILD_CONFIG_HAVE_SSL */ + +#ifdef __cplusplus +} +#endif + +#endif /* GLDNS_KEYRAW_INTERNAL_H */