1135446Strhodes/* 2262706Serwin * Copyright (C) 2004, 2005, 2007, 2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2003 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id$ */ 19135446Strhodes 20135446Strhodes/* 21135446Strhodes * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley. 22135446Strhodes */ 23135446Strhodes 24170222Sdougb/* RFC2535 */ 25135446Strhodes 26135446Strhodes#ifndef RDATA_GENERIC_DNSKEY_48_C 27135446Strhodes#define RDATA_GENERIC_DNSKEY_48_C 28135446Strhodes 29135446Strhodes#include <dst/dst.h> 30135446Strhodes 31135446Strhodes#define RRTYPE_DNSKEY_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC) 32135446Strhodes 33135446Strhodesstatic inline isc_result_t 34135446Strhodesfromtext_dnskey(ARGS_FROMTEXT) { 35262706Serwin isc_result_t result; 36135446Strhodes isc_token_t token; 37135446Strhodes dns_secalg_t alg; 38135446Strhodes dns_secproto_t proto; 39135446Strhodes dns_keyflags_t flags; 40135446Strhodes 41135446Strhodes REQUIRE(type == 48); 42135446Strhodes 43135446Strhodes UNUSED(type); 44135446Strhodes UNUSED(rdclass); 45135446Strhodes UNUSED(origin); 46135446Strhodes UNUSED(options); 47135446Strhodes UNUSED(callbacks); 48135446Strhodes 49135446Strhodes /* flags */ 50135446Strhodes RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 51135446Strhodes ISC_FALSE)); 52135446Strhodes RETTOK(dns_keyflags_fromtext(&flags, &token.value.as_textregion)); 53135446Strhodes RETERR(uint16_tobuffer(flags, target)); 54135446Strhodes 55135446Strhodes /* protocol */ 56135446Strhodes RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 57135446Strhodes ISC_FALSE)); 58135446Strhodes RETTOK(dns_secproto_fromtext(&proto, &token.value.as_textregion)); 59135446Strhodes RETERR(mem_tobuffer(target, &proto, 1)); 60135446Strhodes 61135446Strhodes /* algorithm */ 62135446Strhodes RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 63135446Strhodes ISC_FALSE)); 64135446Strhodes RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion)); 65135446Strhodes RETERR(mem_tobuffer(target, &alg, 1)); 66135446Strhodes 67135446Strhodes /* No Key? */ 68135446Strhodes if ((flags & 0xc000) == 0xc000) 69135446Strhodes return (ISC_R_SUCCESS); 70135446Strhodes 71262706Serwin result = isc_base64_tobuffer(lexer, target, -1); 72262706Serwin if (result != ISC_R_SUCCESS) 73262706Serwin return (result); 74262706Serwin 75262706Serwin /* Ensure there's at least enough data to compute a key ID for MD5 */ 76262706Serwin if (alg == DST_ALG_RSAMD5 && isc_buffer_usedlength(target) < 7) 77262706Serwin return (ISC_R_UNEXPECTEDEND); 78262706Serwin 79262706Serwin return (ISC_R_SUCCESS); 80135446Strhodes} 81135446Strhodes 82135446Strhodesstatic inline isc_result_t 83135446Strhodestotext_dnskey(ARGS_TOTEXT) { 84135446Strhodes isc_region_t sr; 85135446Strhodes char buf[sizeof("64000")]; 86135446Strhodes unsigned int flags; 87135446Strhodes unsigned char algorithm; 88254897Serwin char algbuf[DNS_NAME_FORMATSIZE]; 89254897Serwin const char *keyinfo; 90135446Strhodes 91135446Strhodes REQUIRE(rdata->type == 48); 92135446Strhodes REQUIRE(rdata->length != 0); 93135446Strhodes 94135446Strhodes dns_rdata_toregion(rdata, &sr); 95135446Strhodes 96135446Strhodes /* flags */ 97135446Strhodes flags = uint16_fromregion(&sr); 98135446Strhodes isc_region_consume(&sr, 2); 99135446Strhodes sprintf(buf, "%u", flags); 100135446Strhodes RETERR(str_totext(buf, target)); 101135446Strhodes RETERR(str_totext(" ", target)); 102254897Serwin if ((flags & DNS_KEYFLAG_KSK) != 0) { 103254897Serwin if (flags & DNS_KEYFLAG_REVOKE) 104254897Serwin keyinfo = "revoked KSK"; 105254897Serwin else 106254897Serwin keyinfo = "KSK"; 107254897Serwin } else 108254897Serwin keyinfo = "ZSK"; 109135446Strhodes 110135446Strhodes /* protocol */ 111135446Strhodes sprintf(buf, "%u", sr.base[0]); 112135446Strhodes isc_region_consume(&sr, 1); 113135446Strhodes RETERR(str_totext(buf, target)); 114135446Strhodes RETERR(str_totext(" ", target)); 115135446Strhodes 116135446Strhodes /* algorithm */ 117135446Strhodes algorithm = sr.base[0]; 118135446Strhodes sprintf(buf, "%u", algorithm); 119135446Strhodes isc_region_consume(&sr, 1); 120135446Strhodes RETERR(str_totext(buf, target)); 121135446Strhodes 122135446Strhodes /* No Key? */ 123135446Strhodes if ((flags & 0xc000) == 0xc000) 124135446Strhodes return (ISC_R_SUCCESS); 125135446Strhodes 126254897Serwin if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 && 127224092Sdougb algorithm == DNS_KEYALG_PRIVATEDNS) { 128224092Sdougb dns_name_t name; 129224092Sdougb dns_name_init(&name, NULL); 130224092Sdougb dns_name_fromregion(&name, &sr); 131254897Serwin dns_name_format(&name, algbuf, sizeof(algbuf)); 132254897Serwin } else { 133254897Serwin dns_secalg_format((dns_secalg_t) algorithm, algbuf, 134254897Serwin sizeof(algbuf)); 135254897Serwin } 136224092Sdougb 137135446Strhodes /* key */ 138135446Strhodes if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 139135446Strhodes RETERR(str_totext(" (", target)); 140135446Strhodes RETERR(str_totext(tctx->linebreak, target)); 141254897Serwin if (tctx->width == 0) /* No splitting */ 142254897Serwin RETERR(isc_base64_totext(&sr, 0, "", target)); 143254897Serwin else 144254897Serwin RETERR(isc_base64_totext(&sr, tctx->width - 2, 145254897Serwin tctx->linebreak, target)); 146135446Strhodes 147254897Serwin if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) 148135446Strhodes RETERR(str_totext(tctx->linebreak, target)); 149135446Strhodes else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 150135446Strhodes RETERR(str_totext(" ", target)); 151135446Strhodes 152135446Strhodes if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 153135446Strhodes RETERR(str_totext(")", target)); 154135446Strhodes 155254897Serwin if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) { 156135446Strhodes isc_region_t tmpr; 157135446Strhodes 158254897Serwin RETERR(str_totext(" ; ", target)); 159254897Serwin RETERR(str_totext(keyinfo, target)); 160254897Serwin RETERR(str_totext("; alg = ", target)); 161254897Serwin RETERR(str_totext(algbuf, target)); 162254897Serwin RETERR(str_totext("; key id = ", target)); 163135446Strhodes dns_rdata_toregion(rdata, &tmpr); 164135446Strhodes sprintf(buf, "%u", dst_region_computeid(&tmpr, algorithm)); 165135446Strhodes RETERR(str_totext(buf, target)); 166135446Strhodes } 167135446Strhodes return (ISC_R_SUCCESS); 168135446Strhodes} 169135446Strhodes 170135446Strhodesstatic inline isc_result_t 171135446Strhodesfromwire_dnskey(ARGS_FROMWIRE) { 172224092Sdougb unsigned char algorithm; 173135446Strhodes isc_region_t sr; 174135446Strhodes 175135446Strhodes REQUIRE(type == 48); 176135446Strhodes 177135446Strhodes UNUSED(type); 178135446Strhodes UNUSED(rdclass); 179135446Strhodes UNUSED(dctx); 180135446Strhodes UNUSED(options); 181135446Strhodes 182135446Strhodes isc_buffer_activeregion(source, &sr); 183135446Strhodes if (sr.length < 4) 184135446Strhodes return (ISC_R_UNEXPECTEDEND); 185135446Strhodes 186224092Sdougb algorithm = sr.base[3]; 187224092Sdougb RETERR(mem_tobuffer(target, sr.base, 4)); 188224092Sdougb isc_region_consume(&sr, 4); 189224092Sdougb isc_buffer_forward(source, 4); 190224092Sdougb 191224092Sdougb if (algorithm == DNS_KEYALG_PRIVATEDNS) { 192224092Sdougb dns_name_t name; 193224092Sdougb dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); 194224092Sdougb dns_name_init(&name, NULL); 195224092Sdougb RETERR(dns_name_fromwire(&name, source, dctx, options, target)); 196224092Sdougb } 197262706Serwin 198262706Serwin /* 199262706Serwin * RSAMD5 computes key ID differently from other 200262706Serwin * algorithms: we need to ensure there's enough data 201262706Serwin * present for the computation 202262706Serwin */ 203262706Serwin if (algorithm == DST_ALG_RSAMD5 && sr.length < 3) 204262706Serwin return (ISC_R_UNEXPECTEDEND); 205262706Serwin 206224092Sdougb isc_buffer_activeregion(source, &sr); 207135446Strhodes isc_buffer_forward(source, sr.length); 208135446Strhodes return (mem_tobuffer(target, sr.base, sr.length)); 209135446Strhodes} 210135446Strhodes 211135446Strhodesstatic inline isc_result_t 212135446Strhodestowire_dnskey(ARGS_TOWIRE) { 213135446Strhodes isc_region_t sr; 214135446Strhodes 215135446Strhodes REQUIRE(rdata->type == 48); 216135446Strhodes REQUIRE(rdata->length != 0); 217135446Strhodes 218135446Strhodes UNUSED(cctx); 219135446Strhodes 220135446Strhodes dns_rdata_toregion(rdata, &sr); 221135446Strhodes return (mem_tobuffer(target, sr.base, sr.length)); 222135446Strhodes} 223135446Strhodes 224135446Strhodesstatic inline int 225135446Strhodescompare_dnskey(ARGS_COMPARE) { 226135446Strhodes isc_region_t r1; 227135446Strhodes isc_region_t r2; 228135446Strhodes 229135446Strhodes REQUIRE(rdata1->type == rdata2->type); 230135446Strhodes REQUIRE(rdata1->rdclass == rdata2->rdclass); 231135446Strhodes REQUIRE(rdata1->type == 48); 232135446Strhodes REQUIRE(rdata1->length != 0); 233135446Strhodes REQUIRE(rdata2->length != 0); 234135446Strhodes 235135446Strhodes dns_rdata_toregion(rdata1, &r1); 236135446Strhodes dns_rdata_toregion(rdata2, &r2); 237135446Strhodes return (isc_region_compare(&r1, &r2)); 238135446Strhodes} 239135446Strhodes 240135446Strhodesstatic inline isc_result_t 241135446Strhodesfromstruct_dnskey(ARGS_FROMSTRUCT) { 242135446Strhodes dns_rdata_dnskey_t *dnskey = source; 243135446Strhodes 244135446Strhodes REQUIRE(type == 48); 245135446Strhodes REQUIRE(source != NULL); 246135446Strhodes REQUIRE(dnskey->common.rdtype == type); 247135446Strhodes REQUIRE(dnskey->common.rdclass == rdclass); 248135446Strhodes 249135446Strhodes UNUSED(type); 250135446Strhodes UNUSED(rdclass); 251135446Strhodes 252135446Strhodes /* Flags */ 253135446Strhodes RETERR(uint16_tobuffer(dnskey->flags, target)); 254135446Strhodes 255135446Strhodes /* Protocol */ 256135446Strhodes RETERR(uint8_tobuffer(dnskey->protocol, target)); 257135446Strhodes 258135446Strhodes /* Algorithm */ 259135446Strhodes RETERR(uint8_tobuffer(dnskey->algorithm, target)); 260135446Strhodes 261135446Strhodes /* Data */ 262135446Strhodes return (mem_tobuffer(target, dnskey->data, dnskey->datalen)); 263135446Strhodes} 264135446Strhodes 265135446Strhodesstatic inline isc_result_t 266135446Strhodestostruct_dnskey(ARGS_TOSTRUCT) { 267135446Strhodes dns_rdata_dnskey_t *dnskey = target; 268135446Strhodes isc_region_t sr; 269135446Strhodes 270135446Strhodes REQUIRE(rdata->type == 48); 271135446Strhodes REQUIRE(target != NULL); 272135446Strhodes REQUIRE(rdata->length != 0); 273135446Strhodes 274135446Strhodes dnskey->common.rdclass = rdata->rdclass; 275135446Strhodes dnskey->common.rdtype = rdata->type; 276135446Strhodes ISC_LINK_INIT(&dnskey->common, link); 277135446Strhodes 278135446Strhodes dns_rdata_toregion(rdata, &sr); 279135446Strhodes 280135446Strhodes /* Flags */ 281135446Strhodes if (sr.length < 2) 282135446Strhodes return (ISC_R_UNEXPECTEDEND); 283135446Strhodes dnskey->flags = uint16_fromregion(&sr); 284135446Strhodes isc_region_consume(&sr, 2); 285135446Strhodes 286135446Strhodes /* Protocol */ 287135446Strhodes if (sr.length < 1) 288135446Strhodes return (ISC_R_UNEXPECTEDEND); 289135446Strhodes dnskey->protocol = uint8_fromregion(&sr); 290135446Strhodes isc_region_consume(&sr, 1); 291135446Strhodes 292135446Strhodes /* Algorithm */ 293135446Strhodes if (sr.length < 1) 294135446Strhodes return (ISC_R_UNEXPECTEDEND); 295135446Strhodes dnskey->algorithm = uint8_fromregion(&sr); 296135446Strhodes isc_region_consume(&sr, 1); 297135446Strhodes 298135446Strhodes /* Data */ 299135446Strhodes dnskey->datalen = sr.length; 300135446Strhodes dnskey->data = mem_maybedup(mctx, sr.base, dnskey->datalen); 301135446Strhodes if (dnskey->data == NULL) 302135446Strhodes return (ISC_R_NOMEMORY); 303135446Strhodes 304135446Strhodes dnskey->mctx = mctx; 305135446Strhodes return (ISC_R_SUCCESS); 306135446Strhodes} 307135446Strhodes 308135446Strhodesstatic inline void 309135446Strhodesfreestruct_dnskey(ARGS_FREESTRUCT) { 310135446Strhodes dns_rdata_dnskey_t *dnskey = (dns_rdata_dnskey_t *) source; 311135446Strhodes 312135446Strhodes REQUIRE(source != NULL); 313135446Strhodes REQUIRE(dnskey->common.rdtype == 48); 314135446Strhodes 315135446Strhodes if (dnskey->mctx == NULL) 316135446Strhodes return; 317135446Strhodes 318135446Strhodes if (dnskey->data != NULL) 319135446Strhodes isc_mem_free(dnskey->mctx, dnskey->data); 320135446Strhodes dnskey->mctx = NULL; 321135446Strhodes} 322135446Strhodes 323135446Strhodesstatic inline isc_result_t 324135446Strhodesadditionaldata_dnskey(ARGS_ADDLDATA) { 325135446Strhodes REQUIRE(rdata->type == 48); 326135446Strhodes 327135446Strhodes UNUSED(rdata); 328135446Strhodes UNUSED(add); 329135446Strhodes UNUSED(arg); 330135446Strhodes 331135446Strhodes return (ISC_R_SUCCESS); 332135446Strhodes} 333135446Strhodes 334135446Strhodesstatic inline isc_result_t 335135446Strhodesdigest_dnskey(ARGS_DIGEST) { 336135446Strhodes isc_region_t r; 337135446Strhodes 338135446Strhodes REQUIRE(rdata->type == 48); 339135446Strhodes 340135446Strhodes dns_rdata_toregion(rdata, &r); 341135446Strhodes 342135446Strhodes return ((digest)(arg, &r)); 343135446Strhodes} 344135446Strhodes 345135446Strhodesstatic inline isc_boolean_t 346135446Strhodescheckowner_dnskey(ARGS_CHECKOWNER) { 347135446Strhodes 348135446Strhodes REQUIRE(type == 48); 349135446Strhodes 350135446Strhodes UNUSED(name); 351135446Strhodes UNUSED(type); 352135446Strhodes UNUSED(rdclass); 353135446Strhodes UNUSED(wildcard); 354135446Strhodes 355135446Strhodes return (ISC_TRUE); 356135446Strhodes} 357135446Strhodes 358135446Strhodesstatic inline isc_boolean_t 359135446Strhodeschecknames_dnskey(ARGS_CHECKNAMES) { 360135446Strhodes 361135446Strhodes REQUIRE(rdata->type == 48); 362135446Strhodes 363135446Strhodes UNUSED(rdata); 364135446Strhodes UNUSED(owner); 365135446Strhodes UNUSED(bad); 366135446Strhodes 367135446Strhodes return (ISC_TRUE); 368135446Strhodes} 369135446Strhodes 370224092Sdougbstatic inline int 371224092Sdougbcasecompare_dnskey(ARGS_COMPARE) { 372224092Sdougb 373224092Sdougb /* 374224092Sdougb * Treat ALG 253 (private DNS) subtype name case sensistively. 375224092Sdougb */ 376224092Sdougb return (compare_dnskey(rdata1, rdata2)); 377224092Sdougb} 378224092Sdougb 379135446Strhodes#endif /* RDATA_GENERIC_DNSKEY_48_C */ 380