diff --git a/CHANGES b/CHANGES index 919c00091b..c7b6b1dcde 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +1973. [func] TSIG HMACSHA1, HMACSHA224, HMACSHA256, HMACSHA384 and + HMACSHA512 support. [RT #13606] + 1972. [contrib] DBUS dynamic forwarders integation from Jason Vas Dias . diff --git a/bin/dig/dig.c b/bin/dig/dig.c index d89bf1b221..1274034948 100644 --- a/bin/dig/dig.c +++ b/bin/dig/dig.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dig.c,v 1.210 2006/01/07 00:23:35 marka Exp $ */ +/* $Id: dig.c,v 1.211 2006/01/27 02:35:14 marka Exp $ */ /*! \file */ @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -152,7 +153,7 @@ help(void) { " -t type (specify query type)\n" " -c class (specify query class)\n" " -k keyfile (specify tsig key file)\n" -" -y name:key (specify named base64 tsig key)\n" +" -y [hmac:]name:key (specify named base64 tsig key)\n" " -4 (use IPv4 query transport only)\n" " -6 (use IPv6 query transport only)\n" " d-opt is of the form +keyword[=value], where keyword is:\n" @@ -1105,7 +1106,7 @@ static isc_boolean_t dash_option(char *option, char *next, dig_lookup_t **lookup, isc_boolean_t *open_type_class, isc_boolean_t config_only) { - char opt, *value, *ptr; + char opt, *value, *ptr, *ptr2, *ptr3; isc_result_t result; isc_boolean_t value_from_next; isc_textregion_t tr; @@ -1295,16 +1296,83 @@ dash_option(char *option, char *next, dig_lookup_t **lookup, value); return (value_from_next); case 'y': - ptr = next_token(&value,":"); + ptr = next_token(&value,":"); /* hmac type or name */ if (ptr == NULL) { usage(); } + ptr2 = next_token(&value, ":"); /* name or secret */ + if (ptr2 == NULL) + usage(); + ptr3 = next_token(&value,":"); /* secret or NULL */ + if (ptr3 != NULL) { + if (strcasecmp(ptr, "hmac-md5") == 0) { + hmacname = DNS_TSIG_HMACMD5_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-md5-", 9) == 0) { + hmacname = DNS_TSIG_HMACMD5_NAME; + digestbits = parse_uint(&ptr[9], + "digest-bits [0..128]", + 128); + digestbits = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(ptr, "hmac-sha1") == 0) { + hmacname = DNS_TSIG_HMACSHA1_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-sha1-", 10) == 0) { + hmacname = DNS_TSIG_HMACSHA1_NAME; + digestbits = parse_uint(&ptr[10], + "digest-bits [0..160]", + 160); + digestbits = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(ptr, "hmac-sha224") == 0) { + hmacname = DNS_TSIG_HMACSHA224_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-sha224-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA224_NAME; + digestbits = parse_uint(&ptr[12], + "digest-bits [0..224]", + 224); + digestbits = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(ptr, "hmac-sha256") == 0) { + hmacname = DNS_TSIG_HMACSHA256_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-sha256-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA256_NAME; + digestbits = parse_uint(&ptr[12], + "digest-bits [0..256]", + 256); + digestbits = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(ptr, "hmac-sha384") == 0) { + hmacname = DNS_TSIG_HMACSHA384_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-sha384-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA384_NAME; + digestbits = parse_uint(&ptr[12], + "digest-bits [0..384]", + 384); + digestbits = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(ptr, "hmac-sha512") == 0) { + hmacname = DNS_TSIG_HMACSHA512_NAME; + digestbits = 0; + } else if (strncasecmp(ptr, "hmac-sha512-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA512_NAME; + digestbits = parse_uint(&ptr[12], + "digest-bits [0..512]", + 512); + digestbits = (digestbits + 7) & ~0x7U; + } else { + fprintf(stderr, ";; Warning, ignoring " + "invalid TSIG algorithm %s\n", ptr); + return (value_from_next); + } + ptr = ptr2; + ptr2 = ptr3; + } else { + hmacname = DNS_TSIG_HMACMD5_NAME; + digestbits = 0; + } strncpy(keynametext, ptr, sizeof(keynametext)); keynametext[sizeof(keynametext)-1]=0; - ptr = next_token(&value, ""); - if (ptr == NULL) - usage(); - strncpy(keysecret, ptr, sizeof(keysecret)); + strncpy(keysecret, ptr2, sizeof(keysecret)); keysecret[sizeof(keysecret)-1]=0; return (value_from_next); case 'x': diff --git a/bin/dig/dig.docbook b/bin/dig/dig.docbook index aa988b642c..be2418b23b 100644 --- a/bin/dig/dig.docbook +++ b/bin/dig/dig.docbook @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -63,7 +63,7 @@ - + name @@ -281,6 +281,7 @@ responses using transaction signatures (TSIG), specify a TSIG key file using the option. You can also specify the TSIG key itself on the command line using the option; + hmac is the type of the TSIG, default HMAC-MD5, name is the name of the TSIG key and key is the actual key. The key is a base-64 diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 41d1103e6e..3aaa106371 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dighost.c,v 1.290 2006/01/07 00:23:35 marka Exp $ */ +/* $Id: dighost.c,v 1.291 2006/01/27 02:35:14 marka Exp $ */ /*! \file * \note @@ -161,6 +161,8 @@ int fatalexit = 0; char keynametext[MXNAME]; char keyfile[MXNAME] = ""; char keysecret[MXNAME] = ""; +dns_name_t *hmacname = NULL; +unsigned int digestbits = 0; isc_buffer_t *namebuf = NULL; dns_tsigkey_t *key = NULL; isc_boolean_t validated = ISC_TRUE; @@ -890,14 +892,15 @@ setup_text_key(void) { if (result != ISC_R_SUCCESS) goto failure; - result = dns_tsigkey_create(&keyname, dns_tsig_hmacmd5_name, - secretstore, secretsize, - ISC_FALSE, NULL, 0, 0, mctx, + result = dns_tsigkey_create(&keyname, hmacname, secretstore, + secretsize, ISC_FALSE, NULL, 0, 0, mctx, NULL, &key); failure: if (result != ISC_R_SUCCESS) printf(";; Couldn't create key %s: %s\n", keynametext, isc_result_totext(result)); + else + dst_key_setbits(key->key, digestbits); isc_mem_free(mctx, secretstore); dns_name_invalidate(&keyname); @@ -918,8 +921,31 @@ setup_file_key(void) { goto failure; } - result = dns_tsigkey_createfromkey(dst_key_name(dstkey), - dns_tsig_hmacmd5_name, + switch (dst_key_alg(dstkey)) { + case DST_ALG_HMACMD5: + hmacname = DNS_TSIG_HMACMD5_NAME; + break; + case DST_ALG_HMACSHA1: + hmacname = DNS_TSIG_HMACSHA1_NAME; + break; + case DST_ALG_HMACSHA224: + hmacname = DNS_TSIG_HMACSHA224_NAME; + break; + case DST_ALG_HMACSHA256: + hmacname = DNS_TSIG_HMACSHA256_NAME; + break; + case DST_ALG_HMACSHA384: + hmacname = DNS_TSIG_HMACSHA384_NAME; + break; + case DST_ALG_HMACSHA512: + hmacname = DNS_TSIG_HMACSHA512_NAME; + break; + default: + printf(";; Couldn't create key %s: bad algorithm\n", + keynametext); + goto failure; + } + result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmacname, dstkey, ISC_FALSE, NULL, 0, 0, mctx, NULL, &key); if (result != ISC_R_SUCCESS) { diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h index 7441036562..ea346c4690 100644 --- a/bin/dig/include/dig/dig.h +++ b/bin/dig/include/dig/dig.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dig.h,v 1.96 2005/08/25 00:40:50 marka Exp $ */ +/* $Id: dig.h,v 1.97 2006/01/27 02:35:14 marka Exp $ */ #ifndef DIG_H #define DIG_H @@ -257,6 +257,8 @@ extern isc_sockaddr_t bind_address; extern char keynametext[MXNAME]; extern char keyfile[MXNAME]; extern char keysecret[MXNAME]; +extern dns_name_t *hmacname; +extern unsigned int digestbits; #ifdef DIG_SIGCHASE extern char trustedkey[MXNAME]; #endif diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c index 75dcce9eac..8a8f9b01ff 100644 --- a/bin/dnssec/dnssec-keygen.c +++ b/bin/dnssec/dnssec-keygen.c @@ -16,7 +16,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-keygen.c,v 1.72 2006/01/04 00:37:24 marka Exp $ */ +/* $Id: dnssec-keygen.c,v 1.73 2006/01/27 02:35:14 marka Exp $ */ /*! \file */ @@ -49,7 +49,9 @@ const char *program = "dnssec-keygen"; int verbose; -static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1 | HMAC-MD5"; +static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1 | HMAC-MD5 |" + " HMAC-SHA1 | HMAC-SHA224 | HMAC-SHA256 | " + " HMAC-SHA384 | HMAC-SHA512"; static isc_boolean_t dsa_size_ok(int size) { @@ -70,10 +72,16 @@ usage(void) { fprintf(stderr, " DH:\t\t[128..4096]\n"); fprintf(stderr, " DSA:\t\t[512..1024] and divisible by 64\n"); fprintf(stderr, " HMAC-MD5:\t[1..512]\n"); + fprintf(stderr, " HMAC-SHA1:\t[1..160]\n"); + fprintf(stderr, " HMAC-SHA224:\t[1..224]\n"); + fprintf(stderr, " HMAC-SHA256:\t[1..256]\n"); + fprintf(stderr, " HMAC-SHA384:\t[1..384]\n"); + fprintf(stderr, " HMAC-SHA512:\t[1..512]\n"); fprintf(stderr, " -n nametype: ZONE | HOST | ENTITY | USER | OTHER\n"); fprintf(stderr, " name: owner of the key\n"); fprintf(stderr, "Other options:\n"); fprintf(stderr, " -c (default: IN)\n"); + fprintf(stderr, " -d (0 => max, default)\n"); fprintf(stderr, " -e use large exponent (RSAMD5/RSASHA1 only)\n"); fprintf(stderr, " -f keyflag: KSK\n"); fprintf(stderr, " -g use specified generator " @@ -117,6 +125,7 @@ main(int argc, char **argv) { isc_entropy_t *ectx = NULL; dns_rdataclass_t rdclass; int options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC; + int dbits = 0; if (argc == 1) usage(); @@ -126,7 +135,7 @@ main(int argc, char **argv) { dns_result_register(); while ((ch = isc_commandline_parse(argc, argv, - "a:b:c:ef:g:kn:t:p:s:r:v:h")) != -1) + "a:b:c:d:ef:g:kn:t:p:s:r:v:h")) != -1) { switch (ch) { case 'a': @@ -140,6 +149,11 @@ main(int argc, char **argv) { case 'c': classname = isc_commandline_argument; break; + case 'd': + dbits = strtol(isc_commandline_argument, &endp, 10); + if (*endp != '\0' || dbits < 0) + fatal("-d requires a non-negative number"); + break; case 'e': rsa_exp = 1; break; @@ -221,6 +235,21 @@ main(int argc, char **argv) { } else if (strcasecmp(algname, "HMAC-MD5") == 0) { options |= DST_TYPE_KEY; alg = DST_ALG_HMACMD5; + } else if (strcasecmp(algname, "HMAC-SHA1") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACSHA1; + } else if (strcasecmp(algname, "HMAC-SHA224") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACSHA224; + } else if (strcasecmp(algname, "HMAC-SHA256") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACSHA256; + } else if (strcasecmp(algname, "HMAC-SHA384") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACSHA384; + } else if (strcasecmp(algname, "HMAC-SHA512") == 0) { + options |= DST_TYPE_KEY; + alg = DST_ALG_HMACSHA512; } else { r.base = algname; r.length = strlen(algname); @@ -267,6 +296,56 @@ main(int argc, char **argv) { case DST_ALG_HMACMD5: if (size < 1 || size > 512) fatal("HMAC-MD5 key size %d out of range", size); + if (dbits != 0 && (dbits < 80 || dbits > 128)) + fatal("HMAC-MD5 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-MD5 digest bits %d not divisible by 8", + dbits); + break; + case DST_ALG_HMACSHA1: + if (size < 1 || size > 160) + fatal("HMAC-SHA1 key size %d out of range", size); + if (dbits != 0 && (dbits < 80 || dbits > 160)) + fatal("HMAC-SHA1 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-SHA1 digest bits %d not divisible by 8", + dbits); + break; + case DST_ALG_HMACSHA224: + if (size < 1 || size > 224) + fatal("HMAC-SHA224 key size %d out of range", size); + if (dbits != 0 && (dbits < 112 || dbits > 224)) + fatal("HMAC-SHA224 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-SHA224 digest bits %d not divisible by 8", + dbits); + break; + case DST_ALG_HMACSHA256: + if (size < 1 || size > 256) + fatal("HMAC-SHA256 key size %d out of range", size); + if (dbits != 0 && (dbits < 128 || dbits > 256)) + fatal("HMAC-SHA256 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-SHA256 digest bits %d not divisible by 8", + dbits); + break; + case DST_ALG_HMACSHA384: + if (size < 1 || size > 384) + fatal("HMAC-384 key size %d out of range", size); + if (dbits != 0 && (dbits < 192 || dbits > 384)) + fatal("HMAC-SHA384 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-SHA384 digest bits %d not divisible by 8", + dbits); + break; + case DST_ALG_HMACSHA512: + if (size < 1 || size > 512) + fatal("HMAC-SHA512 key size %d out of range", size); + if (dbits != 0 && (dbits < 256 || dbits > 512)) + fatal("HMAC-SHA512 digest bits %d out of range", dbits); + if ((dbits % 8) != 0) + fatal("HMAC-SHA512 digest bits %d not divisible by 8", + dbits); break; } @@ -313,7 +392,10 @@ main(int argc, char **argv) { } if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE && - (alg == DNS_KEYALG_DH || alg == DST_ALG_HMACMD5)) + (alg == DNS_KEYALG_DH || alg == DST_ALG_HMACMD5 || + alg == DST_ALG_HMACSHA1 || alg == DST_ALG_HMACSHA224 || + alg == DST_ALG_HMACSHA256 || alg == DST_ALG_HMACSHA384 || + alg == DST_ALG_HMACSHA512)) fatal("a key with algorithm '%s' cannot be a zone key", algname); @@ -337,6 +419,11 @@ main(int argc, char **argv) { break; case DNS_KEYALG_DSA: case DST_ALG_HMACMD5: + case DST_ALG_HMACSHA1: + case DST_ALG_HMACSHA224: + case DST_ALG_HMACSHA256: + case DST_ALG_HMACSHA384: + case DST_ALG_HMACSHA512: param = 0; break; } @@ -365,6 +452,8 @@ main(int argc, char **argv) { exit(-1); } + dst_key_setbits(key, dbits); + /* * Try to read a key with the same name, alg and id from disk. * If there is one we must continue generating a new one diff --git a/bin/named/config.c b/bin/named/config.c index 728274840c..04a9b36fe4 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: config.c,v 1.67 2006/01/05 23:45:33 marka Exp $ */ +/* $Id: config.c,v 1.68 2006/01/27 02:35:14 marka Exp $ */ /*! \file */ @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -724,16 +725,65 @@ ns_config_getport(cfg_obj_t *config, in_port_t *portp) { return (ISC_R_SUCCESS); } +struct keyalgorithms { + const char *str; + enum { hmacnone, hmacmd5, hmacsha1, hmacsha224, + hmacsha256, hmacsha384, hmacsha512 } hmac; + isc_uint16_t size; +} algorithms[] = { + { "hmac-md5", hmacmd5, 128 }, + { "hmac-md5.sig-alg.reg.int", hmacmd5, 0 }, + { "hmac-md5.sig-alg.reg.int.", hmacmd5, 0 }, + { "hmac-sha1", hmacsha1, 160 }, + { "hmac-sha224", hmacsha224, 224 }, + { "hmac-sha256", hmacsha256, 256 }, + { "hmac-sha384", hmacsha384, 384 }, + { "hmac-sha512", hmacsha512, 512 }, + { NULL, hmacnone, 0 } +}; + isc_result_t -ns_config_getkeyalgorithm(const char *str, dns_name_t **name) +ns_config_getkeyalgorithm(const char *str, dns_name_t **name, + isc_uint16_t *digestbits) { - if (strcasecmp(str, "hmac-md5") == 0 || - strcasecmp(str, "hmac-md5.sig-alg.reg.int") == 0 || - strcasecmp(str, "hmac-md5.sig-alg.reg.int.") == 0) - { - if (name != NULL) - *name = dns_tsig_hmacmd5_name; - return (ISC_R_SUCCESS); + int i; + size_t len = 0; + isc_uint16_t bits; + isc_result_t result; + + for (i = 0; algorithms[i].str != NULL; i++) { + len = strlen(algorithms[i].str); + if (strncasecmp(algorithms[i].str, str, len) == 0 && + (str[len] == '\0' || + (algorithms[i].size != 0 && str[len] == '-'))) + break; } - return (ISC_R_NOTFOUND); + if (algorithms[i].str == NULL) + return (ISC_R_NOTFOUND); + if (str[len] == '-') { + result = isc_parse_uint16(&bits, str + len + 1, 10); + if (result != ISC_R_SUCCESS) + return (result); + if (bits > algorithms[i].size) + return (ISC_R_RANGE); + } else if (algorithms[i].size == 0) + bits = 128; + else + bits = algorithms[i].size; + + if (name != NULL) { + switch (algorithms[i].hmac) { + case hmacmd5: *name = dns_tsig_hmacmd5_name; break; + case hmacsha1: *name = dns_tsig_hmacsha1_name; break; + case hmacsha224: *name = dns_tsig_hmacsha224_name; break; + case hmacsha256: *name = dns_tsig_hmacsha256_name; break; + case hmacsha384: *name = dns_tsig_hmacsha384_name; break; + case hmacsha512: *name = dns_tsig_hmacsha512_name; break; + default: + INSIST(0); + } + } + if (digestbits != NULL) + *digestbits = bits; + return (ISC_R_SUCCESS); } diff --git a/bin/named/controlconf.c b/bin/named/controlconf.c index 57f894bf08..0d6c51a4a1 100644 --- a/bin/named/controlconf.c +++ b/bin/named/controlconf.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: controlconf.c,v 1.47 2005/11/30 03:36:45 marka Exp $ */ +/* $Id: controlconf.c,v 1.48 2006/01/27 02:35:14 marka Exp $ */ /*! \file */ @@ -758,7 +758,7 @@ register_keys(cfg_obj_t *control, cfg_obj_t *keylist, algstr = cfg_obj_asstring(algobj); secretstr = cfg_obj_asstring(secretobj); - if (ns_config_getkeyalgorithm(algstr, NULL) != + if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != ISC_R_SUCCESS) { cfg_obj_log(control, ns_g_lctx, @@ -848,7 +848,7 @@ get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) { algstr = cfg_obj_asstring(algobj); secretstr = cfg_obj_asstring(secretobj); - if (ns_config_getkeyalgorithm(algstr, NULL) != ISC_R_SUCCESS) { + if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != ISC_R_SUCCESS) { cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, "unsupported algorithm '%s' in " diff --git a/bin/named/include/named/config.h b/bin/named/include/named/config.h index bd7981ce48..58afaef8e3 100644 --- a/bin/named/include/named/config.h +++ b/bin/named/include/named/config.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: config.h,v 1.9 2005/04/29 00:22:30 marka Exp $ */ +/* $Id: config.h,v 1.10 2006/01/27 02:35:14 marka Exp $ */ #ifndef NAMED_CONFIG_H #define NAMED_CONFIG_H 1 @@ -72,6 +72,7 @@ isc_result_t ns_config_getport(cfg_obj_t *config, in_port_t *portp); isc_result_t -ns_config_getkeyalgorithm(const char *str, dns_name_t **name); +ns_config_getkeyalgorithm(const char *str, dns_name_t **name, + isc_uint16_t *digestbits); #endif /* NAMED_CONFIG_H */ diff --git a/bin/named/tsigconf.c b/bin/named/tsigconf.c index 4cc9c36930..3932d07d0e 100644 --- a/bin/named/tsigconf.c +++ b/bin/named/tsigconf.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tsigconf.c,v 1.25 2005/08/23 02:36:07 marka Exp $ */ +/* $Id: tsigconf.c,v 1.26 2006/01/27 02:35:14 marka Exp $ */ /*! \file */ @@ -38,6 +38,7 @@ static isc_result_t add_initial_keys(cfg_obj_t *list, dns_tsig_keyring_t *ring, isc_mem_t *mctx) { + dns_tsigkey_t *tsigkey = NULL; cfg_listelt_t *element; cfg_obj_t *key = NULL; const char *keyid = NULL; @@ -46,6 +47,7 @@ add_initial_keys(cfg_obj_t *list, dns_tsig_keyring_t *ring, isc_mem_t *mctx) { int secretlen = 0; isc_result_t ret; isc_stdtime_t now; + isc_uint16_t bits; for (element = cfg_list_first(list); element != NULL; @@ -86,10 +88,11 @@ add_initial_keys(cfg_obj_t *list, dns_tsig_keyring_t *ring, isc_mem_t *mctx) { * Create the algorithm. */ algstr = cfg_obj_asstring(algobj); - if (ns_config_getkeyalgorithm(algstr, &alg) != ISC_R_SUCCESS) { + if (ns_config_getkeyalgorithm(algstr, &alg, &bits) + != ISC_R_SUCCESS) { cfg_obj_log(algobj, ns_g_lctx, ISC_LOG_ERROR, - "key '%s': the only supported algorithm " - "is hmac-md5", keyid); + "key '%s': has a unsupported algorithm '%s'", + keyid, algstr); ret = DNS_R_BADALG; goto failure; } @@ -110,11 +113,16 @@ add_initial_keys(cfg_obj_t *list, dns_tsig_keyring_t *ring, isc_mem_t *mctx) { isc_stdtime_get(&now); ret = dns_tsigkey_create(&keyname, alg, secret, secretlen, ISC_FALSE, NULL, now, now, - mctx, ring, NULL); + mctx, ring, &tsigkey); isc_mem_put(mctx, secret, secretalloc); secret = NULL; if (ret != ISC_R_SUCCESS) goto failure; + /* + * Set digest bits. + */ + dst_key_setbits(tsigkey->key, bits); + dns_tsigkey_detach(&tsigkey); } return (ISC_R_SUCCESS); @@ -127,7 +135,6 @@ add_initial_keys(cfg_obj_t *list, dns_tsig_keyring_t *ring, isc_mem_t *mctx) { if (secret != NULL) isc_mem_put(mctx, secret, secretalloc); return (ret); - } isc_result_t diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index cb7275ff0e..568dc72408 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsupdate.c,v 1.141 2006/01/07 00:23:35 marka Exp $ */ +/* $Id: nsupdate.c,v 1.142 2006/01/27 02:35:14 marka Exp $ */ /*! \file */ @@ -284,6 +284,74 @@ reset_system(void) { updatemsg->opcode = dns_opcode_update; } +static isc_uint16_t +parse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) { + isc_uint16_t digestbits = 0; + isc_result_t result; + char buf[20]; + + REQUIRE(hmac != NULL && *hmac == NULL); + REQUIRE(hmacstr != NULL); + + if (len >= sizeof(buf)) + fatal("unknown key type '%.*s'", (int)(len), hmacstr); + + strncpy(buf, hmacstr, len); + buf[len] = 0; + + if (strcasecmp(buf, "hmac-md5") == 0) { + *hmac = DNS_TSIG_HMACMD5_NAME; + } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) { + *hmac = DNS_TSIG_HMACMD5_NAME; + result = isc_parse_uint16(&digestbits, &buf[9], 10); + if (result != ISC_R_SUCCESS || digestbits > 128) + fatal("digest-bits out of range [0..128]"); + digestbits = (digestbits +7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha1") == 0) { + *hmac = DNS_TSIG_HMACSHA1_NAME; + } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) { + *hmac = DNS_TSIG_HMACSHA1_NAME; + result = isc_parse_uint16(&digestbits, &buf[10], 10); + if (result != ISC_R_SUCCESS || digestbits > 160) + fatal("digest-bits out of range [0..160]"); + digestbits = (digestbits +7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha224") == 0) { + *hmac = DNS_TSIG_HMACSHA224_NAME; + } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA224_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 224) + fatal("digest-bits out of range [0..224]"); + digestbits = (digestbits +7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha256") == 0) { + *hmac = DNS_TSIG_HMACSHA256_NAME; + } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA256_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 256) + fatal("digest-bits out of range [0..256]"); + digestbits = (digestbits +7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha384") == 0) { + *hmac = DNS_TSIG_HMACSHA384_NAME; + } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA384_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 384) + fatal("digest-bits out of range [0..384]"); + digestbits = (digestbits +7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha512") == 0) { + *hmac = DNS_TSIG_HMACSHA512_NAME; + } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA512_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 512) + fatal("digest-bits out of range [0..512]"); + digestbits = (digestbits +7) & ~0x7U; + } else + fatal("unknown key type '%s'", buf); + return (digestbits); +} + static void setup_keystr(void) { unsigned char *secret = NULL; @@ -292,9 +360,12 @@ setup_keystr(void) { isc_result_t result; isc_buffer_t keynamesrc; char *secretstr; - char *s; + char *s, *n; dns_fixedname_t fkeyname; dns_name_t *keyname; + char *name; + dns_name_t *hmacname = NULL; + isc_uint16_t digestbits = 0; dns_fixedname_init(&fkeyname); keyname = dns_fixedname_name(&fkeyname); @@ -302,12 +373,24 @@ setup_keystr(void) { debug("Creating key..."); s = strchr(keystr, ':'); - if (s == NULL || s == keystr || *s == 0) - fatal("key option must specify keyname:secret"); + if (s == NULL || s == keystr || s[1] == 0) + fatal("key option must specify [hmac:]keyname:secret"); secretstr = s + 1; + n = strchr(secretstr, ':'); + if (n != NULL) { + if (n == secretstr || n[1] == 0) + fatal("key option must specify [hmac:]keyname:secret"); + name = secretstr; + secretstr = n + 1; + digestbits = parse_hmac(&hmacname, keystr, s - keystr); + } else { + hmacname = DNS_TSIG_HMACMD5_NAME; + name = keystr; + n = s; + } - isc_buffer_init(&keynamesrc, keystr, s - keystr); - isc_buffer_add(&keynamesrc, s - keystr); + isc_buffer_init(&keynamesrc, name, n - name); + isc_buffer_add(&keynamesrc, n - name); debug("namefromtext"); result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname, @@ -330,12 +413,13 @@ setup_keystr(void) { secretlen = isc_buffer_usedlength(&secretbuf); debug("keycreate"); - result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name, - secret, secretlen, ISC_TRUE, NULL, - 0, 0, mctx, NULL, &tsigkey); + result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, + ISC_TRUE, NULL, 0, 0, mctx, NULL, &tsigkey); if (result != ISC_R_SUCCESS) fprintf(stderr, "could not create key from %s: %s\n", keystr, dns_result_totext(result)); + else + dst_key_setbits(tsigkey->key, digestbits); failure: if (secret != NULL) isc_mem_free(mctx, secret); @@ -345,6 +429,7 @@ static void setup_keyfile(void) { dst_key_t *dstkey = NULL; isc_result_t result; + dns_name_t *hmacname = NULL; debug("Creating key..."); @@ -356,11 +441,31 @@ setup_keyfile(void) { keyfile, isc_result_totext(result)); return; } - if (dst_key_alg(dstkey) == DST_ALG_HMACMD5) { + switch (dst_key_alg(dstkey)) { + case DST_ALG_HMACMD5: + hmacname = DNS_TSIG_HMACMD5_NAME; + break; + case DST_ALG_HMACSHA1: + hmacname = DNS_TSIG_HMACSHA1_NAME; + break; + case DST_ALG_HMACSHA224: + hmacname = DNS_TSIG_HMACSHA224_NAME; + break; + case DST_ALG_HMACSHA256: + hmacname = DNS_TSIG_HMACSHA256_NAME; + break; + case DST_ALG_HMACSHA384: + hmacname = DNS_TSIG_HMACSHA384_NAME; + break; + case DST_ALG_HMACSHA512: + hmacname = DNS_TSIG_HMACSHA512_NAME; + break; + } + if (hmacname != NULL) { result = dns_tsigkey_createfromkey(dst_key_name(dstkey), - dns_tsig_hmacmd5_name, - dstkey, ISC_FALSE, NULL, - 0, 0, mctx, NULL, &tsigkey); + hmacname, dstkey, ISC_FALSE, + NULL, 0, 0, mctx, NULL, + &tsigkey); if (result != ISC_R_SUCCESS) { fprintf(stderr, "could not create key from %s: %s\n", keyfile, isc_result_totext(result)); @@ -1000,6 +1105,9 @@ evaluate_key(char *cmdline) { int secretlen; unsigned char *secret = NULL; isc_buffer_t secretbuf; + dns_name_t *hmacname = NULL; + isc_uint16_t digestbits = 0; + char *n; namestr = nsu_strsep(&cmdline, " \t\r\n"); if (*namestr == 0) { @@ -1010,6 +1118,13 @@ evaluate_key(char *cmdline) { dns_fixedname_init(&fkeyname); keyname = dns_fixedname_name(&fkeyname); + n = strchr(namestr, ':'); + if (n != NULL) { + digestbits = parse_hmac(&hmacname, namestr, n - namestr); + namestr = n + 1; + } else + hmacname = DNS_TSIG_HMACMD5_NAME; + isc_buffer_init(&b, namestr, strlen(namestr)); isc_buffer_add(&b, strlen(namestr)); result = dns_name_fromtext(keyname, &b, dns_rootname, ISC_FALSE, NULL); @@ -1040,15 +1155,16 @@ evaluate_key(char *cmdline) { if (tsigkey != NULL) dns_tsigkey_detach(&tsigkey); - result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name, - secret, secretlen, ISC_TRUE, NULL, 0, 0, - mctx, NULL, &tsigkey); + result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, + ISC_TRUE, NULL, 0, 0, mctx, NULL, + &tsigkey); isc_mem_free(mctx, secret); if (result != ISC_R_SUCCESS) { fprintf(stderr, "could not create key from %s %s: %s\n", namestr, secretstr, dns_result_totext(result)); return (STATUS_SYNTAX); } + dst_key_setbits(tsigkey->key, digestbits); return (STATUS_MORE); } diff --git a/bin/nsupdate/nsupdate.docbook b/bin/nsupdate/nsupdate.docbook index 2c6e92cdf5..7c8b10b7f1 100644 --- a/bin/nsupdate/nsupdate.docbook +++ b/bin/nsupdate/nsupdate.docbook @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + Jun 30, 2000 @@ -53,7 +53,7 @@ nsupdate - + @@ -126,40 +126,29 @@ /etc/named.conf. nsupdate - uses the or - option (with an HMAC-MD5 key) to provide the shared secret needed to - generate - a TSIG record for authenticating Dynamic DNS update requests. - These options are mutually exclusive. - With the - - option, - nsupdate - reads the shared secret from the file - keyfile, + uses the or option + to provide the shared secret needed to generate a TSIG record + for authenticating Dynamic DNS update requests, default type + HMAC-MD5. These options are mutually exclusive. With the + option, nsupdate reads + the shared secret from the file keyfile, whose name is of the form - K{name}.+157.+{random}.private. - For historical - reasons, the file - K{name}.+157.+{random}.key - must also be present. When the - - option is used, a signature is generated from - keyname:secret. - keyname - is the name of the key, - and - secret - is the base64 encoded shared secret. - Use of the - - option is discouraged because the shared secret is supplied as a command - line argument in clear text. - This may be visible in the output from + K{name}.+157.+{random}.private. For + historical reasons, the file + K{name}.+157.+{random}.key must also be + present. When the option is used, a + signature is generated from + hmac:keyname:secret. + keyname is the name of the key, and + secret is the base64 encoded shared + secret. Use of the option is discouraged + because the shared secret is supplied as a command line + argument in clear text. This may be visible in the output + from - ps1 - - or in a history file maintained by the user's shell. + ps1 + or in a history file maintained by the user's + shell. The may also be used to specify a SIG(0) key used diff --git a/bin/tests/system/tsig/clean.sh b/bin/tests/system/tsig/clean.sh new file mode 100644 index 0000000000..b9cf2913bd --- /dev/null +++ b/bin/tests/system/tsig/clean.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +# $Id: clean.sh,v 1.2 2006/01/27 02:35:14 marka Exp $ + +# +# Clean up after tsig tests. +# + +rm -f dig.out.* diff --git a/bin/tests/system/tsig/ns1/example.db b/bin/tests/system/tsig/ns1/example.db new file mode 100644 index 0000000000..f68fda93e1 --- /dev/null +++ b/bin/tests/system/tsig/ns1/example.db @@ -0,0 +1,152 @@ +; Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +; Copyright (C) 2000-2002 Internet Software Consortium. +; +; Permission to use, copy, modify, and distribute this software for any +; purpose with or without fee is hereby granted, provided that the above +; copyright notice and this permission notice appear in all copies. +; +; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +; PERFORMANCE OF THIS SOFTWARE. + +; $Id: example.db,v 1.2 2006/01/27 02:35:14 marka Exp $ + +$ORIGIN . +$TTL 300 ; 5 minutes +example.nil IN SOA ns1.example.nil. hostmaster.example.nil. ( + 1 ; serial + 2000 ; refresh (2000 seconds) + 2000 ; retry (2000 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) +example.nil. NS ns1.example.nil. +ns1.example.nil. A 10.53.0.1 +example.nil. NS ns2.example.nil. +ns2.example.nil. A 10.53.0.2 + +$ORIGIN example.nil. +* MX 10 mail +a TXT "foo foo foo" + PTR foo.net. +$TTL 3600 ; 1 hour +a01 A 0.0.0.0 +a02 A 255.255.255.255 +a601 AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +afsdb01 AFSDB 0 hostname +afsdb02 AFSDB 65535 . +$TTL 300 ; 5 minutes +b CNAME foo.net. +c A 73.80.65.49 +$TTL 3600 ; 1 hour +cert01 CERT 65534 65535 PRIVATEOID ( + MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi + WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl + d80jEeC8aTrO+KKmCaY= ) +cname01 CNAME cname-target. +cname02 CNAME cname-target +cname03 CNAME . +$TTL 300 ; 5 minutes +d A 73.80.65.49 +$TTL 3600 ; 1 hour +dname01 DNAME dname-target. +dname02 DNAME dname-target +dname03 DNAME . +$TTL 300 ; 5 minutes +e MX 10 mail + TXT "one" + TXT "three" + TXT "two" + A 73.80.65.49 + A 73.80.65.50 + A 73.80.65.52 + A 73.80.65.51 +f A 73.80.65.52 +$TTL 3600 ; 1 hour +gpos01 GPOS "-22.6882" "116.8652" "250.0" +gpos02 GPOS "" "" "" +hinfo01 HINFO "Generic PC clone" "NetBSD-1.4" +hinfo02 HINFO "PC" "NetBSD" +isdn01 ISDN "isdn-address" +isdn02 ISDN "isdn-address" "subaddress" +isdn03 ISDN "isdn-address" +isdn04 ISDN "isdn-address" "subaddress" +key01 KEY 512 255 1 ( + AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR + yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 + GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o + jqf0BaqHT+8= ) +kx01 KX 10 kdc +kx02 KX 10 . +loc01 LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20m 2000m 20m +loc02 LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20m 2000m 20m +mb01 MG madname +mb02 MG . +mg01 MG mgmname +mg02 MG . +minfo01 MINFO rmailbx emailbx +minfo02 MINFO . . +mr01 MR mrname +mr02 MR . +mx01 MX 10 mail +mx02 MX 10 . +naptr01 NAPTR 0 0 "" "" "" . +naptr02 NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo. +nsap-ptr01 NSAP-PTR foo. + NSAP-PTR . +nsap01 NSAP 0x47000580005a0000000001e133ffffff00016100 +nsap02 NSAP 0x47000580005a0000000001e133ffffff00016100 +nxt01 NXT a.secure ( NS SOA MX SIG KEY LOC NXT ) +nxt02 NXT . ( NSAP-PTR NXT ) +nxt03 NXT . ( A ) +nxt04 NXT . ( 127 ) +ptr01 PTR example.nil. +px01 PX 65535 foo. bar. +px02 PX 65535 . . +rp01 RP mbox-dname txt-dname +rp02 RP . . +rt01 RT 0 intermediate-host +rt02 RT 65535 . +$TTL 300 ; 5 minutes +s NS ns.s +$ORIGIN s.example.nil. +ns A 73.80.65.49 +$ORIGIN example.nil. +$TTL 3600 ; 1 hour +sig01 SIG NXT 1 3 3600 20000102030405 ( + 19961211100908 2143 foo + MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi + WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl + d80jEeC8aTrO+KKmCaY= ) +srv01 SRV 0 0 0 . +srv02 SRV 65535 65535 65535 old-slow-box.example.com. +$TTL 301 ; 5 minutes 1 second +t A 73.80.65.49 +$TTL 3600 ; 1 hour +txt01 TXT "foo" +txt02 TXT "foo" "bar" +txt03 TXT "foo" +txt04 TXT "foo" "bar" +txt05 TXT "foo bar" +txt06 TXT "foo bar" +txt07 TXT "foo bar" +txt08 TXT "foo\010bar" +txt09 TXT "foo\010bar" +txt10 TXT "foo bar" +txt11 TXT "\"foo\"" +txt12 TXT "\"foo\"" +$TTL 300 ; 5 minutes +u TXT "txt-not-in-nxt" +$ORIGIN u.example.nil. +a A 73.80.65.49 +b A 73.80.65.49 +$ORIGIN example.nil. +$TTL 3600 ; 1 hour +wks01 WKS 10.0.0.1 6 ( 0 1 2 21 23 ) +wks02 WKS 10.0.0.1 17 ( 0 1 2 53 ) +wks03 WKS 10.0.0.2 6 ( 65535 ) +x2501 X25 "123456789" diff --git a/bin/tests/system/tsig/ns1/named.conf b/bin/tests/system/tsig/ns1/named.conf new file mode 100644 index 0000000000..2a381dff7f --- /dev/null +++ b/bin/tests/system/tsig/ns1/named.conf @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: named.conf,v 1.2 2006/01/27 02:35:14 marka Exp $ */ + +controls { /* empty */ }; + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + recursion no; + notify no; +}; + +key "md5" { + secret "97rnFx24Tfna4mHPfgnerA=="; + algorithm hmac-md5; +}; + +key "sha1" { + secret "FrSt77yPTFx6hTs4i2tKLB9LmE0="; + algorithm hmac-sha1; +}; + +key "sha224" { + secret "hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA=="; + algorithm hmac-sha224; +}; + +key "sha256" { + secret "R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY="; + algorithm hmac-sha256; +}; + +key "sha384" { + secret "OaDdoAk2LAcLtYeUnsT7A9XHjsb6ZEma7OCvUpMraQIJX6HetGrlKmF7yglO1G2h"; + algorithm hmac-sha384; +}; + +key "sha512" { + secret "jI/Pa4qRu96t76Pns5Z/Ndxbn3QCkwcxLOgt9vgvnJw5wqTRvNyk3FtD6yIMd1dWVlqZ+Y4fe6Uasc0ckctEmg=="; + algorithm hmac-sha512; +}; + +key "md5-trunc" { + secret "97rnFx24Tfna4mHPfgnerA=="; + algorithm hmac-md5-80; +}; + +key "sha1-trunc" { + secret "FrSt77yPTFx6hTs4i2tKLB9LmE0="; + algorithm hmac-sha1-80; +}; + +key "sha224-trunc" { + secret "hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA=="; + algorithm hmac-sha224-112; +}; + +key "sha256-trunc" { + secret "R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY="; + algorithm hmac-sha256-128; +}; + +key "sha384-trunc" { + secret "OaDdoAk2LAcLtYeUnsT7A9XHjsb6ZEma7OCvUpMraQIJX6HetGrlKmF7yglO1G2h"; + algorithm hmac-sha384-192; +}; + +key "sha512-trunc" { + secret "jI/Pa4qRu96t76Pns5Z/Ndxbn3QCkwcxLOgt9vgvnJw5wqTRvNyk3FtD6yIMd1dWVlqZ+Y4fe6Uasc0ckctEmg=="; + algorithm hmac-sha512-256; +}; + +zone "example.nil" { + type master; + file "example.db"; +}; diff --git a/bin/tests/system/tsig/tests.sh b/bin/tests/system/tsig/tests.sh new file mode 100644 index 0000000000..9e11a026cb --- /dev/null +++ b/bin/tests/system/tsig/tests.sh @@ -0,0 +1,219 @@ +#!/bin/sh +# +# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2000, 2001 Internet Software Consortium. +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +# $Id: tests.sh,v 1.2 2006/01/27 02:35:14 marka Exp $ + +SYSTEMTESTTOP=.. +. $SYSTEMTESTTOP/conf.sh + +# +# Shared secrets. +# +md5="97rnFx24Tfna4mHPfgnerA==" +sha1="FrSt77yPTFx6hTs4i2tKLB9LmE0=" +sha224="hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA==" +sha256="R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY=" +sha384="OaDdoAk2LAcLtYeUnsT7A9XHjsb6ZEma7OCvUpMraQIJX6HetGrlKmF7yglO1G2h" +sha512="jI/Pa4qRu96t76Pns5Z/Ndxbn3QCkwcxLOgt9vgvnJw5wqTRvNyk3FtD6yIMd1dWVlqZ+Y4fe6Uasc0ckctEmg==" + +status=0 + +echo "I:fetching using hmac-md5 (old form)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "md5:$md5" @10.53.0.1 soa -p 5300 > dig.out.md5.old || ret=1 +grep -i "md5.*TSIG.*NOERROR" dig.out.md5.old > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-md5 (new form)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-md5:md5:$md5" @10.53.0.1 soa -p 5300 > dig.out.md5.new || ret=1 +grep -i "md5.*TSIG.*NOERROR" dig.out.md5.new > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha1" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha1:sha1:$sha1" @10.53.0.1 soa -p 5300 > dig.out.sha1 || ret=1 +grep -i "sha1.*TSIG.*NOERROR" dig.out.sha1 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha224" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha224:sha224:$sha224" @10.53.0.1 soa -p 5300 > dig.out.sha224 || ret=1 +grep -i "sha224.*TSIG.*NOERROR" dig.out.sha224 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha256" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha256:sha256:$sha256" @10.53.0.1 soa -p 5300 > dig.out.sha256 || ret=1 +grep -i "sha256.*TSIG.*NOERROR" dig.out.sha256 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha384" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha384:sha384:$sha384" @10.53.0.1 soa -p 5300 > dig.out.sha384 || ret=1 +grep -i "sha384.*TSIG.*NOERROR" dig.out.sha384 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha512" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha512:sha512:$sha512" @10.53.0.1 soa -p 5300 > dig.out.sha512 || ret=1 +grep -i "sha512.*TSIG.*NOERROR" dig.out.sha512 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +# +# +# Truncated TSIG +# +# +echo "I:fetching using hmac-md5 (trunc)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-md5-80:md5-trunc:$md5" @10.53.0.1 soa -p 5300 > dig.out.md5.trunc || ret=1 +grep -i "md5-trunc.*TSIG.*NOERROR" dig.out.md5.trunc > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha1 (trunc)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha1-80:sha1-trunc:$sha1" @10.53.0.1 soa -p 5300 > dig.out.sha1.trunc || ret=1 +grep -i "sha1.*TSIG.*NOERROR" dig.out.sha1.trunc > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha224 (trunc)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha224-112:sha224-trunc:$sha224" @10.53.0.1 soa -p 5300 > dig.out.sha224.trunc || ret=1 +grep -i "sha224-trunc.*TSIG.*NOERROR" dig.out.sha224.trunc > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha256 (trunc)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha256-128:sha256-trunc:$sha256" @10.53.0.1 soa -p 5300 > dig.out.sha256.trunc || ret=1 +grep -i "sha256-trunc.*TSIG.*NOERROR" dig.out.sha256.trunc > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha384 (trunc)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha384-192:sha384-trunc:$sha384" @10.53.0.1 soa -p 5300 > dig.out.sha384.trunc || ret=1 +grep -i "sha384-trunc.*TSIG.*NOERROR" dig.out.sha384.trunc > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha512-256 (trunc)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha512-256:sha512-trunc:$sha512" @10.53.0.1 soa -p 5300 > dig.out.sha512.trunc || ret=1 +grep -i "sha512-trunc.*TSIG.*NOERROR" dig.out.sha512.trunc > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + + +# +# +# Check for bad truncation. +# +# +echo "I:fetching using hmac-md5-80 (BADTRUNC)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-md5-80:md5:$md5" @10.53.0.1 soa -p 5300 > dig.out.md5-80 || ret=1 +grep -i "md5.*TSIG.*BADTRUNC" dig.out.md5-80 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha1-80 (BADTRUNC)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha1-80:sha1:$sha1" @10.53.0.1 soa -p 5300 > dig.out.sha1-80 || ret=1 +grep -i "sha1.*TSIG.*BADTRUNC" dig.out.sha1-80 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha224-112 (BADTRUNC)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha224-112:sha224:$sha224" @10.53.0.1 soa -p 5300 > dig.out.sha224-112 || ret=1 +grep -i "sha224.*TSIG.*BADTRUNC" dig.out.sha224-112 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha256-128 (BADTRUNC)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha256-128:sha256:$sha256" @10.53.0.1 soa -p 5300 > dig.out.sha256-128 || ret=1 +grep -i "sha256.*TSIG.*BADTRUNC" dig.out.sha256-128 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha384-192 (BADTRUNC)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha384-192:sha384:$sha384" @10.53.0.1 soa -p 5300 > dig.out.sha384-192 || ret=1 +grep -i "sha384.*TSIG.*BADTRUNC" dig.out.sha384-192 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:fetching using hmac-sha512-256 (BADTRUNC)" +ret=0 +$DIG +tcp +nosea +nostat +noquest +nocomm +nocmd example.nil.\ + -y "hmac-sha512-256:sha512:$sha512" @10.53.0.1 soa -p 5300 > dig.out.sha512-256 || ret=1 +grep -i "sha512.*TSIG.*BADTRUNC" dig.out.sha512-256 > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +exit $status + + diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 70c021d7d3..ee15531740 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + BIND 9 Administrator Reference Manual @@ -3639,16 +3639,20 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. matching this name, algorithm, and secret. - - The algorithm_id is a string - that specifies a security/authentication algorithm. The only - algorithm currently supported with TSIG authentication is - hmac-md5. The - secret_string is the secret - to be - used by the algorithm, and is treated as a base-64 encoded - string. - + + The algorithm_id is a string + that specifies a security/authentication algorithm. Named + supports hmac-md5, + hmac-sha1, hmac-sha224, + hmac-sha256, hmac-sha384 + and hmac-sha512 TSIG authentication. + Truncated hashes are supported by appending the minimum + number of required bits preceeded by a dash, e.g. + hmac-sha1-80. The + secret_string is the secret + to be used by the algorithm, and is treated as a base-64 + encoded string. + diff --git a/lib/bind9/check.c b/lib/bind9/check.c index 29e6ed4b33..fe78461a23 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: check.c,v 1.67 2006/01/07 00:23:35 marka Exp $ */ +/* $Id: check.c,v 1.68 2006/01/27 02:35:15 marka Exp $ */ /*! \file */ @@ -1174,11 +1174,31 @@ check_zoneconf(cfg_obj_t *zconfig, cfg_obj_t *voptions, cfg_obj_t *config, return (result); } + +typedef struct keyalgorithms { + const char *name; + isc_uint16_t size; +} algorithmtable; + isc_result_t bind9_check_key(cfg_obj_t *key, isc_log_t *logctx) { cfg_obj_t *algobj = NULL; cfg_obj_t *secretobj = NULL; const char *keyname = cfg_obj_asstring(cfg_map_getname(key)); + const char *algorithm; + int i; + size_t len = 0; + static const algorithmtable algorithms[] = { + { "hmac-md5", 128 }, + { "hmac-md5.sig-alg.reg.int", 0 }, + { "hmac-md5.sig-alg.reg.int.", 0 }, + { "hmac-sha1", 160 }, + { "hmac-sha224", 224 }, + { "hmac-sha256", 256 }, + { "hmac-sha384", 384 }, + { "hmac-sha512", 512 }, + { NULL, 0 } + }; (void)cfg_map_get(key, "algorithm", &algobj); (void)cfg_map_get(key, "secret", &secretobj); @@ -1189,6 +1209,56 @@ bind9_check_key(cfg_obj_t *key, isc_log_t *logctx) { keyname); return (ISC_R_FAILURE); } + + algorithm = cfg_obj_asstring(algobj); + for (i = 0; algorithms[i].name != NULL; i++) { + len = strlen(algorithms[i].name); + if (strncasecmp(algorithms[i].name, algorithm, len) == 0 && + (algorithm[len] == '\0' || + (algorithms[i].size != 0 && algorithm[len] == '-'))) + break; + } + if (algorithms[i].name == NULL) { + cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, + "unknown algorithm '%s'", algorithm); + return (ISC_R_NOTFOUND); + } + if (algorithm[len] == '-') { + isc_uint16_t digestbits; + isc_result_t result; + result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10); + if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) { + if (result == ISC_R_RANGE || + digestbits > algorithms[i].size) { + cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, + "key '%s' digest-bits too large " + "[%u..%u]", keyname, + algorithms[i].size / 2, + algorithms[i].size); + return (ISC_R_RANGE); + } + if ((digestbits % 8) != 0) { + cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, + "key '%s' digest-bits not multiple" + " of 8", keyname); + return (ISC_R_RANGE); + } + /* + * Recommended minima for hmac algorithms. + */ + if ((digestbits < (algorithms[i].size / 2U) || + (digestbits < 80U))) + cfg_obj_log(algobj, logctx, ISC_LOG_WARNING, + "key '%s' digest-bits too small " + "[<%u]", keyname, + algorithms[i].size/2); + } else { + cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, + "key '%s': unable to parse digest-bits", + keyname); + return (result); + } + } return (ISC_R_SUCCESS); } @@ -1206,6 +1276,10 @@ check_keylist(cfg_obj_t *keys, isc_symtab_t *symtab, isc_log_t *logctx) { const char *keyname = cfg_obj_asstring(cfg_map_getname(key)); isc_symvalue_t symvalue; + tresult = bind9_check_key(key, logctx); + if (tresult != ISC_R_SUCCESS) + return (tresult); + symvalue.as_pointer = key; tresult = isc_symtab_define(symtab, keyname, 1, symvalue, isc_symexists_reject); @@ -1227,10 +1301,6 @@ check_keylist(cfg_obj_t *keys, isc_symtab_t *symtab, isc_log_t *logctx) { result = tresult; } else if (tresult != ISC_R_SUCCESS) return (tresult); - - tresult = bind9_check_key(key, logctx); - if (tresult != ISC_R_SUCCESS) - return (tresult); } return (result); } diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 1510649e4b..2bd83174a3 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -18,7 +18,7 @@ /* * Principal Author: Brian Wellington - * $Id: dst_api.c,v 1.5 2005/11/30 03:33:49 marka Exp $ + * $Id: dst_api.c,v 1.6 2006/01/27 02:35:15 marka Exp $ */ /*! \file */ @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -157,6 +158,11 @@ dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { memset(dst_t_func, 0, sizeof(dst_t_func)); RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5])); + RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1])); + RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224])); + RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256])); + RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384])); + RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512])); #ifdef OPENSSL RETERR(dst__openssl_init()); RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5])); @@ -777,6 +783,21 @@ dst_key_sigsize(const dst_key_t *key, unsigned int *n) { case DST_ALG_HMACMD5: *n = 16; break; + case DST_ALG_HMACSHA1: + *n = ISC_SHA1_DIGESTLENGTH; + break; + case DST_ALG_HMACSHA224: + *n = ISC_SHA224_DIGESTLENGTH; + break; + case DST_ALG_HMACSHA256: + *n = ISC_SHA256_DIGESTLENGTH; + break; + case DST_ALG_HMACSHA384: + *n = ISC_SHA384_DIGESTLENGTH; + break; + case DST_ALG_HMACSHA512: + *n = ISC_SHA512_DIGESTLENGTH; + break; case DST_ALG_GSSAPI: *n = 128; /*%< XXX */ break; diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index 92eef13f3a..9bf03b2ddd 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -16,7 +16,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_internal.h,v 1.3 2005/04/29 00:22:45 marka Exp $ */ +/* $Id: dst_internal.h,v 1.4 2006/01/27 02:35:15 marka Exp $ */ #ifndef DST_DST_INTERNAL_H #define DST_DST_INTERNAL_H 1 @@ -55,6 +55,7 @@ struct dst_key { unsigned int key_alg; /*%< algorithm of the key */ isc_uint32_t key_flags; /*%< flags of the public key */ isc_uint16_t key_id; /*%< identifier of the key */ + isc_uint16_t key_bits; /*%< hmac digest bits */ dns_rdataclass_t key_class; /*%< class of the key record */ isc_mem_t *mctx; /*%< memory context */ void * opaque; /*%< pointer to key in crypto pkg fmt */ @@ -107,6 +108,11 @@ struct dst_func { isc_result_t dst__openssl_init(void); isc_result_t dst__hmacmd5_init(struct dst_func **funcp); +isc_result_t dst__hmacsha1_init(struct dst_func **funcp); +isc_result_t dst__hmacsha224_init(struct dst_func **funcp); +isc_result_t dst__hmacsha256_init(struct dst_func **funcp); +isc_result_t dst__hmacsha384_init(struct dst_func **funcp); +isc_result_t dst__hmacsha512_init(struct dst_func **funcp); isc_result_t dst__opensslrsa_init(struct dst_func **funcp); isc_result_t dst__openssldsa_init(struct dst_func **funcp); isc_result_t dst__openssldh_init(struct dst_func **funcp); diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c index e910bbb688..6628d41546 100644 --- a/lib/dns/dst_parse.c +++ b/lib/dns/dst_parse.c @@ -18,7 +18,7 @@ /*% * Principal Author: Brian Wellington - * $Id: dst_parse.c,v 1.3 2005/04/29 00:22:46 marka Exp $ + * $Id: dst_parse.c,v 1.4 2006/01/27 02:35:15 marka Exp $ */ #include @@ -67,6 +67,23 @@ static struct parse_map map[] = { {TAG_DSA_PUBLIC, "Public_value(y):"}, {TAG_HMACMD5_KEY, "Key:"}, + {TAG_HMACMD5_BITS, "Bits:"}, + + {TAG_HMACSHA1_KEY, "Key:"}, + {TAG_HMACSHA1_BITS, "Bits:"}, + + {TAG_HMACSHA224_KEY, "Key:"}, + {TAG_HMACSHA224_BITS, "Bits:"}, + + {TAG_HMACSHA256_KEY, "Key:"}, + {TAG_HMACSHA256_BITS, "Bits:"}, + + {TAG_HMACSHA384_KEY, "Key:"}, + {TAG_HMACSHA384_BITS, "Bits:"}, + + {TAG_HMACSHA512_KEY, "Key:"}, + {TAG_HMACSHA512_BITS, "Bits:"}, + {0, NULL} }; @@ -141,16 +158,46 @@ check_dsa(const dst_private_t *priv) { } static int -check_hmac_md5(const dst_private_t *priv) { - if (priv->nelements != HMACMD5_NTAGS) +check_hmac_md5(const dst_private_t *priv, isc_boolean_t old) { + int i, j; + + if (!((priv->nelements == HMACMD5_NTAGS) || + (old && (priv->nelements == OLD_HMACMD5_NTAGS)))) return (-1); - if (priv->elements[0].tag != TAG_HMACMD5_KEY) + if (priv->nelements == OLD_HMACMD5_NTAGS && + priv->elements[0].tag != TAG_HMACMD5_KEY) return (-1); + for (i = 0; i < DSA_NTAGS; i++) { + for (j = 0; j < priv->nelements; j++) + if (priv->elements[j].tag == TAG(DST_ALG_DSA, i)) + break; + if (j == priv->nelements) + return (-1); + } return (0); } static int -check_data(const dst_private_t *priv, const unsigned int alg) { +check_hmac_sha(const dst_private_t *priv, unsigned int ntags, + unsigned int alg) +{ + unsigned int i, j; + if (priv->nelements != ntags) + return (-1); + for (i = 0; i < ntags; i++) { + for (j = 0; j < priv->nelements; j++) + if (priv->elements[j].tag == TAG(alg, i)) + break; + if (j == priv->nelements) + return (-1); + } + return (0); +} + +static int +check_data(const dst_private_t *priv, const unsigned int alg, + isc_boolean_t old) +{ /* XXXVIX this switch statement is too sparse to gen a jump table. */ switch (alg) { case DST_ALG_RSAMD5: @@ -161,7 +208,17 @@ check_data(const dst_private_t *priv, const unsigned int alg) { case DST_ALG_DSA: return (check_dsa(priv)); case DST_ALG_HMACMD5: - return (check_hmac_md5(priv)); + return (check_hmac_md5(priv, old)); + case DST_ALG_HMACSHA1: + return (check_hmac_sha(priv, HMACSHA1_NTAGS, alg)); + case DST_ALG_HMACSHA224: + return (check_hmac_sha(priv, HMACSHA224_NTAGS, alg)); + case DST_ALG_HMACSHA256: + return (check_hmac_sha(priv, HMACSHA256_NTAGS, alg)); + case DST_ALG_HMACSHA384: + return (check_hmac_sha(priv, HMACSHA384_NTAGS, alg)); + case DST_ALG_HMACSHA512: + return (check_hmac_sha(priv, HMACSHA512_NTAGS, alg)); default: return (DST_R_UNSUPPORTEDALG); } @@ -313,7 +370,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, done: priv->nelements = n; - if (check_data(priv, alg) < 0) + if (check_data(priv, alg, ISC_TRUE) < 0) goto fail; return (ISC_R_SUCCESS); @@ -341,7 +398,7 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, REQUIRE(priv != NULL); - if (check_data(priv, dst_key_alg(key)) < 0) + if (check_data(priv, dst_key_alg(key), ISC_FALSE) < 0) return (DST_R_INVALIDPRIVATEKEY); isc_buffer_init(&b, filename, sizeof(filename)); @@ -380,6 +437,21 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, case DST_ALG_HMACMD5: fprintf(fp, "(HMAC_MD5)\n"); break; + case DST_ALG_HMACSHA1: + fprintf(fp, "(HMAC_SHA1)\n"); + break; + case DST_ALG_HMACSHA224: + fprintf(fp, "(HMAC_SHA224)\n"); + break; + case DST_ALG_HMACSHA256: + fprintf(fp, "(HMAC_SHA256)\n"); + break; + case DST_ALG_HMACSHA384: + fprintf(fp, "(HMAC_SHA384)\n"); + break; + case DST_ALG_HMACSHA512: + fprintf(fp, "(HMAC_SHA512)\n"); + break; default: fprintf(fp, "(?)\n"); break; diff --git a/lib/dns/dst_parse.h b/lib/dns/dst_parse.h index 67342f6f56..ca159a5397 100644 --- a/lib/dns/dst_parse.h +++ b/lib/dns/dst_parse.h @@ -16,7 +16,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_parse.h,v 1.3 2005/04/29 00:22:46 marka Exp $ */ +/* $Id: dst_parse.h,v 1.4 2006/01/27 02:35:15 marka Exp $ */ /*! \file */ #ifndef DST_DST_PARSE_H @@ -60,8 +60,30 @@ #define TAG_DSA_PRIVATE ((DST_ALG_DSA << TAG_SHIFT) + 3) #define TAG_DSA_PUBLIC ((DST_ALG_DSA << TAG_SHIFT) + 4) -#define HMACMD5_NTAGS 1 +#define OLD_HMACMD5_NTAGS 1 +#define HMACMD5_NTAGS 2 #define TAG_HMACMD5_KEY ((DST_ALG_HMACMD5 << TAG_SHIFT) + 0) +#define TAG_HMACMD5_BITS ((DST_ALG_HMACMD5 << TAG_SHIFT) + 1) + +#define HMACSHA1_NTAGS 2 +#define TAG_HMACSHA1_KEY ((DST_ALG_HMACSHA1 << TAG_SHIFT) + 0) +#define TAG_HMACSHA1_BITS ((DST_ALG_HMACSHA1 << TAG_SHIFT) + 1) + +#define HMACSHA224_NTAGS 2 +#define TAG_HMACSHA224_KEY ((DST_ALG_HMACSHA224 << TAG_SHIFT) + 0) +#define TAG_HMACSHA224_BITS ((DST_ALG_HMACSHA224 << TAG_SHIFT) + 1) + +#define HMACSHA256_NTAGS 2 +#define TAG_HMACSHA256_KEY ((DST_ALG_HMACSHA256 << TAG_SHIFT) + 0) +#define TAG_HMACSHA256_BITS ((DST_ALG_HMACSHA224 << TAG_SHIFT) + 1) + +#define HMACSHA384_NTAGS 2 +#define TAG_HMACSHA384_KEY ((DST_ALG_HMACSHA384 << TAG_SHIFT) + 0) +#define TAG_HMACSHA384_BITS ((DST_ALG_HMACSHA384 << TAG_SHIFT) + 1) + +#define HMACSHA512_NTAGS 2 +#define TAG_HMACSHA512_KEY ((DST_ALG_HMACSHA512 << TAG_SHIFT) + 0) +#define TAG_HMACSHA512_BITS ((DST_ALG_HMACSHA512 << TAG_SHIFT) + 1) struct dst_private_element { unsigned short tag; diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c index 49d3c5b6e7..1b6b1fb8a6 100644 --- a/lib/dns/hmac_link.c +++ b/lib/dns/hmac_link.c @@ -18,14 +18,16 @@ /* * Principal Author: Brian Wellington - * $Id: hmac_link.c,v 1.3 2005/04/29 00:22:47 marka Exp $ + * $Id: hmac_link.c,v 1.4 2006/01/27 02:35:15 marka Exp $ */ #include #include #include +#include #include +#include #include #include #include @@ -45,6 +47,17 @@ typedef struct hmackey { unsigned char key[HMAC_LEN]; } HMAC_Key; +static isc_result_t +getkeybits(dst_key_t *key, struct dst_private_element *element) { + + if (element->length != 2) + return (DST_R_INVALIDPRIVATEKEY); + + key->key_bits = (element->data[0] << 8) + element->data[1]; + + return (ISC_R_SUCCESS); +} + static isc_result_t hmacmd5_createctx(dst_key_t *key, dst_context_t *dctx) { isc_hmacmd5_t *hmacmd5ctx; @@ -95,10 +108,10 @@ static isc_result_t hmacmd5_verify(dst_context_t *dctx, const isc_region_t *sig) { isc_hmacmd5_t *hmacmd5ctx = dctx->opaque; - if (sig->length < ISC_MD5_DIGESTLENGTH) + if (sig->length > ISC_MD5_DIGESTLENGTH) return (DST_R_VERIFYFAILURE); - if (isc_hmacmd5_verify(hmacmd5ctx, sig->base)) + if (isc_hmacmd5_verify2(hmacmd5ctx, sig->base, sig->length)) return (ISC_R_SUCCESS); else return (DST_R_VERIFYFAILURE); @@ -130,9 +143,9 @@ hmacmd5_generate(dst_key_t *key, int pseudorandom_ok) { unsigned char data[HMAC_LEN]; bytes = (key->key_size + 7) / 8; - if (bytes > 64) { - bytes = 64; - key->key_size = 512; + if (bytes > HMAC_LEN) { + bytes = HMAC_LEN; + key->key_size = HMAC_LEN * 8; } memset(data, 0, HMAC_LEN); @@ -220,6 +233,7 @@ hmacmd5_tofile(const dst_key_t *key, const char *directory) { HMAC_Key *hkey; dst_private_t priv; int bytes = (key->key_size + 7) / 8; + unsigned char buf[2]; if (key->opaque == NULL) return (DST_R_NULLKEY); @@ -230,6 +244,12 @@ hmacmd5_tofile(const dst_key_t *key, const char *directory) { priv.elements[cnt].length = bytes; priv.elements[cnt++].data = hkey->key; + buf[0] = (key->key_bits >> 8) & 0xffU; + buf[1] = key->key_bits & 0xffU; + priv.elements[cnt].tag = TAG_HMACMD5_BITS; + priv.elements[cnt].data = buf; + priv.elements[cnt++].length = 2; + priv.nelements = cnt; return (dst__privstruct_writefile(key, &priv, directory)); } @@ -237,21 +257,40 @@ hmacmd5_tofile(const dst_key_t *key, const char *directory) { static isc_result_t hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer) { dst_private_t priv; - isc_result_t ret; + isc_result_t result, tresult; isc_buffer_t b; isc_mem_t *mctx = key->mctx; + unsigned int i; /* read private key file */ - ret = dst__privstruct_parse(key, DST_ALG_HMACMD5, lexer, mctx, &priv); - if (ret != ISC_R_SUCCESS) - return (ret); + result = dst__privstruct_parse(key, DST_ALG_HMACMD5, lexer, mctx, &priv); + if (result != ISC_R_SUCCESS) + return (result); - isc_buffer_init(&b, priv.elements[0].data, priv.elements[0].length); - isc_buffer_add(&b, priv.elements[0].length); - ret = hmacmd5_fromdns(key, &b); + key->key_bits = 0; + for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) { + switch (priv.elements[i].tag) { + case TAG_HMACMD5_KEY: + isc_buffer_init(&b, priv.elements[i].data, + priv.elements[i].length); + isc_buffer_add(&b, priv.elements[i].length); + tresult = hmacmd5_fromdns(key, &b); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + case TAG_HMACMD5_BITS: + tresult = getkeybits(key, &priv.elements[i]); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + default: + result = DST_R_INVALIDPRIVATEKEY; + break; + } + } dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); - return (ret); + return (result); } static dst_func_t hmacmd5_functions = { @@ -281,4 +320,1349 @@ dst__hmacmd5_init(dst_func_t **funcp) { return (ISC_R_SUCCESS); } +static isc_result_t hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data); + +typedef struct { + unsigned char key[ISC_SHA1_DIGESTLENGTH]; +} HMACSHA1_Key; + +static isc_result_t +hmacsha1_createctx(dst_key_t *key, dst_context_t *dctx) { + isc_hmacsha1_t *hmacsha1ctx; + HMACSHA1_Key *hkey = key->opaque; + + hmacsha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha1_t)); + if (hmacsha1ctx == NULL) + return (ISC_R_NOMEMORY); + isc_hmacsha1_init(hmacsha1ctx, hkey->key, ISC_SHA1_DIGESTLENGTH); + dctx->opaque = hmacsha1ctx; + return (ISC_R_SUCCESS); +} + +static void +hmacsha1_destroyctx(dst_context_t *dctx) { + isc_hmacsha1_t *hmacsha1ctx = dctx->opaque; + + if (hmacsha1ctx != NULL) { + isc_hmacsha1_invalidate(hmacsha1ctx); + isc_mem_put(dctx->mctx, hmacsha1ctx, sizeof(isc_hmacsha1_t)); + dctx->opaque = NULL; + } +} + +static isc_result_t +hmacsha1_adddata(dst_context_t *dctx, const isc_region_t *data) { + isc_hmacsha1_t *hmacsha1ctx = dctx->opaque; + + isc_hmacsha1_update(hmacsha1ctx, data->base, data->length); + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha1_sign(dst_context_t *dctx, isc_buffer_t *sig) { + isc_hmacsha1_t *hmacsha1ctx = dctx->opaque; + unsigned char *digest; + + if (isc_buffer_availablelength(sig) < ISC_SHA1_DIGESTLENGTH) + return (ISC_R_NOSPACE); + digest = isc_buffer_used(sig); + isc_hmacsha1_sign(hmacsha1ctx, digest, ISC_SHA1_DIGESTLENGTH); + isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha1_verify(dst_context_t *dctx, const isc_region_t *sig) { + isc_hmacsha1_t *hmacsha1ctx = dctx->opaque; + + if (sig->length > ISC_SHA1_DIGESTLENGTH || sig->length == 0) + return (DST_R_VERIFYFAILURE); + + if (isc_hmacsha1_verify(hmacsha1ctx, sig->base, sig->length)) + return (ISC_R_SUCCESS); + else + return (DST_R_VERIFYFAILURE); +} + +static isc_boolean_t +hmacsha1_compare(const dst_key_t *key1, const dst_key_t *key2) { + HMACSHA1_Key *hkey1, *hkey2; + + hkey1 = (HMACSHA1_Key *)key1->opaque; + hkey2 = (HMACSHA1_Key *)key2->opaque; + + if (hkey1 == NULL && hkey2 == NULL) + return (ISC_TRUE); + else if (hkey1 == NULL || hkey2 == NULL) + return (ISC_FALSE); + + if (memcmp(hkey1->key, hkey2->key, ISC_SHA1_DIGESTLENGTH) == 0) + return (ISC_TRUE); + else + return (ISC_FALSE); +} + +static isc_result_t +hmacsha1_generate(dst_key_t *key, int pseudorandom_ok) { + isc_buffer_t b; + isc_result_t ret; + int bytes; + unsigned char data[HMAC_LEN]; + + bytes = (key->key_size + 7) / 8; + if (bytes > HMAC_LEN) { + bytes = HMAC_LEN; + key->key_size = HMAC_LEN * 8; + } + + memset(data, 0, HMAC_LEN); + ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); + + if (ret != ISC_R_SUCCESS) + return (ret); + + isc_buffer_init(&b, data, bytes); + isc_buffer_add(&b, bytes); + ret = hmacsha1_fromdns(key, &b); + memset(data, 0, ISC_SHA1_DIGESTLENGTH); + + return (ret); +} + +static isc_boolean_t +hmacsha1_isprivate(const dst_key_t *key) { + UNUSED(key); + return (ISC_TRUE); +} + +static void +hmacsha1_destroy(dst_key_t *key) { + HMACSHA1_Key *hkey = key->opaque; + memset(hkey, 0, sizeof(HMACSHA1_Key)); + isc_mem_put(key->mctx, hkey, sizeof(HMACSHA1_Key)); + key->opaque = NULL; +} + +static isc_result_t +hmacsha1_todns(const dst_key_t *key, isc_buffer_t *data) { + HMACSHA1_Key *hkey; + unsigned int bytes; + + REQUIRE(key->opaque != NULL); + + hkey = (HMACSHA1_Key *) key->opaque; + + bytes = (key->key_size + 7) / 8; + if (isc_buffer_availablelength(data) < bytes) + return (ISC_R_NOSPACE); + isc_buffer_putmem(data, hkey->key, bytes); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) { + HMACSHA1_Key *hkey; + int keylen; + isc_region_t r; + isc_sha1_t sha1ctx; + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); + + hkey = (HMACSHA1_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA1_Key)); + if (hkey == NULL) + return (ISC_R_NOMEMORY); + + memset(hkey->key, 0, sizeof(hkey->key)); + + if (r.length > ISC_SHA1_DIGESTLENGTH) { + isc_sha1_init(&sha1ctx); + isc_sha1_update(&sha1ctx, r.base, r.length); + isc_sha1_final(&sha1ctx, hkey->key); + keylen = ISC_SHA1_DIGESTLENGTH; + } + else { + memcpy(hkey->key, r.base, r.length); + keylen = r.length; + } + + key->key_size = keylen * 8; + key->opaque = hkey; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha1_tofile(const dst_key_t *key, const char *directory) { + int cnt = 0; + HMACSHA1_Key *hkey; + dst_private_t priv; + int bytes = (key->key_size + 7) / 8; + unsigned char buf[2]; + + if (key->opaque == NULL) + return (DST_R_NULLKEY); + + hkey = (HMACSHA1_Key *) key->opaque; + + priv.elements[cnt].tag = TAG_HMACSHA1_KEY; + priv.elements[cnt].length = bytes; + priv.elements[cnt++].data = hkey->key; + + buf[0] = (key->key_bits >> 8) & 0xffU; + buf[1] = key->key_bits & 0xffU; + priv.elements[cnt].tag = TAG_HMACSHA1_BITS; + priv.elements[cnt].data = buf; + priv.elements[cnt++].length = 2; + + priv.nelements = cnt; + return (dst__privstruct_writefile(key, &priv, directory)); +} + +static isc_result_t +hmacsha1_parse(dst_key_t *key, isc_lex_t *lexer) { + dst_private_t priv; + isc_result_t result, tresult; + isc_buffer_t b; + isc_mem_t *mctx = key->mctx; + unsigned int i; + + /* read private key file */ + result = dst__privstruct_parse(key, DST_ALG_HMACSHA1, lexer, mctx, + &priv); + if (result != ISC_R_SUCCESS) + return (result); + + key->key_bits = 0; + for (i = 0; i < priv.nelements; i++) { + switch (priv.elements[i].tag) { + case TAG_HMACSHA1_KEY: + isc_buffer_init(&b, priv.elements[i].data, + priv.elements[i].length); + isc_buffer_add(&b, priv.elements[i].length); + tresult = hmacsha1_fromdns(key, &b); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + case TAG_HMACSHA1_BITS: + tresult = getkeybits(key, &priv.elements[i]); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + default: + result = DST_R_INVALIDPRIVATEKEY; + break; + } + } + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (result); +} + +static dst_func_t hmacsha1_functions = { + hmacsha1_createctx, + hmacsha1_destroyctx, + hmacsha1_adddata, + hmacsha1_sign, + hmacsha1_verify, + NULL, /* computesecret */ + hmacsha1_compare, + NULL, /* paramcompare */ + hmacsha1_generate, + hmacsha1_isprivate, + hmacsha1_destroy, + hmacsha1_todns, + hmacsha1_fromdns, + hmacsha1_tofile, + hmacsha1_parse, + NULL, /* cleanup */ +}; + +isc_result_t +dst__hmacsha1_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + if (*funcp == NULL) + *funcp = &hmacsha1_functions; + return (ISC_R_SUCCESS); +} + +static isc_result_t hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data); + +typedef struct { + unsigned char key[ISC_SHA224_DIGESTLENGTH]; +} HMACSHA224_Key; + +static isc_result_t +hmacsha224_createctx(dst_key_t *key, dst_context_t *dctx) { + isc_hmacsha224_t *hmacsha224ctx; + HMACSHA224_Key *hkey = key->opaque; + + hmacsha224ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha224_t)); + if (hmacsha224ctx == NULL) + return (ISC_R_NOMEMORY); + isc_hmacsha224_init(hmacsha224ctx, hkey->key, ISC_SHA224_DIGESTLENGTH); + dctx->opaque = hmacsha224ctx; + return (ISC_R_SUCCESS); +} + +static void +hmacsha224_destroyctx(dst_context_t *dctx) { + isc_hmacsha224_t *hmacsha224ctx = dctx->opaque; + + if (hmacsha224ctx != NULL) { + isc_hmacsha224_invalidate(hmacsha224ctx); + isc_mem_put(dctx->mctx, hmacsha224ctx, sizeof(isc_hmacsha224_t)); + dctx->opaque = NULL; + } +} + +static isc_result_t +hmacsha224_adddata(dst_context_t *dctx, const isc_region_t *data) { + isc_hmacsha224_t *hmacsha224ctx = dctx->opaque; + + isc_hmacsha224_update(hmacsha224ctx, data->base, data->length); + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha224_sign(dst_context_t *dctx, isc_buffer_t *sig) { + isc_hmacsha224_t *hmacsha224ctx = dctx->opaque; + unsigned char *digest; + + if (isc_buffer_availablelength(sig) < ISC_SHA224_DIGESTLENGTH) + return (ISC_R_NOSPACE); + digest = isc_buffer_used(sig); + isc_hmacsha224_sign(hmacsha224ctx, digest, ISC_SHA224_DIGESTLENGTH); + isc_buffer_add(sig, ISC_SHA224_DIGESTLENGTH); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha224_verify(dst_context_t *dctx, const isc_region_t *sig) { + isc_hmacsha224_t *hmacsha224ctx = dctx->opaque; + + if (sig->length > ISC_SHA224_DIGESTLENGTH || sig->length == 0) + return (DST_R_VERIFYFAILURE); + + if (isc_hmacsha224_verify(hmacsha224ctx, sig->base, sig->length)) + return (ISC_R_SUCCESS); + else + return (DST_R_VERIFYFAILURE); +} + +static isc_boolean_t +hmacsha224_compare(const dst_key_t *key1, const dst_key_t *key2) { + HMACSHA224_Key *hkey1, *hkey2; + + hkey1 = (HMACSHA224_Key *)key1->opaque; + hkey2 = (HMACSHA224_Key *)key2->opaque; + + if (hkey1 == NULL && hkey2 == NULL) + return (ISC_TRUE); + else if (hkey1 == NULL || hkey2 == NULL) + return (ISC_FALSE); + + if (memcmp(hkey1->key, hkey2->key, ISC_SHA224_DIGESTLENGTH) == 0) + return (ISC_TRUE); + else + return (ISC_FALSE); +} + +static isc_result_t +hmacsha224_generate(dst_key_t *key, int pseudorandom_ok) { + isc_buffer_t b; + isc_result_t ret; + int bytes; + unsigned char data[HMAC_LEN]; + + bytes = (key->key_size + 7) / 8; + if (bytes > HMAC_LEN) { + bytes = HMAC_LEN; + key->key_size = HMAC_LEN * 8; + } + + memset(data, 0, HMAC_LEN); + ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); + + if (ret != ISC_R_SUCCESS) + return (ret); + + isc_buffer_init(&b, data, bytes); + isc_buffer_add(&b, bytes); + ret = hmacsha224_fromdns(key, &b); + memset(data, 0, ISC_SHA224_DIGESTLENGTH); + + return (ret); +} + +static isc_boolean_t +hmacsha224_isprivate(const dst_key_t *key) { + UNUSED(key); + return (ISC_TRUE); +} + +static void +hmacsha224_destroy(dst_key_t *key) { + HMACSHA224_Key *hkey = key->opaque; + memset(hkey, 0, sizeof(HMACSHA224_Key)); + isc_mem_put(key->mctx, hkey, sizeof(HMACSHA224_Key)); + key->opaque = NULL; +} + +static isc_result_t +hmacsha224_todns(const dst_key_t *key, isc_buffer_t *data) { + HMACSHA224_Key *hkey; + unsigned int bytes; + + REQUIRE(key->opaque != NULL); + + hkey = (HMACSHA224_Key *) key->opaque; + + bytes = (key->key_size + 7) / 8; + if (isc_buffer_availablelength(data) < bytes) + return (ISC_R_NOSPACE); + isc_buffer_putmem(data, hkey->key, bytes); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) { + HMACSHA224_Key *hkey; + int keylen; + isc_region_t r; + isc_sha224_t sha224ctx; + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); + + hkey = (HMACSHA224_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA224_Key)); + if (hkey == NULL) + return (ISC_R_NOMEMORY); + + memset(hkey->key, 0, sizeof(hkey->key)); + + if (r.length > ISC_SHA224_DIGESTLENGTH) { + isc_sha224_init(&sha224ctx); + isc_sha224_update(&sha224ctx, r.base, r.length); + isc_sha224_final(hkey->key, &sha224ctx); + keylen = ISC_SHA224_DIGESTLENGTH; + } + else { + memcpy(hkey->key, r.base, r.length); + keylen = r.length; + } + + key->key_size = keylen * 8; + key->opaque = hkey; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha224_tofile(const dst_key_t *key, const char *directory) { + int cnt = 0; + HMACSHA224_Key *hkey; + dst_private_t priv; + int bytes = (key->key_size + 7) / 8; + unsigned char buf[2]; + + if (key->opaque == NULL) + return (DST_R_NULLKEY); + + hkey = (HMACSHA224_Key *) key->opaque; + + priv.elements[cnt].tag = TAG_HMACSHA224_KEY; + priv.elements[cnt].length = bytes; + priv.elements[cnt++].data = hkey->key; + + buf[0] = (key->key_bits >> 8) & 0xffU; + buf[1] = key->key_bits & 0xffU; + priv.elements[cnt].tag = TAG_HMACSHA224_BITS; + priv.elements[cnt].data = buf; + priv.elements[cnt++].length = 2; + + priv.nelements = cnt; + return (dst__privstruct_writefile(key, &priv, directory)); +} + +static isc_result_t +hmacsha224_parse(dst_key_t *key, isc_lex_t *lexer) { + dst_private_t priv; + isc_result_t result, tresult; + isc_buffer_t b; + isc_mem_t *mctx = key->mctx; + unsigned int i; + + /* read private key file */ + result = dst__privstruct_parse(key, DST_ALG_HMACSHA224, lexer, mctx, + &priv); + if (result != ISC_R_SUCCESS) + return (result); + + key->key_bits = 0; + for (i = 0; i < priv.nelements; i++) { + switch (priv.elements[i].tag) { + case TAG_HMACSHA224_KEY: + isc_buffer_init(&b, priv.elements[i].data, + priv.elements[i].length); + isc_buffer_add(&b, priv.elements[i].length); + tresult = hmacsha224_fromdns(key, &b); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + case TAG_HMACSHA224_BITS: + tresult = getkeybits(key, &priv.elements[i]); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + default: + result = DST_R_INVALIDPRIVATEKEY; + break; + } + } + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (result); +} + +static dst_func_t hmacsha224_functions = { + hmacsha224_createctx, + hmacsha224_destroyctx, + hmacsha224_adddata, + hmacsha224_sign, + hmacsha224_verify, + NULL, /* computesecret */ + hmacsha224_compare, + NULL, /* paramcompare */ + hmacsha224_generate, + hmacsha224_isprivate, + hmacsha224_destroy, + hmacsha224_todns, + hmacsha224_fromdns, + hmacsha224_tofile, + hmacsha224_parse, + NULL, /* cleanup */ +}; + +isc_result_t +dst__hmacsha224_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + if (*funcp == NULL) + *funcp = &hmacsha224_functions; + return (ISC_R_SUCCESS); +} + +static isc_result_t hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data); + +typedef struct { + unsigned char key[ISC_SHA256_DIGESTLENGTH]; +} HMACSHA256_Key; + +static isc_result_t +hmacsha256_createctx(dst_key_t *key, dst_context_t *dctx) { + isc_hmacsha256_t *hmacsha256ctx; + HMACSHA256_Key *hkey = key->opaque; + + hmacsha256ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha256_t)); + if (hmacsha256ctx == NULL) + return (ISC_R_NOMEMORY); + isc_hmacsha256_init(hmacsha256ctx, hkey->key, ISC_SHA256_DIGESTLENGTH); + dctx->opaque = hmacsha256ctx; + return (ISC_R_SUCCESS); +} + +static void +hmacsha256_destroyctx(dst_context_t *dctx) { + isc_hmacsha256_t *hmacsha256ctx = dctx->opaque; + + if (hmacsha256ctx != NULL) { + isc_hmacsha256_invalidate(hmacsha256ctx); + isc_mem_put(dctx->mctx, hmacsha256ctx, sizeof(isc_hmacsha256_t)); + dctx->opaque = NULL; + } +} + +static isc_result_t +hmacsha256_adddata(dst_context_t *dctx, const isc_region_t *data) { + isc_hmacsha256_t *hmacsha256ctx = dctx->opaque; + + isc_hmacsha256_update(hmacsha256ctx, data->base, data->length); + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha256_sign(dst_context_t *dctx, isc_buffer_t *sig) { + isc_hmacsha256_t *hmacsha256ctx = dctx->opaque; + unsigned char *digest; + + if (isc_buffer_availablelength(sig) < ISC_SHA256_DIGESTLENGTH) + return (ISC_R_NOSPACE); + digest = isc_buffer_used(sig); + isc_hmacsha256_sign(hmacsha256ctx, digest, ISC_SHA256_DIGESTLENGTH); + isc_buffer_add(sig, ISC_SHA256_DIGESTLENGTH); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha256_verify(dst_context_t *dctx, const isc_region_t *sig) { + isc_hmacsha256_t *hmacsha256ctx = dctx->opaque; + + if (sig->length > ISC_SHA256_DIGESTLENGTH || sig->length == 0) + return (DST_R_VERIFYFAILURE); + + if (isc_hmacsha256_verify(hmacsha256ctx, sig->base, sig->length)) + return (ISC_R_SUCCESS); + else + return (DST_R_VERIFYFAILURE); +} + +static isc_boolean_t +hmacsha256_compare(const dst_key_t *key1, const dst_key_t *key2) { + HMACSHA256_Key *hkey1, *hkey2; + + hkey1 = (HMACSHA256_Key *)key1->opaque; + hkey2 = (HMACSHA256_Key *)key2->opaque; + + if (hkey1 == NULL && hkey2 == NULL) + return (ISC_TRUE); + else if (hkey1 == NULL || hkey2 == NULL) + return (ISC_FALSE); + + if (memcmp(hkey1->key, hkey2->key, ISC_SHA256_DIGESTLENGTH) == 0) + return (ISC_TRUE); + else + return (ISC_FALSE); +} + +static isc_result_t +hmacsha256_generate(dst_key_t *key, int pseudorandom_ok) { + isc_buffer_t b; + isc_result_t ret; + int bytes; + unsigned char data[HMAC_LEN]; + + bytes = (key->key_size + 7) / 8; + if (bytes > HMAC_LEN) { + bytes = HMAC_LEN; + key->key_size = HMAC_LEN * 8; + } + + memset(data, 0, HMAC_LEN); + ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); + + if (ret != ISC_R_SUCCESS) + return (ret); + + isc_buffer_init(&b, data, bytes); + isc_buffer_add(&b, bytes); + ret = hmacsha256_fromdns(key, &b); + memset(data, 0, ISC_SHA256_DIGESTLENGTH); + + return (ret); +} + +static isc_boolean_t +hmacsha256_isprivate(const dst_key_t *key) { + UNUSED(key); + return (ISC_TRUE); +} + +static void +hmacsha256_destroy(dst_key_t *key) { + HMACSHA256_Key *hkey = key->opaque; + memset(hkey, 0, sizeof(HMACSHA256_Key)); + isc_mem_put(key->mctx, hkey, sizeof(HMACSHA256_Key)); + key->opaque = NULL; +} + +static isc_result_t +hmacsha256_todns(const dst_key_t *key, isc_buffer_t *data) { + HMACSHA256_Key *hkey; + unsigned int bytes; + + REQUIRE(key->opaque != NULL); + + hkey = (HMACSHA256_Key *) key->opaque; + + bytes = (key->key_size + 7) / 8; + if (isc_buffer_availablelength(data) < bytes) + return (ISC_R_NOSPACE); + isc_buffer_putmem(data, hkey->key, bytes); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) { + HMACSHA256_Key *hkey; + int keylen; + isc_region_t r; + isc_sha256_t sha256ctx; + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); + + hkey = (HMACSHA256_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA256_Key)); + if (hkey == NULL) + return (ISC_R_NOMEMORY); + + memset(hkey->key, 0, sizeof(hkey->key)); + + if (r.length > ISC_SHA256_DIGESTLENGTH) { + isc_sha256_init(&sha256ctx); + isc_sha256_update(&sha256ctx, r.base, r.length); + isc_sha256_final(hkey->key, &sha256ctx); + keylen = ISC_SHA256_DIGESTLENGTH; + } + else { + memcpy(hkey->key, r.base, r.length); + keylen = r.length; + } + + key->key_size = keylen * 8; + key->opaque = hkey; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha256_tofile(const dst_key_t *key, const char *directory) { + int cnt = 0; + HMACSHA256_Key *hkey; + dst_private_t priv; + int bytes = (key->key_size + 7) / 8; + unsigned char buf[2]; + + if (key->opaque == NULL) + return (DST_R_NULLKEY); + + hkey = (HMACSHA256_Key *) key->opaque; + + priv.elements[cnt].tag = TAG_HMACSHA256_KEY; + priv.elements[cnt].length = bytes; + priv.elements[cnt++].data = hkey->key; + + buf[0] = (key->key_bits >> 8) & 0xffU; + buf[1] = key->key_bits & 0xffU; + priv.elements[cnt].tag = TAG_HMACSHA256_BITS; + priv.elements[cnt].data = buf; + priv.elements[cnt++].length = 2; + + priv.nelements = cnt; + return (dst__privstruct_writefile(key, &priv, directory)); +} + +static isc_result_t +hmacsha256_parse(dst_key_t *key, isc_lex_t *lexer) { + dst_private_t priv; + isc_result_t result, tresult; + isc_buffer_t b; + isc_mem_t *mctx = key->mctx; + unsigned int i; + + /* read private key file */ + result = dst__privstruct_parse(key, DST_ALG_HMACSHA256, lexer, mctx, + &priv); + if (result != ISC_R_SUCCESS) + return (result); + + key->key_bits = 0; + for (i = 0; i < priv.nelements; i++) { + switch (priv.elements[i].tag) { + case TAG_HMACSHA256_KEY: + isc_buffer_init(&b, priv.elements[i].data, + priv.elements[i].length); + isc_buffer_add(&b, priv.elements[i].length); + tresult = hmacsha256_fromdns(key, &b); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + case TAG_HMACSHA256_BITS: + tresult = getkeybits(key, &priv.elements[i]); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + default: + result = DST_R_INVALIDPRIVATEKEY; + break; + } + } + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (result); +} + +static dst_func_t hmacsha256_functions = { + hmacsha256_createctx, + hmacsha256_destroyctx, + hmacsha256_adddata, + hmacsha256_sign, + hmacsha256_verify, + NULL, /* computesecret */ + hmacsha256_compare, + NULL, /* paramcompare */ + hmacsha256_generate, + hmacsha256_isprivate, + hmacsha256_destroy, + hmacsha256_todns, + hmacsha256_fromdns, + hmacsha256_tofile, + hmacsha256_parse, + NULL, /* cleanup */ +}; + +isc_result_t +dst__hmacsha256_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + if (*funcp == NULL) + *funcp = &hmacsha256_functions; + return (ISC_R_SUCCESS); +} + +static isc_result_t hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data); + +typedef struct { + unsigned char key[ISC_SHA384_DIGESTLENGTH]; +} HMACSHA384_Key; + +static isc_result_t +hmacsha384_createctx(dst_key_t *key, dst_context_t *dctx) { + isc_hmacsha384_t *hmacsha384ctx; + HMACSHA384_Key *hkey = key->opaque; + + hmacsha384ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha384_t)); + if (hmacsha384ctx == NULL) + return (ISC_R_NOMEMORY); + isc_hmacsha384_init(hmacsha384ctx, hkey->key, ISC_SHA384_DIGESTLENGTH); + dctx->opaque = hmacsha384ctx; + return (ISC_R_SUCCESS); +} + +static void +hmacsha384_destroyctx(dst_context_t *dctx) { + isc_hmacsha384_t *hmacsha384ctx = dctx->opaque; + + if (hmacsha384ctx != NULL) { + isc_hmacsha384_invalidate(hmacsha384ctx); + isc_mem_put(dctx->mctx, hmacsha384ctx, sizeof(isc_hmacsha384_t)); + dctx->opaque = NULL; + } +} + +static isc_result_t +hmacsha384_adddata(dst_context_t *dctx, const isc_region_t *data) { + isc_hmacsha384_t *hmacsha384ctx = dctx->opaque; + + isc_hmacsha384_update(hmacsha384ctx, data->base, data->length); + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha384_sign(dst_context_t *dctx, isc_buffer_t *sig) { + isc_hmacsha384_t *hmacsha384ctx = dctx->opaque; + unsigned char *digest; + + if (isc_buffer_availablelength(sig) < ISC_SHA384_DIGESTLENGTH) + return (ISC_R_NOSPACE); + digest = isc_buffer_used(sig); + isc_hmacsha384_sign(hmacsha384ctx, digest, ISC_SHA384_DIGESTLENGTH); + isc_buffer_add(sig, ISC_SHA384_DIGESTLENGTH); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha384_verify(dst_context_t *dctx, const isc_region_t *sig) { + isc_hmacsha384_t *hmacsha384ctx = dctx->opaque; + + if (sig->length > ISC_SHA384_DIGESTLENGTH || sig->length == 0) + return (DST_R_VERIFYFAILURE); + + if (isc_hmacsha384_verify(hmacsha384ctx, sig->base, sig->length)) + return (ISC_R_SUCCESS); + else + return (DST_R_VERIFYFAILURE); +} + +static isc_boolean_t +hmacsha384_compare(const dst_key_t *key1, const dst_key_t *key2) { + HMACSHA384_Key *hkey1, *hkey2; + + hkey1 = (HMACSHA384_Key *)key1->opaque; + hkey2 = (HMACSHA384_Key *)key2->opaque; + + if (hkey1 == NULL && hkey2 == NULL) + return (ISC_TRUE); + else if (hkey1 == NULL || hkey2 == NULL) + return (ISC_FALSE); + + if (memcmp(hkey1->key, hkey2->key, ISC_SHA384_DIGESTLENGTH) == 0) + return (ISC_TRUE); + else + return (ISC_FALSE); +} + +static isc_result_t +hmacsha384_generate(dst_key_t *key, int pseudorandom_ok) { + isc_buffer_t b; + isc_result_t ret; + int bytes; + unsigned char data[HMAC_LEN]; + + bytes = (key->key_size + 7) / 8; + if (bytes > HMAC_LEN) { + bytes = HMAC_LEN; + key->key_size = HMAC_LEN * 8; + } + + memset(data, 0, HMAC_LEN); + ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); + + if (ret != ISC_R_SUCCESS) + return (ret); + + isc_buffer_init(&b, data, bytes); + isc_buffer_add(&b, bytes); + ret = hmacsha384_fromdns(key, &b); + memset(data, 0, ISC_SHA384_DIGESTLENGTH); + + return (ret); +} + +static isc_boolean_t +hmacsha384_isprivate(const dst_key_t *key) { + UNUSED(key); + return (ISC_TRUE); +} + +static void +hmacsha384_destroy(dst_key_t *key) { + HMACSHA384_Key *hkey = key->opaque; + memset(hkey, 0, sizeof(HMACSHA384_Key)); + isc_mem_put(key->mctx, hkey, sizeof(HMACSHA384_Key)); + key->opaque = NULL; +} + +static isc_result_t +hmacsha384_todns(const dst_key_t *key, isc_buffer_t *data) { + HMACSHA384_Key *hkey; + unsigned int bytes; + + REQUIRE(key->opaque != NULL); + + hkey = (HMACSHA384_Key *) key->opaque; + + bytes = (key->key_size + 7) / 8; + if (isc_buffer_availablelength(data) < bytes) + return (ISC_R_NOSPACE); + isc_buffer_putmem(data, hkey->key, bytes); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) { + HMACSHA384_Key *hkey; + int keylen; + isc_region_t r; + isc_sha384_t sha384ctx; + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); + + hkey = (HMACSHA384_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA384_Key)); + if (hkey == NULL) + return (ISC_R_NOMEMORY); + + memset(hkey->key, 0, sizeof(hkey->key)); + + if (r.length > ISC_SHA384_DIGESTLENGTH) { + isc_sha384_init(&sha384ctx); + isc_sha384_update(&sha384ctx, r.base, r.length); + isc_sha384_final(hkey->key, &sha384ctx); + keylen = ISC_SHA384_DIGESTLENGTH; + } + else { + memcpy(hkey->key, r.base, r.length); + keylen = r.length; + } + + key->key_size = keylen * 8; + key->opaque = hkey; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha384_tofile(const dst_key_t *key, const char *directory) { + int cnt = 0; + HMACSHA384_Key *hkey; + dst_private_t priv; + int bytes = (key->key_size + 7) / 8; + unsigned char buf[2]; + + if (key->opaque == NULL) + return (DST_R_NULLKEY); + + hkey = (HMACSHA384_Key *) key->opaque; + + priv.elements[cnt].tag = TAG_HMACSHA384_KEY; + priv.elements[cnt].length = bytes; + priv.elements[cnt++].data = hkey->key; + + buf[0] = (key->key_bits >> 8) & 0xffU; + buf[1] = key->key_bits & 0xffU; + priv.elements[cnt].tag = TAG_HMACSHA384_BITS; + priv.elements[cnt].data = buf; + priv.elements[cnt++].length = 2; + + priv.nelements = cnt; + return (dst__privstruct_writefile(key, &priv, directory)); +} + +static isc_result_t +hmacsha384_parse(dst_key_t *key, isc_lex_t *lexer) { + dst_private_t priv; + isc_result_t result, tresult; + isc_buffer_t b; + isc_mem_t *mctx = key->mctx; + unsigned int i; + + /* read private key file */ + result = dst__privstruct_parse(key, DST_ALG_HMACSHA384, lexer, mctx, + &priv); + if (result != ISC_R_SUCCESS) + return (result); + + key->key_bits = 0; + for (i = 0; i < priv.nelements; i++) { + switch (priv.elements[i].tag) { + case TAG_HMACSHA384_KEY: + isc_buffer_init(&b, priv.elements[i].data, + priv.elements[i].length); + isc_buffer_add(&b, priv.elements[i].length); + tresult = hmacsha384_fromdns(key, &b); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + case TAG_HMACSHA384_BITS: + tresult = getkeybits(key, &priv.elements[i]); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + default: + result = DST_R_INVALIDPRIVATEKEY; + break; + } + } + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (result); +} + +static dst_func_t hmacsha384_functions = { + hmacsha384_createctx, + hmacsha384_destroyctx, + hmacsha384_adddata, + hmacsha384_sign, + hmacsha384_verify, + NULL, /* computesecret */ + hmacsha384_compare, + NULL, /* paramcompare */ + hmacsha384_generate, + hmacsha384_isprivate, + hmacsha384_destroy, + hmacsha384_todns, + hmacsha384_fromdns, + hmacsha384_tofile, + hmacsha384_parse, + NULL, /* cleanup */ +}; + +isc_result_t +dst__hmacsha384_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + if (*funcp == NULL) + *funcp = &hmacsha384_functions; + return (ISC_R_SUCCESS); +} + +static isc_result_t hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data); + +typedef struct { + unsigned char key[ISC_SHA512_DIGESTLENGTH]; +} HMACSHA512_Key; + +static isc_result_t +hmacsha512_createctx(dst_key_t *key, dst_context_t *dctx) { + isc_hmacsha512_t *hmacsha512ctx; + HMACSHA512_Key *hkey = key->opaque; + + hmacsha512ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha512_t)); + if (hmacsha512ctx == NULL) + return (ISC_R_NOMEMORY); + isc_hmacsha512_init(hmacsha512ctx, hkey->key, ISC_SHA512_DIGESTLENGTH); + dctx->opaque = hmacsha512ctx; + return (ISC_R_SUCCESS); +} + +static void +hmacsha512_destroyctx(dst_context_t *dctx) { + isc_hmacsha512_t *hmacsha512ctx = dctx->opaque; + + if (hmacsha512ctx != NULL) { + isc_hmacsha512_invalidate(hmacsha512ctx); + isc_mem_put(dctx->mctx, hmacsha512ctx, sizeof(isc_hmacsha512_t)); + dctx->opaque = NULL; + } +} + +static isc_result_t +hmacsha512_adddata(dst_context_t *dctx, const isc_region_t *data) { + isc_hmacsha512_t *hmacsha512ctx = dctx->opaque; + + isc_hmacsha512_update(hmacsha512ctx, data->base, data->length); + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha512_sign(dst_context_t *dctx, isc_buffer_t *sig) { + isc_hmacsha512_t *hmacsha512ctx = dctx->opaque; + unsigned char *digest; + + if (isc_buffer_availablelength(sig) < ISC_SHA512_DIGESTLENGTH) + return (ISC_R_NOSPACE); + digest = isc_buffer_used(sig); + isc_hmacsha512_sign(hmacsha512ctx, digest, ISC_SHA512_DIGESTLENGTH); + isc_buffer_add(sig, ISC_SHA512_DIGESTLENGTH); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha512_verify(dst_context_t *dctx, const isc_region_t *sig) { + isc_hmacsha512_t *hmacsha512ctx = dctx->opaque; + + if (sig->length > ISC_SHA512_DIGESTLENGTH || sig->length == 0) + return (DST_R_VERIFYFAILURE); + + if (isc_hmacsha512_verify(hmacsha512ctx, sig->base, sig->length)) + return (ISC_R_SUCCESS); + else + return (DST_R_VERIFYFAILURE); +} + +static isc_boolean_t +hmacsha512_compare(const dst_key_t *key1, const dst_key_t *key2) { + HMACSHA512_Key *hkey1, *hkey2; + + hkey1 = (HMACSHA512_Key *)key1->opaque; + hkey2 = (HMACSHA512_Key *)key2->opaque; + + if (hkey1 == NULL && hkey2 == NULL) + return (ISC_TRUE); + else if (hkey1 == NULL || hkey2 == NULL) + return (ISC_FALSE); + + if (memcmp(hkey1->key, hkey2->key, ISC_SHA512_DIGESTLENGTH) == 0) + return (ISC_TRUE); + else + return (ISC_FALSE); +} + +static isc_result_t +hmacsha512_generate(dst_key_t *key, int pseudorandom_ok) { + isc_buffer_t b; + isc_result_t ret; + int bytes; + unsigned char data[HMAC_LEN]; + + bytes = (key->key_size + 7) / 8; + if (bytes > HMAC_LEN) { + bytes = HMAC_LEN; + key->key_size = HMAC_LEN * 8; + } + + memset(data, 0, HMAC_LEN); + ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); + + if (ret != ISC_R_SUCCESS) + return (ret); + + isc_buffer_init(&b, data, bytes); + isc_buffer_add(&b, bytes); + ret = hmacsha512_fromdns(key, &b); + memset(data, 0, ISC_SHA512_DIGESTLENGTH); + + return (ret); +} + +static isc_boolean_t +hmacsha512_isprivate(const dst_key_t *key) { + UNUSED(key); + return (ISC_TRUE); +} + +static void +hmacsha512_destroy(dst_key_t *key) { + HMACSHA512_Key *hkey = key->opaque; + memset(hkey, 0, sizeof(HMACSHA512_Key)); + isc_mem_put(key->mctx, hkey, sizeof(HMACSHA512_Key)); + key->opaque = NULL; +} + +static isc_result_t +hmacsha512_todns(const dst_key_t *key, isc_buffer_t *data) { + HMACSHA512_Key *hkey; + unsigned int bytes; + + REQUIRE(key->opaque != NULL); + + hkey = (HMACSHA512_Key *) key->opaque; + + bytes = (key->key_size + 7) / 8; + if (isc_buffer_availablelength(data) < bytes) + return (ISC_R_NOSPACE); + isc_buffer_putmem(data, hkey->key, bytes); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) { + HMACSHA512_Key *hkey; + int keylen; + isc_region_t r; + isc_sha512_t sha512ctx; + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); + + hkey = (HMACSHA512_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA512_Key)); + if (hkey == NULL) + return (ISC_R_NOMEMORY); + + memset(hkey->key, 0, sizeof(hkey->key)); + + if (r.length > ISC_SHA512_DIGESTLENGTH) { + isc_sha512_init(&sha512ctx); + isc_sha512_update(&sha512ctx, r.base, r.length); + isc_sha512_final(hkey->key, &sha512ctx); + keylen = ISC_SHA512_DIGESTLENGTH; + } + else { + memcpy(hkey->key, r.base, r.length); + keylen = r.length; + } + + key->key_size = keylen * 8; + key->opaque = hkey; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacsha512_tofile(const dst_key_t *key, const char *directory) { + int cnt = 0; + HMACSHA512_Key *hkey; + dst_private_t priv; + int bytes = (key->key_size + 7) / 8; + unsigned char buf[2]; + + if (key->opaque == NULL) + return (DST_R_NULLKEY); + + hkey = (HMACSHA512_Key *) key->opaque; + + priv.elements[cnt].tag = TAG_HMACSHA512_KEY; + priv.elements[cnt].length = bytes; + priv.elements[cnt++].data = hkey->key; + + buf[0] = (key->key_bits >> 8) & 0xffU; + buf[1] = key->key_bits & 0xffU; + priv.elements[cnt].tag = TAG_HMACSHA512_BITS; + priv.elements[cnt].data = buf; + priv.elements[cnt++].length = 2; + + priv.nelements = cnt; + return (dst__privstruct_writefile(key, &priv, directory)); +} + +static isc_result_t +hmacsha512_parse(dst_key_t *key, isc_lex_t *lexer) { + dst_private_t priv; + isc_result_t result, tresult; + isc_buffer_t b; + isc_mem_t *mctx = key->mctx; + unsigned int i; + + /* read private key file */ + result = dst__privstruct_parse(key, DST_ALG_HMACSHA512, lexer, mctx, + &priv); + if (result != ISC_R_SUCCESS) + return (result); + + key->key_bits = 0; + for (i = 0; i < priv.nelements; i++) { + switch (priv.elements[i].tag) { + case TAG_HMACSHA512_KEY: + isc_buffer_init(&b, priv.elements[i].data, + priv.elements[i].length); + isc_buffer_add(&b, priv.elements[i].length); + tresult = hmacsha512_fromdns(key, &b); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + case TAG_HMACSHA512_BITS: + tresult = getkeybits(key, &priv.elements[i]); + if (tresult != ISC_R_SUCCESS) + result = tresult; + break; + default: + result = DST_R_INVALIDPRIVATEKEY; + break; + } + } + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (result); +} + +static dst_func_t hmacsha512_functions = { + hmacsha512_createctx, + hmacsha512_destroyctx, + hmacsha512_adddata, + hmacsha512_sign, + hmacsha512_verify, + NULL, /* computesecret */ + hmacsha512_compare, + NULL, /* paramcompare */ + hmacsha512_generate, + hmacsha512_isprivate, + hmacsha512_destroy, + hmacsha512_todns, + hmacsha512_fromdns, + hmacsha512_tofile, + hmacsha512_parse, + NULL, /* cleanup */ +}; + +isc_result_t +dst__hmacsha512_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + if (*funcp == NULL) + *funcp = &hmacsha512_functions; + return (ISC_R_SUCCESS); +} + /*! \file */ diff --git a/lib/dns/include/dns/tsig.h b/lib/dns/include/dns/tsig.h index a70b2c8a2e..0d1a457690 100644 --- a/lib/dns/include/dns/tsig.h +++ b/lib/dns/include/dns/tsig.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tsig.h,v 1.45 2005/04/29 00:23:05 marka Exp $ */ +/* $Id: tsig.h,v 1.46 2006/01/27 02:35:15 marka Exp $ */ #ifndef DNS_TSIG_H #define DNS_TSIG_H 1 @@ -41,6 +41,16 @@ LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_gssapi_name; #define DNS_TSIG_GSSAPI_NAME dns_tsig_gssapi_name LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_gssapims_name; #define DNS_TSIG_GSSAPIMS_NAME dns_tsig_gssapims_name +LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha1_name; +#define DNS_TSIG_HMACSHA1_NAME dns_tsig_hmacsha1_name +LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha224_name; +#define DNS_TSIG_HMACSHA224_NAME dns_tsig_hmacsha224_name +LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha256_name; +#define DNS_TSIG_HMACSHA256_NAME dns_tsig_hmacsha256_name +LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha384_name; +#define DNS_TSIG_HMACSHA384_NAME dns_tsig_hmacsha384_name +LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha512_name; +#define DNS_TSIG_HMACSHA512_NAME dns_tsig_hmacsha512_name /*% * Default fudge value. diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 5763fe65cc..61ad026af5 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.117 2005/09/05 00:11:03 marka Exp $ */ +/* $Id: types.h,v 1.118 2006/01/27 02:35:15 marka Exp $ */ #ifndef DNS_TYPES_H #define DNS_TYPES_H 1 @@ -212,7 +212,8 @@ enum { dns_tsigerror_badtime = 18, dns_tsigerror_badmode = 19, dns_tsigerror_badname = 20, - dns_tsigerror_badalg = 21 + dns_tsigerror_badalg = 21, + dns_tsigerror_badtrunc = 22 }; /*% diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 0ba71c5609..ed124383ce 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst.h,v 1.3 2005/04/29 00:23:06 marka Exp $ */ +/* $Id: dst.h,v 1.4 2006/01/27 02:35:15 marka Exp $ */ #ifndef DST_DST_H #define DST_DST_H 1 @@ -51,6 +51,11 @@ typedef struct dst_context dst_context_t; #define DST_ALG_RSASHA1 5 #define DST_ALG_HMACMD5 157 #define DST_ALG_GSSAPI 160 +#define DST_ALG_HMACSHA1 161 /* XXXMPA */ +#define DST_ALG_HMACSHA224 162 /* XXXMPA */ +#define DST_ALG_HMACSHA256 163 /* XXXMPA */ +#define DST_ALG_HMACSHA384 164 /* XXXMPA */ +#define DST_ALG_HMACSHA512 165 /* XXXMPA */ #define DST_ALG_PRIVATE 254 #define DST_ALG_EXPAND 255 #define DST_MAX_ALGS 255 @@ -592,6 +597,24 @@ dst_region_computeid(const isc_region_t *source, unsigned int alg); *\li the key id */ +isc_uint16_t +dst_key_getbits(const dst_key_t *key); +/* + * Get the number of digest bits required (0 == MAX). + * + * Requires: + * "key" is a valid key. + */ + +void +dst_key_setbits(dst_key_t *key, isc_uint16_t bits); +/* + * Set the number of digest bits required (0 == MAX). + * + * Requires: + * "key" is a valid key. + */ + ISC_LANG_ENDDECLS #endif /* DST_DST_H */ diff --git a/lib/dns/key.c b/lib/dns/key.c index dd3f32a2bb..3bd73d1fa0 100644 --- a/lib/dns/key.c +++ b/lib/dns/key.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: key.c,v 1.4 2005/06/08 02:06:59 marka Exp $ */ +/* $Id: key.c,v 1.5 2006/01/27 02:35:15 marka Exp $ */ #include @@ -126,4 +126,22 @@ dst_key_isnullkey(const dst_key_t *key) { return (ISC_TRUE); } +void +dst_key_setbits(dst_key_t *key, isc_uint16_t bits) { + unsigned int maxbits; + REQUIRE(VALID_KEY(key)); + if (bits != 0) { + RUNTIME_CHECK(dst_key_sigsize(key, &maxbits) == ISC_R_SUCCESS); + maxbits *= 8; + REQUIRE(bits <= maxbits); + } + key->key_bits = bits; +} + +isc_uint16_t +dst_key_getbits(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + return (key->key_bits); +} + /*! \file */ diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c index 6bdb1d940c..a6e125e982 100644 --- a/lib/dns/rcode.c +++ b/lib/dns/rcode.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rcode.c,v 1.2 2004/03/16 05:52:18 marka Exp $ */ +/* $Id: rcode.c,v 1.3 2006/01/27 02:35:15 marka Exp $ */ #include #include @@ -76,6 +76,7 @@ { dns_tsigerror_badmode, "BADMODE", 0}, \ { dns_tsigerror_badname, "BADNAME", 0}, \ { dns_tsigerror_badalg, "BADALG", 0}, \ + { dns_tsigerror_badtrunc, "BADTRUNC", 0}, \ { 0, NULL, 0 } /* RFC2538 section 2.1 */ diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index e40deee66a..dd132fef0a 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -16,7 +16,7 @@ */ /* - * $Id: tsig.c,v 1.122 2005/11/30 03:33:49 marka Exp $ + * $Id: tsig.c,v 1.123 2006/01/27 02:35:15 marka Exp $ */ /*! \file */ #include @@ -48,6 +48,11 @@ #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR) #define algname_is_allocated(algname) \ ((algname) != dns_tsig_hmacmd5_name && \ + (algname) != dns_tsig_hmacsha1_name && \ + (algname) != dns_tsig_hmacsha224_name && \ + (algname) != dns_tsig_hmacsha256_name && \ + (algname) != dns_tsig_hmacsha384_name && \ + (algname) != dns_tsig_hmacsha512_name && \ (algname) != dns_tsig_gssapi_name && \ (algname) != dns_tsig_gssapims_name) @@ -96,6 +101,76 @@ static dns_name_t gsstsigms = { LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapims_name = &gsstsigms; +static unsigned char hmacsha1_ndata[] = "\011hmac-sha1"; +static unsigned char hmacsha1_offsets[] = { 0, 10 }; + +static dns_name_t hmacsha1 = { + DNS_NAME_MAGIC, + hmacsha1_ndata, 11, 2, + DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, + hmacsha1_offsets, NULL, + {(void *)-1, (void *)-1}, + {NULL, NULL} +}; + +LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha1_name = &hmacsha1; + +static unsigned char hmacsha224_ndata[] = "\013hmac-sha224"; +static unsigned char hmacsha224_offsets[] = { 0, 12 }; + +static dns_name_t hmacsha224 = { + DNS_NAME_MAGIC, + hmacsha224_ndata, 13, 2, + DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, + hmacsha224_offsets, NULL, + {(void *)-1, (void *)-1}, + {NULL, NULL} +}; + +LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha224_name = &hmacsha224; + +static unsigned char hmacsha256_ndata[] = "\013hmac-sha256"; +static unsigned char hmacsha256_offsets[] = { 0, 12 }; + +static dns_name_t hmacsha256 = { + DNS_NAME_MAGIC, + hmacsha256_ndata, 13, 2, + DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, + hmacsha256_offsets, NULL, + {(void *)-1, (void *)-1}, + {NULL, NULL} +}; + +LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha256_name = &hmacsha256; + +static unsigned char hmacsha384_ndata[] = "\013hmac-sha384"; +static unsigned char hmacsha384_offsets[] = { 0, 12 }; + +static dns_name_t hmacsha384 = { + DNS_NAME_MAGIC, + hmacsha384_ndata, 13, 2, + DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, + hmacsha384_offsets, NULL, + {(void *)-1, (void *)-1}, + {NULL, NULL} +}; + +LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha384_name = &hmacsha384; + +static unsigned char hmacsha512_ndata[] = "\013hmac-sha512"; +static unsigned char hmacsha512_offsets[] = { 0, 12 }; + +static dns_name_t hmacsha512 = { + DNS_NAME_MAGIC, + hmacsha512_ndata, 13, 2, + DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, + hmacsha512_offsets, NULL, + {(void *)-1, (void *)-1}, + {NULL, NULL} +}; + +LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha512_name = &hmacsha512; + static isc_result_t tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg); @@ -155,6 +230,40 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, ret = DNS_R_BADALG; goto cleanup_name; } + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) { + tkey->algorithm = DNS_TSIG_HMACSHA1_NAME; + if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA1) { + ret = DNS_R_BADALG; + goto cleanup_name; + } + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) { + tkey->algorithm = DNS_TSIG_HMACSHA224_NAME; + if (dstkey != NULL && + dst_key_alg(dstkey) != DST_ALG_HMACSHA224) { + ret = DNS_R_BADALG; + goto cleanup_name; + } + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) { + tkey->algorithm = DNS_TSIG_HMACSHA256_NAME; + if (dstkey != NULL && + dst_key_alg(dstkey) != DST_ALG_HMACSHA256) { + ret = DNS_R_BADALG; + goto cleanup_name; + } + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) { + tkey->algorithm = DNS_TSIG_HMACSHA384_NAME; + if (dstkey != NULL && + dst_key_alg(dstkey) != DST_ALG_HMACSHA384) { + ret = DNS_R_BADALG; + goto cleanup_name; + } + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) { + tkey->algorithm = DNS_TSIG_HMACSHA512_NAME; + if (dstkey != NULL && + dst_key_alg(dstkey) != DST_ALG_HMACSHA512) { + ret = DNS_R_BADALG; + goto cleanup_name; + } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPI_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { @@ -279,22 +388,93 @@ dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm, if (length > 0) REQUIRE(secret != NULL); - if (!dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME) && length > 0) + if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) { + if (secret != NULL) { + isc_buffer_t b; + + isc_buffer_init(&b, secret, length); + isc_buffer_add(&b, length); + result = dst_key_frombuffer(name, DST_ALG_HMACMD5, + DNS_KEYOWNER_ENTITY, + DNS_KEYPROTO_DNSSEC, + dns_rdataclass_in, + &b, mctx, &dstkey); + if (result != ISC_R_SUCCESS) + return (result); + } + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) { + if (secret != NULL) { + isc_buffer_t b; + + isc_buffer_init(&b, secret, length); + isc_buffer_add(&b, length); + result = dst_key_frombuffer(name, DST_ALG_HMACSHA1, + DNS_KEYOWNER_ENTITY, + DNS_KEYPROTO_DNSSEC, + dns_rdataclass_in, + &b, mctx, &dstkey); + if (result != ISC_R_SUCCESS) + return (result); + } + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) { + if (secret != NULL) { + isc_buffer_t b; + + isc_buffer_init(&b, secret, length); + isc_buffer_add(&b, length); + result = dst_key_frombuffer(name, DST_ALG_HMACSHA224, + DNS_KEYOWNER_ENTITY, + DNS_KEYPROTO_DNSSEC, + dns_rdataclass_in, + &b, mctx, &dstkey); + if (result != ISC_R_SUCCESS) + return (result); + } + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) { + if (secret != NULL) { + isc_buffer_t b; + + isc_buffer_init(&b, secret, length); + isc_buffer_add(&b, length); + result = dst_key_frombuffer(name, DST_ALG_HMACSHA256, + DNS_KEYOWNER_ENTITY, + DNS_KEYPROTO_DNSSEC, + dns_rdataclass_in, + &b, mctx, &dstkey); + if (result != ISC_R_SUCCESS) + return (result); + } + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) { + if (secret != NULL) { + isc_buffer_t b; + + isc_buffer_init(&b, secret, length); + isc_buffer_add(&b, length); + result = dst_key_frombuffer(name, DST_ALG_HMACSHA384, + DNS_KEYOWNER_ENTITY, + DNS_KEYPROTO_DNSSEC, + dns_rdataclass_in, + &b, mctx, &dstkey); + if (result != ISC_R_SUCCESS) + return (result); + } + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) { + if (secret != NULL) { + isc_buffer_t b; + + isc_buffer_init(&b, secret, length); + isc_buffer_add(&b, length); + result = dst_key_frombuffer(name, DST_ALG_HMACSHA512, + DNS_KEYOWNER_ENTITY, + DNS_KEYPROTO_DNSSEC, + dns_rdataclass_in, + &b, mctx, &dstkey); + if (result != ISC_R_SUCCESS) + return (result); + } + } else if (length > 0) return (DNS_R_BADALG); - if (secret != NULL) { - isc_buffer_t b; - - isc_buffer_init(&b, secret, length); - isc_buffer_add(&b, length); - result = dst_key_frombuffer(name, DST_ALG_HMACMD5, - DNS_KEYOWNER_ENTITY, - DNS_KEYPROTO_DNSSEC, - dns_rdataclass_in, - &b, mctx, &dstkey); - if (result != ISC_R_SUCCESS) - return (result); - } result = dns_tsigkey_createfromkey(name, algorithm, dstkey, generated, creator, inception, expire, mctx, ring, key); @@ -438,6 +618,7 @@ dns_tsig_sign(dns_message_t *msg) { if (key->key != NULL && tsig.error != dns_tsigerror_badsig) { unsigned char header[DNS_MESSAGE_HEADERLEN]; isc_buffer_t headerbuf; + isc_uint16_t digestbits; ret = dst_context_create(key->key, mctx, &ctx); if (ret != ISC_R_SUCCESS) @@ -564,7 +745,16 @@ dns_tsig_sign(dns_message_t *msg) { if (ret != ISC_R_SUCCESS) goto cleanup_signature; dst_context_destroy(&ctx); - tsig.siglen = isc_buffer_usedlength(&sigbuf); + digestbits = dst_key_getbits(key->key); + if (digestbits != 0) { + unsigned int bytes = (digestbits + 1) / 8; + if (is_response(msg) && bytes < querytsig.siglen) + bytes = querytsig.siglen; + if (bytes > isc_buffer_usedlength(&sigbuf)) + bytes = isc_buffer_usedlength(&sigbuf); + tsig.siglen = bytes; + } else + tsig.siglen = isc_buffer_usedlength(&sigbuf); } else { tsig.siglen = 0; tsig.signature = NULL; @@ -656,6 +846,8 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, dst_context_t *ctx = NULL; isc_mem_t *mctx; isc_uint16_t addcount, id; + unsigned int siglen; + unsigned int alg; REQUIRE(source != NULL); REQUIRE(DNS_MESSAGE_VALID(msg)); @@ -765,6 +957,42 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, return (DNS_R_CLOCKSKEW); } + /* + * Check digest length. + */ + alg = dst_key_alg(key); + ret = dst_key_sigsize(key, &siglen); + if (ret != ISC_R_SUCCESS) + return (ret); + if (alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 || + alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 || + alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) { + isc_uint16_t digestbits = dst_key_getbits(key); + if (tsig.siglen > siglen) { + tsig_log(msg->tsigkey, 2, "signature length to big"); + return (DNS_R_FORMERR); + } + if (tsig.siglen > 0 && + (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) { + tsig_log(msg->tsigkey, 2, + "signature length below minimum"); + return (DNS_R_FORMERR); + } + if (tsig.siglen > 0 && digestbits != 0 && + tsig.siglen < ((digestbits + 1) / 8)) { + msg->tsigstatus = dns_tsigerror_badtrunc; + tsig_log(msg->tsigkey, 2, + "truncated signature length too small"); + return (DNS_R_TSIGVERIFYFAILURE); + } + if (tsig.siglen > 0 && digestbits == 0 && + tsig.siglen < siglen) { + msg->tsigstatus = dns_tsigerror_badtrunc; + tsig_log(msg->tsigkey, 2, "signature length too small"); + return (DNS_R_TSIGVERIFYFAILURE); + } + } + if (tsig.siglen > 0) { sig_r.base = tsig.signature; sig_r.length = tsig.siglen; diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in index 761dc5f875..4c608ed78a 100644 --- a/lib/isc/Makefile.in +++ b/lib/isc/Makefile.in @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.85 2005/07/12 01:00:17 marka Exp $ +# $Id: Makefile.in,v 1.86 2006/01/27 02:35:15 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -53,25 +53,25 @@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \ OBJS = @ISC_EXTRA_OBJS@ \ assertions.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \ bufferlist.@O@ commandline.@O@ error.@O@ event.@O@ \ - hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ \ + hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@\ lex.@O@ lfsr.@O@ lib.@O@ log.@O@ md5.@O@ \ mem.@O@ mutexblock.@O@ netaddr.@O@ netscope.@O@ ondestroy.@O@ \ parseint.@O@ quota.@O@ random.@O@ \ ratelimiter.@O@ refcount.@O@ region.@O@ result.@O@ rwlock.@O@ \ - serial.@O@ sha1.@O@ sockaddr.@O@ string.@O@ strtoul.@O@ \ - symtab.@O@ task.@O@ taskpool.@O@ timer.@O@ version.@O@ \ - ${UNIXOBJS} ${NLSOBJS} ${THREADOBJS} + serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ string.@O@ \ + strtoul.@O@ symtab.@O@ task.@O@ taskpool.@O@ timer.@O@ \ + version.@O@ ${UNIXOBJS} ${NLSOBJS} ${THREADOBJS} # Alphabetically SRCS = @ISC_EXTRA_SRCS@ \ assertions.c base64.c bitstring.c buffer.c \ bufferlist.c commandline.c error.c event.c \ - heap.c hex.c hmacmd5.c \ + heap.c hex.c hmacmd5.c hmacsha.c \ lex.c lfsr.c lib.c log.c \ md5.c mem.c mutexblock.c netaddr.c netscope.c ondestroy.c \ parseint.c quota.c random.c \ ratelimiter.c refcount.c region.c result.c rwlock.c \ - serial.c sha1.c sockaddr.c string.c strtoul.c symtab.c \ + serial.c sha1.c sha2.c sockaddr.c string.c strtoul.c symtab.c \ task.c taskpool.c timer.c version.c LIBS = @LIBS@ diff --git a/lib/isc/hmacmd5.c b/lib/isc/hmacmd5.c index d7d891105c..db31b855ac 100644 --- a/lib/isc/hmacmd5.c +++ b/lib/isc/hmacmd5.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: hmacmd5.c,v 1.9 2005/04/29 00:23:25 marka Exp $ */ +/* $Id: hmacmd5.c,v 1.10 2006/01/27 02:35:15 marka Exp $ */ /*! \file * This code implements the HMAC-MD5 keyed hash algorithm @@ -106,8 +106,14 @@ isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) { */ isc_boolean_t isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest) { + return (isc_hmacmd5_verify2(ctx, digest, ISC_MD5_DIGESTLENGTH)); +} + +isc_boolean_t +isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len) { unsigned char newdigest[ISC_MD5_DIGESTLENGTH]; + REQUIRE(len <= ISC_MD5_DIGESTLENGTH); isc_hmacmd5_sign(ctx, newdigest); - return (ISC_TF(memcmp(digest, newdigest, ISC_MD5_DIGESTLENGTH) == 0)); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); } diff --git a/lib/isc/hmacsha.c b/lib/isc/hmacsha.c new file mode 100644 index 0000000000..b51c05a0d2 --- /dev/null +++ b/lib/isc/hmacsha.c @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: hmacsha.c,v 1.2 2006/01/27 02:35:15 marka Exp $ */ + +/* + * This code implements the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, HMAC-SHA384 + * and HMAC-SHA512 keyed hash algorithm described in RFC 2104 and + * draft-ietf-dnsext-tsig-sha-01.txt. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#define IPAD 0x36 +#define OPAD 0x5C + +/* + * Start HMAC-SHA1 process. Initialize an sha1 context and digest the key. + */ +void +isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[ISC_SHA1_DIGESTLENGTH]; + int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_sha1_t sha1ctx; + isc_sha1_init(&sha1ctx); + isc_sha1_update(&sha1ctx, key, len); + isc_sha1_final(&sha1ctx, ctx->key); + } else + memcpy(ctx->key, key, len); + + isc_sha1_init(&ctx->sha1ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < ISC_SHA1_DIGESTLENGTH; i++) + ipad[i] ^= ctx->key[i]; + isc_sha1_update(&ctx->sha1ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) { + isc_sha1_invalidate(&ctx->sha1ctx); + memset(ctx->key, 0, sizeof(ctx->key)); + memset(ctx, 0, sizeof(ctx)); +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_sha1_update(&ctx->sha1ctx, buf, len); +} + +/* + * Compute signature - finalize SHA1 operation and reapply SHA1. + */ +void +isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) { + unsigned char opad[ISC_SHA1_DIGESTLENGTH]; + unsigned char newdigest[ISC_SHA1_DIGESTLENGTH]; + int i; + + REQUIRE(len <= ISC_SHA1_DIGESTLENGTH); + isc_sha1_final(&ctx->sha1ctx, newdigest); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < ISC_SHA1_DIGESTLENGTH; i++) + opad[i] ^= ctx->key[i]; + + isc_sha1_init(&ctx->sha1ctx); + isc_sha1_update(&ctx->sha1ctx, opad, sizeof(opad)); + isc_sha1_update(&ctx->sha1ctx, newdigest, ISC_SHA1_DIGESTLENGTH); + isc_sha1_final(&ctx->sha1ctx, newdigest); + isc_hmacsha1_invalidate(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, len); +} + +/* + * Verify signature - finalize SHA1 operation and reapply SHA1, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA1_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA1_DIGESTLENGTH); + isc_hmacsha1_sign(ctx, newdigest, ISC_SHA1_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Start HMAC-SHA224 process. Initialize an sha224 context and digest the key. + */ +void +isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[ISC_SHA224_DIGESTLENGTH]; + int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_sha224_t sha224ctx; + isc_sha224_init(&sha224ctx); + isc_sha224_update(&sha224ctx, key, len); + isc_sha224_final(ctx->key, &sha224ctx); + } else + memcpy(ctx->key, key, len); + + isc_sha224_init(&ctx->sha224ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < ISC_SHA224_DIGESTLENGTH; i++) + ipad[i] ^= ctx->key[i]; + isc_sha224_update(&ctx->sha224ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) { + memset(ctx->key, 0, sizeof(ctx->key)); + memset(ctx, 0, sizeof(ctx)); +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_sha224_update(&ctx->sha224ctx, buf, len); +} + +/* + * Compute signature - finalize SHA224 operation and reapply SHA224. + */ +void +isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) { + unsigned char opad[ISC_SHA224_DIGESTLENGTH]; + unsigned char newdigest[ISC_SHA224_DIGESTLENGTH]; + int i; + + REQUIRE(len <= ISC_SHA224_DIGESTLENGTH); + isc_sha224_final(newdigest, &ctx->sha224ctx); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < ISC_SHA224_DIGESTLENGTH; i++) + opad[i] ^= ctx->key[i]; + + isc_sha224_init(&ctx->sha224ctx); + isc_sha224_update(&ctx->sha224ctx, opad, sizeof(opad)); + isc_sha224_update(&ctx->sha224ctx, newdigest, ISC_SHA224_DIGESTLENGTH); + isc_sha224_final(newdigest, &ctx->sha224ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, len); +} + +/* + * Verify signature - finalize SHA224 operation and reapply SHA224, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA224_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA224_DIGESTLENGTH); + isc_hmacsha224_sign(ctx, newdigest, ISC_SHA224_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Start HMAC-SHA256 process. Initialize an sha256 context and digest the key. + */ +void +isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[ISC_SHA256_DIGESTLENGTH]; + int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_sha256_t sha256ctx; + isc_sha256_init(&sha256ctx); + isc_sha256_update(&sha256ctx, key, len); + isc_sha256_final(ctx->key, &sha256ctx); + } else + memcpy(ctx->key, key, len); + + isc_sha256_init(&ctx->sha256ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < ISC_SHA256_DIGESTLENGTH; i++) + ipad[i] ^= ctx->key[i]; + isc_sha256_update(&ctx->sha256ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) { + memset(ctx->key, 0, sizeof(ctx->key)); + memset(ctx, 0, sizeof(ctx)); +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_sha256_update(&ctx->sha256ctx, buf, len); +} + +/* + * Compute signature - finalize SHA256 operation and reapply SHA256. + */ +void +isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) { + unsigned char opad[ISC_SHA256_DIGESTLENGTH]; + unsigned char newdigest[ISC_SHA256_DIGESTLENGTH]; + int i; + + REQUIRE(len <= ISC_SHA256_DIGESTLENGTH); + isc_sha256_final(newdigest, &ctx->sha256ctx); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < ISC_SHA256_DIGESTLENGTH; i++) + opad[i] ^= ctx->key[i]; + + isc_sha256_init(&ctx->sha256ctx); + isc_sha256_update(&ctx->sha256ctx, opad, sizeof(opad)); + isc_sha256_update(&ctx->sha256ctx, newdigest, ISC_SHA256_DIGESTLENGTH); + isc_sha256_final(newdigest, &ctx->sha256ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, len); +} + +/* + * Verify signature - finalize SHA256 operation and reapply SHA256, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA256_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA256_DIGESTLENGTH); + isc_hmacsha256_sign(ctx, newdigest, ISC_SHA256_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Start HMAC-SHA384 process. Initialize an sha384 context and digest the key. + */ +void +isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[ISC_SHA384_DIGESTLENGTH]; + int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_sha384_t sha384ctx; + isc_sha384_init(&sha384ctx); + isc_sha384_update(&sha384ctx, key, len); + isc_sha384_final(ctx->key, &sha384ctx); + } else + memcpy(ctx->key, key, len); + + isc_sha384_init(&ctx->sha384ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < ISC_SHA384_DIGESTLENGTH; i++) + ipad[i] ^= ctx->key[i]; + isc_sha384_update(&ctx->sha384ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) { + memset(ctx->key, 0, sizeof(ctx->key)); + memset(ctx, 0, sizeof(ctx)); +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_sha384_update(&ctx->sha384ctx, buf, len); +} + +/* + * Compute signature - finalize SHA384 operation and reapply SHA384. + */ +void +isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) { + unsigned char opad[ISC_SHA384_DIGESTLENGTH]; + unsigned char newdigest[ISC_SHA384_DIGESTLENGTH]; + int i; + + REQUIRE(len <= ISC_SHA384_DIGESTLENGTH); + isc_sha384_final(newdigest, &ctx->sha384ctx); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < ISC_SHA384_DIGESTLENGTH; i++) + opad[i] ^= ctx->key[i]; + + isc_sha384_init(&ctx->sha384ctx); + isc_sha384_update(&ctx->sha384ctx, opad, sizeof(opad)); + isc_sha384_update(&ctx->sha384ctx, newdigest, ISC_SHA384_DIGESTLENGTH); + isc_sha384_final(newdigest, &ctx->sha384ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, len); +} + +/* + * Verify signature - finalize SHA384 operation and reapply SHA384, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA384_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA384_DIGESTLENGTH); + isc_hmacsha384_sign(ctx, newdigest, ISC_SHA384_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Start HMAC-SHA512 process. Initialize an sha512 context and digest the key. + */ +void +isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[ISC_SHA512_DIGESTLENGTH]; + int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_sha512_t sha512ctx; + isc_sha512_init(&sha512ctx); + isc_sha512_update(&sha512ctx, key, len); + isc_sha512_final(ctx->key, &sha512ctx); + } else + memcpy(ctx->key, key, len); + + isc_sha512_init(&ctx->sha512ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < ISC_SHA512_DIGESTLENGTH; i++) + ipad[i] ^= ctx->key[i]; + isc_sha512_update(&ctx->sha512ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) { + memset(ctx->key, 0, sizeof(ctx->key)); + memset(ctx, 0, sizeof(ctx)); +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_sha512_update(&ctx->sha512ctx, buf, len); +} + +/* + * Compute signature - finalize SHA512 operation and reapply SHA512. + */ +void +isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) { + unsigned char opad[ISC_SHA512_DIGESTLENGTH]; + unsigned char newdigest[ISC_SHA512_DIGESTLENGTH]; + int i; + + REQUIRE(len <= ISC_SHA512_DIGESTLENGTH); + isc_sha512_final(newdigest, &ctx->sha512ctx); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < ISC_SHA512_DIGESTLENGTH; i++) + opad[i] ^= ctx->key[i]; + + isc_sha512_init(&ctx->sha512ctx); + isc_sha512_update(&ctx->sha512ctx, opad, sizeof(opad)); + isc_sha512_update(&ctx->sha512ctx, newdigest, ISC_SHA512_DIGESTLENGTH); + isc_sha512_final(newdigest, &ctx->sha512ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, len); +} + +/* + * Verify signature - finalize SHA512 operation and reapply SHA512, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha512_verify(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA512_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA512_DIGESTLENGTH); + isc_hmacsha512_sign(ctx, newdigest, ISC_SHA512_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} diff --git a/lib/isc/include/isc/Makefile.in b/lib/isc/include/isc/Makefile.in index 2ea0fd4c40..e497fbf411 100644 --- a/lib/isc/include/isc/Makefile.in +++ b/lib/isc/include/isc/Makefile.in @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.56 2005/03/22 02:35:14 marka Exp $ +# $Id: Makefile.in,v 1.57 2006/01/27 02:35:15 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -35,9 +35,9 @@ HEADERS = app.h assertions.h base64.h bitstring.h boolean.h buffer.h \ mutexblock.h netaddr.h ondestroy.h os.h parseint.h \ print.h quota.h random.h ratelimiter.h \ refcount.h region.h resource.h \ - result.h resultclass.h rwlock.h serial.h sha1.h sockaddr.h \ - socket.h stdio.h stdlib.h string.h symtab.h task.h taskpool.h \ - timer.h types.h util.h version.h + result.h resultclass.h rwlock.h serial.h sha1.h sha2.h \ + sockaddr.h socket.h stdio.h stdlib.h string.h symtab.h \ + task.h taskpool.h timer.h types.h util.h version.h SUBDIRS = TARGETS = diff --git a/lib/isc/include/isc/hmacmd5.h b/lib/isc/include/isc/hmacmd5.h index 3c2d5ee342..6f4b604b8a 100644 --- a/lib/isc/include/isc/hmacmd5.h +++ b/lib/isc/include/isc/hmacmd5.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: hmacmd5.h,v 1.7 2005/04/29 00:23:37 marka Exp $ */ +/* $Id: hmacmd5.h,v 1.8 2006/01/27 02:35:15 marka Exp $ */ /*! \file * \brief This is the header file for the HMAC-MD5 keyed hash algorithm @@ -55,6 +55,9 @@ isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest); isc_boolean_t isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest); +isc_boolean_t +isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len); + ISC_LANG_ENDDECLS #endif /* ISC_HMACMD5_H */ diff --git a/lib/isc/include/isc/hmacsha.h b/lib/isc/include/isc/hmacsha.h new file mode 100644 index 0000000000..7518fb71da --- /dev/null +++ b/lib/isc/include/isc/hmacsha.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: hmacsha.h,v 1.2 2006/01/27 02:35:15 marka Exp $ */ + +/* + * This is the header file for the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, + * HMAC-SHA334 and HMAC-SHA512 hash algorithm described in RFC 2104. + */ + +#ifndef ISC_HMACSHA_H +#define ISC_HMACSHA_H 1 + +#include +#include +#include +#include + +#define ISC_HMACSHA1_KEYLENGTH ISC_SHA1_DIGESTLENGTH +#define ISC_HMACSHA224_KEYLENGTH ISC_SHA224_DIGESTLENGTH +#define ISC_HMACSHA256_KEYLENGTH ISC_SHA256_DIGESTLENGTH +#define ISC_HMACSHA384_KEYLENGTH ISC_SHA384_DIGESTLENGTH +#define ISC_HMACSHA512_KEYLENGTH ISC_SHA512_DIGESTLENGTH + +typedef struct { + isc_sha1_t sha1ctx; + unsigned char key[ISC_HMACSHA1_KEYLENGTH]; +} isc_hmacsha1_t; + +typedef struct { + isc_sha224_t sha224ctx; + unsigned char key[ISC_HMACSHA224_KEYLENGTH]; +} isc_hmacsha224_t; + +typedef struct { + isc_sha256_t sha256ctx; + unsigned char key[ISC_HMACSHA256_KEYLENGTH]; +} isc_hmacsha256_t; + +typedef struct { + isc_sha384_t sha384ctx; + unsigned char key[ISC_HMACSHA384_KEYLENGTH]; +} isc_hmacsha384_t; + +typedef struct { + isc_sha512_t sha512ctx; + unsigned char key[ISC_HMACSHA512_KEYLENGTH]; +} isc_hmacsha512_t; + +ISC_LANG_BEGINDECLS + +void +isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx); + +void +isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len); + +isc_boolean_t +isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len); + + +void +isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx); + +void +isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len); + +isc_boolean_t +isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len); + + +void +isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx); + +void +isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len); + +isc_boolean_t +isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len); + + +void +isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx); + +void +isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len); + +isc_boolean_t +isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len); + + +void +isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx); + +void +isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len); + +isc_boolean_t +isc_hmacsha512_verify(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len); + +ISC_LANG_ENDDECLS + +#endif /* ISC_HMACSHA_H */ diff --git a/lib/isc/include/isc/sha2.h b/lib/isc/include/isc/sha2.h new file mode 100644 index 0000000000..c93e0582b9 --- /dev/null +++ b/lib/isc/include/isc/sha2.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: sha2.h,v 1.2 2006/01/27 02:35:15 marka Exp $ */ + +/* $FreeBSD: src/sys/crypto/sha2/sha2.h,v 1.1.2.1 2001/07/03 11:01:36 ume Exp $ */ +/* $KAME: sha2.h,v 1.3 2001/03/12 08:27:48 itojun Exp $ */ + +/* + * sha2.h + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford + * + * Copyright 2000 Aaron D. Gifford. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISC_SHA2_H +#define ISC_SHA2_H + +#include +#include + +/*** SHA-224/256/384/512 Various Length Definitions ***********************/ + +#define ISC_SHA224_DIGESTLENGTH 28 +#define ISC_SHA224_DIGESTSTRINGLENGTH (ISC_SHA224_DIGESTLENGTH * 2 + 1) +#define ISC_SHA256_BLOCK_LENGTH 64 +#define ISC_SHA256_DIGESTLENGTH 32 +#define ISC_SHA256_DIGESTSTRINGLENGTH (ISC_SHA256_DIGESTLENGTH * 2 + 1) +#define ISC_SHA384_BLOCK_LENGTH 128 +#define ISC_SHA384_DIGESTLENGTH 48 +#define ISC_SHA384_DIGESTSTRINGLENGTH (ISC_SHA384_DIGESTLENGTH * 2 + 1) +#define ISC_SHA512_BLOCK_LENGTH 128 +#define ISC_SHA512_DIGESTLENGTH 64 +#define ISC_SHA512_DIGESTSTRINGLENGTH (ISC_SHA512_DIGESTLENGTH * 2 + 1) + + +ISC_LANG_BEGINDECLS + +/*** SHA-256/384/512 Context Structures *******************************/ + +typedef struct { + isc_uint32_t state[8]; + isc_uint64_t bitcount; + isc_uint8_t buffer[ISC_SHA256_BLOCK_LENGTH]; +} isc_sha256_t; + +typedef struct { + isc_uint64_t state[8]; + isc_uint64_t bitcount[2]; + isc_uint8_t buffer[ISC_SHA512_BLOCK_LENGTH]; +} isc_sha512_t; + +typedef isc_sha256_t isc_sha224_t; +typedef isc_sha512_t isc_sha384_t; + +/*** SHA-224/256/384/512 Function Prototypes ******************************/ + +void isc_sha224_init (isc_sha224_t *); +void isc_sha224_update (isc_sha224_t *, const isc_uint8_t *, size_t); +void isc_sha224_final (isc_uint8_t[ISC_SHA224_DIGESTLENGTH], isc_sha224_t *); +char *isc_sha224_end (isc_sha224_t *, char[ISC_SHA224_DIGESTSTRINGLENGTH]); +char *isc_sha224_data (const isc_uint8_t *, size_t, char[ISC_SHA224_DIGESTSTRINGLENGTH]); + +void isc_sha256_init (isc_sha256_t *); +void isc_sha256_update (isc_sha256_t *, const isc_uint8_t *, size_t); +void isc_sha256_final (isc_uint8_t[ISC_SHA256_DIGESTLENGTH], isc_sha256_t *); +char *isc_sha256_end (isc_sha256_t *, char[ISC_SHA256_DIGESTSTRINGLENGTH]); +char *isc_sha256_data (const isc_uint8_t *, size_t, char[ISC_SHA256_DIGESTSTRINGLENGTH]); + +void isc_sha384_init (isc_sha384_t *); +void isc_sha384_update (isc_sha384_t *, const isc_uint8_t *, size_t); +void isc_sha384_final (isc_uint8_t[ISC_SHA384_DIGESTLENGTH], isc_sha384_t *); +char *isc_sha384_end (isc_sha384_t *, char[ISC_SHA384_DIGESTSTRINGLENGTH]); +char *isc_sha384_data (const isc_uint8_t *, size_t, char[ISC_SHA384_DIGESTSTRINGLENGTH]); + +void isc_sha512_init (isc_sha512_t *); +void isc_sha512_update (isc_sha512_t *, const isc_uint8_t *, size_t); +void isc_sha512_final (isc_uint8_t[ISC_SHA512_DIGESTLENGTH], isc_sha512_t *); +char *isc_sha512_end (isc_sha512_t *, char[ISC_SHA512_DIGESTSTRINGLENGTH]); +char *isc_sha512_data (const isc_uint8_t *, size_t, char[ISC_SHA512_DIGESTSTRINGLENGTH]); + +ISC_LANG_ENDDECLS + +#endif /* ISC_SHA2_H */ diff --git a/lib/isc/sha2.c b/lib/isc/sha2.c new file mode 100644 index 0000000000..3dea6d223f --- /dev/null +++ b/lib/isc/sha2.c @@ -0,0 +1,1119 @@ +/* + * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: sha2.c,v 1.2 2006/01/27 02:35:15 marka Exp $ */ + +/* $FreeBSD: src/sys/crypto/sha2/sha2.c,v 1.2.2.2 2002/03/05 08:36:47 ume Exp $ */ +/* $KAME: sha2.c,v 1.8 2001/11/08 01:07:52 itojun Exp $ */ + +/* + * sha2.c + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford + * + * Copyright 2000 Aaron D. Gifford. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + +#include + +#include +#include +#include +#include + +/* + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DISC_SHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define ISC_SHA2_UNROLL_TRANSFORM + * + */ + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define ISC_SHA256_SHORT_BLOCK_LENGTH (ISC_SHA256_BLOCK_LENGTH - 8) +#define ISC_SHA384_SHORT_BLOCK_LENGTH (ISC_SHA384_BLOCK_LENGTH - 16) +#define ISC_SHA512_SHORT_BLOCK_LENGTH (ISC_SHA512_BLOCK_LENGTH - 16) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + isc_uint32_t tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + isc_uint64_t tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (isc_uint64_t)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +void isc_sha512_last(isc_sha512_t *); +void isc_sha256_transform(isc_sha256_t *, const isc_uint32_t*); +void isc_sha512_transform(isc_sha512_t *, const isc_uint64_t*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-224 and SHA-256: */ +static const isc_uint32_t K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-224: */ +static const isc_uint32_t sha224_initial_hash_value[8] = { + 0xc1059ed8UL, + 0x367cd507UL, + 0x3070dd17UL, + 0xf70e5939UL, + 0xffc00b31UL, + 0x68581511UL, + 0x64f98fa7UL, + 0xbefa4fa4UL +}; + +/* Initial hash value H for SHA-256: */ +static const isc_uint32_t sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +static const isc_uint64_t K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* Initial hash value H for SHA-384: */ +static const isc_uint64_t sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512: */ +static const isc_uint64_t sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + + +/*** SHA-224: *********************************************************/ +void +isc_sha224_init(isc_sha224_t *context) { + if (context == (isc_sha256_t *)0) { + return; + } + memcpy(context->state, sha224_initial_hash_value, ISC_SHA256_DIGESTLENGTH); + memset(context->buffer, 0, ISC_SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +void +isc_sha224_update(isc_sha224_t *context, const isc_uint8_t* data, size_t len) { + isc_sha256_update((isc_sha256_t *)context, data, len); +} + +void +isc_sha224_final(isc_uint8_t digest[], isc_sha256_t *context) { + isc_uint8_t sha256_digest[ISC_SHA256_DIGESTLENGTH]; + isc_sha256_final(sha256_digest, (isc_sha256_t *)context); + memcpy(digest, sha256_digest, ISC_SHA224_DIGESTLENGTH); + memset(sha256_digest, 0, ISC_SHA256_DIGESTLENGTH); +} + +char * +isc_sha224_end(isc_sha224_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA224_DIGESTLENGTH], *d = digest; + int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha224_t *)0); + + if (buffer != (char*)0) { + isc_sha224_final(digest, context); + + for (i = 0; i < ISC_SHA224_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memset(context, 0, sizeof(context)); + } + memset(digest, 0, ISC_SHA224_DIGESTLENGTH); + return buffer; +} + +char* +isc_sha224_data(const isc_uint8_t *data, size_t len, + char digest[ISC_SHA224_DIGESTSTRINGLENGTH]) +{ + isc_sha224_t context; + + isc_sha224_init(&context); + isc_sha224_update(&context, data, len); + return (isc_sha224_end(&context, digest)); +} + +/*** SHA-256: *********************************************************/ +void +isc_sha256_init(isc_sha256_t *context) { + if (context == (isc_sha256_t *)0) { + return; + } + memcpy(context->state, sha256_initial_hash_value, ISC_SHA256_DIGESTLENGTH); + memset(context->buffer, 0, ISC_SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef ISC_SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void isc_sha256_transform(isc_sha256_t *context, const isc_uint32_t* data) { + isc_uint32_t a, b, c, d, e, f, g, h, s0, s1; + isc_uint32_t T1, *W256; + int j; + + W256 = (isc_uint32_t*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* ISC_SHA2_UNROLL_TRANSFORM */ + +void +isc_sha256_transform(isc_sha256_t *context, const isc_uint32_t* data) { + isc_uint32_t a, b, c, d, e, f, g, h, s0, s1; + isc_uint32_t T1, T2, *W256; + int j; + + W256 = (isc_uint32_t*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* ISC_SHA2_UNROLL_TRANSFORM */ + +void +isc_sha256_update(isc_sha256_t *context, const isc_uint8_t *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0 && data != (isc_uint8_t*)0); + + usedspace = (context->bitcount >> 3) % ISC_SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = ISC_SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + memcpy(&context->buffer[usedspace], data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + isc_sha256_transform(context, (isc_uint32_t*)context->buffer); + } else { + /* The buffer is not yet full */ + memcpy(&context->buffer[usedspace], data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= ISC_SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + isc_sha256_transform(context, (const isc_uint32_t*)data); + context->bitcount += ISC_SHA256_BLOCK_LENGTH << 3; + len -= ISC_SHA256_BLOCK_LENGTH; + data += ISC_SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + memcpy(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void +isc_sha256_final(isc_uint8_t digest[], isc_sha256_t *context) { + isc_uint32_t *d = (isc_uint32_t*)digest; + unsigned int usedspace; + + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + usedspace = (context->bitcount >> 3) % ISC_SHA256_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= ISC_SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + memset(&context->buffer[usedspace], 0, ISC_SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < ISC_SHA256_BLOCK_LENGTH) { + memset(&context->buffer[usedspace], 0, ISC_SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + isc_sha256_transform(context, (isc_uint32_t*)context->buffer); + + /* And set-up for the last transform: */ + memset(context->buffer, 0, ISC_SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + memset(context->buffer, 0, ISC_SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + *(isc_uint64_t*)&context->buffer[ISC_SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; + + /* Final transform: */ + isc_sha256_transform(context, (isc_uint32_t*)context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + memcpy(d, context->state, ISC_SHA256_DIGESTLENGTH); +#endif + } + + /* Clean up state data: */ + memset(context, 0, sizeof(context)); + usedspace = 0; +} + +char * +isc_sha256_end(isc_sha256_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA256_DIGESTLENGTH], *d = digest; + int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0); + + if (buffer != (char*)0) { + isc_sha256_final(digest, context); + + for (i = 0; i < ISC_SHA256_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memset(context, 0, sizeof(context)); + } + memset(digest, 0, ISC_SHA256_DIGESTLENGTH); + return buffer; +} + +char * +isc_sha256_data(const isc_uint8_t* data, size_t len, + char digest[ISC_SHA256_DIGESTSTRINGLENGTH]) +{ + isc_sha256_t context; + + isc_sha256_init(&context); + isc_sha256_update(&context, data, len); + return (isc_sha256_end(&context, digest)); +} + + +/*** SHA-512: *********************************************************/ +void +isc_sha512_init(isc_sha512_t *context) { + if (context == (isc_sha512_t *)0) { + return; + } + memcpy(context->state, sha512_initial_hash_value, ISC_SHA512_DIGESTLENGTH); + memset(context->buffer, 0, ISC_SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef ISC_SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + W512[j]; \ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void isc_sha512_transform(isc_sha512_t *context, const isc_uint64_t* data) { + isc_uint64_t a, b, c, d, e, f, g, h, s0, s1; + isc_uint64_t T1, *W512 = (isc_uint64_t*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* ISC_SHA2_UNROLL_TRANSFORM */ + +void +isc_sha512_transform(isc_sha512_t *context, const isc_uint64_t* data) { + isc_uint64_t a, b, c, d, e, f, g, h, s0, s1; + isc_uint64_t T1, T2, *W512 = (isc_uint64_t*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* ISC_SHA2_UNROLL_TRANSFORM */ + +void isc_sha512_update(isc_sha512_t *context, const isc_uint8_t *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0 && data != (isc_uint8_t*)0); + + usedspace = (context->bitcount[0] >> 3) % ISC_SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = ISC_SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + memcpy(&context->buffer[usedspace], data, freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + isc_sha512_transform(context, (isc_uint64_t*)context->buffer); + } else { + /* The buffer is not yet full */ + memcpy(&context->buffer[usedspace], data, len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= ISC_SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + isc_sha512_transform(context, (const isc_uint64_t*)data); + ADDINC128(context->bitcount, ISC_SHA512_BLOCK_LENGTH << 3); + len -= ISC_SHA512_BLOCK_LENGTH; + data += ISC_SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + memcpy(context->buffer, data, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void isc_sha512_last(isc_sha512_t *context) { + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % ISC_SHA512_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= ISC_SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + memset(&context->buffer[usedspace], 0, ISC_SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < ISC_SHA512_BLOCK_LENGTH) { + memset(&context->buffer[usedspace], 0, ISC_SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + isc_sha512_transform(context, (isc_uint64_t*)context->buffer); + + /* And set-up for the last transform: */ + memset(context->buffer, 0, ISC_SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + memset(context->buffer, 0, ISC_SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + *(isc_uint64_t*)&context->buffer[ISC_SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; + *(isc_uint64_t*)&context->buffer[ISC_SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + + /* Final transform: */ + isc_sha512_transform(context, (isc_uint64_t*)context->buffer); +} + +void isc_sha512_final(isc_uint8_t digest[], isc_sha512_t *context) { + isc_uint64_t *d = (isc_uint64_t*)digest; + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + isc_sha512_last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + memcpy(d, context->state, ISC_SHA512_DIGESTLENGTH); +#endif + } + + /* Zero out state data */ + memset(context, 0, sizeof(context)); +} + +char * +isc_sha512_end(isc_sha512_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA512_DIGESTLENGTH], *d = digest; + int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0); + + if (buffer != (char*)0) { + isc_sha512_final(digest, context); + + for (i = 0; i < ISC_SHA512_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memset(context, 0, sizeof(context)); + } + memset(digest, 0, ISC_SHA512_DIGESTLENGTH); + return buffer; +} + +char * +isc_sha512_data(const isc_uint8_t *data, size_t len, + char digest[ISC_SHA512_DIGESTSTRINGLENGTH]) +{ + isc_sha512_t context; + + isc_sha512_init(&context); + isc_sha512_update(&context, data, len); + return (isc_sha512_end(&context, digest)); +} + + +/*** SHA-384: *********************************************************/ +void +isc_sha384_init(isc_sha384_t *context) { + if (context == (isc_sha384_t *)0) { + return; + } + memcpy(context->state, sha384_initial_hash_value, ISC_SHA512_DIGESTLENGTH); + memset(context->buffer, 0, ISC_SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void +isc_sha384_update(isc_sha384_t *context, const isc_uint8_t* data, size_t len) { + isc_sha512_update((isc_sha512_t *)context, data, len); +} + +void +isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) { + isc_uint64_t *d = (isc_uint64_t*)digest; + + /* Sanity check: */ + REQUIRE(context != (isc_sha384_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + isc_sha512_last((isc_sha512_t *)context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + memcpy(d, context->state, ISC_SHA384_DIGESTLENGTH); +#endif + } + + /* Zero out state data */ + memset(context, 0, sizeof(context)); +} + +char * +isc_sha384_end(isc_sha384_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA384_DIGESTLENGTH], *d = digest; + int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha384_t *)0); + + if (buffer != (char*)0) { + isc_sha384_final(digest, context); + + for (i = 0; i < ISC_SHA384_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memset(context, 0, sizeof(context)); + } + memset(digest, 0, ISC_SHA384_DIGESTLENGTH); + return buffer; +} + +char* +isc_sha384_data(const isc_uint8_t *data, size_t len, + char digest[ISC_SHA384_DIGESTSTRINGLENGTH]) +{ + isc_sha384_t context; + + isc_sha384_init(&context); + isc_sha384_update(&context, data, len); + return (isc_sha384_end(&context, digest)); +} diff --git a/util/copyrights b/util/copyrights index f16cf3d194..878f053efe 100644 --- a/util/copyrights +++ b/util/copyrights @@ -32,7 +32,7 @@ ./bin/dig/Makefile.in MAKE 2000,2001,2002,2004,2005 ./bin/dig/dig.1 MAN DOCBOOK ./bin/dig/dig.c C 2000,2001,2002,2003,2004,2005,2006 -./bin/dig/dig.docbook SGML 2000,2001,2002,2003,2004,2005 +./bin/dig/dig.docbook SGML 2000,2001,2002,2003,2004,2005,2006 ./bin/dig/dig.html HTML DOCBOOK ./bin/dig/dighost.c C 2000,2001,2002,2003,2004,2005,2006 ./bin/dig/host.1 MAN DOCBOOK @@ -694,6 +694,10 @@ ./bin/tests/system/tkey/prereq.sh SH 2001,2004,2006 ./bin/tests/system/tkey/setup.sh SH 2001,2004 ./bin/tests/system/tkey/tests.sh SH 2001,2004 +./bin/tests/system/tsig/clean.sh SH 2005,2006 +./bin/tests/system/tsig/tests.sh SH 2005,2006 +./bin/tests/system/tsig/ns1/example.db ZONE 2005,2006 +./bin/tests/system/tsig/ns1/named.conf CONF-C 2005,2006 ./bin/tests/system/unknown/clean.sh SH 2000,2001,2004 ./bin/tests/system/unknown/ns1/.cvsignore X 2000,2001 ./bin/tests/system/unknown/ns1/broken1.db ZONE 2000,2001,2004 @@ -1968,6 +1972,7 @@ ./lib/isc/heap.c C 1997,1998,1999,2000,2001,2004,2005 ./lib/isc/hex.c C 2000,2001,2002,2003,2004,2005 ./lib/isc/hmacmd5.c C 2000,2001,2004,2005 +./lib/isc/hmacsha.c C 2005,2006 ./lib/isc/include/.cvsignore X 1999,2000,2001 ./lib/isc/include/Makefile.in MAKE 1998,1999,2000,2001,2004 ./lib/isc/include/isc/.cvsignore X 1999,2000,2001 @@ -1991,6 +1996,7 @@ ./lib/isc/include/isc/heap.h C 1997,1998,1999,2000,2001,2004,2005 ./lib/isc/include/isc/hex.h C 2000,2001,2004,2005 ./lib/isc/include/isc/hmacmd5.h C 2000,2001,2004,2005 +./lib/isc/include/isc/hmacsha.h C 2005,2006 ./lib/isc/include/isc/interfaceiter.h C 1999,2000,2001,2004,2005 ./lib/isc/include/isc/ipv6.h C 1999,2000,2001,2002,2004,2005 ./lib/isc/include/isc/lang.h C 1999,2000,2001,2004,2005 @@ -2023,6 +2029,7 @@ ./lib/isc/include/isc/rwlock.h C 1998,1999,2000,2001,2003,2004,2005 ./lib/isc/include/isc/serial.h C 1999,2000,2001,2004,2005 ./lib/isc/include/isc/sha1.h C 2000,2001,2004,2005 +./lib/isc/include/isc/sha2.h C 2004,2005 ./lib/isc/include/isc/sockaddr.h C 1998,1999,2000,2001,2002,2003,2004,2005 ./lib/isc/include/isc/socket.h C 1998,1999,2000,2001,2002,2004,2005 ./lib/isc/include/isc/stdio.h C 2000,2001,2004,2005