mirror of https://github.com/getdnsapi/getdns.git
Compare commits
3 Commits
45683d3cfe
...
01715688d7
Author | SHA1 | Date |
---|---|---|
|
01715688d7 | |
|
ecb9de2c29 | |
|
b86f8e904c |
|
@ -372,6 +372,8 @@ check_function_exists(SSL_set_ciphersuites HAVE_SSL_SET_CIPHERSUITES)
|
|||
|
||||
check_function_exists(OPENSSL_init_crypto HAVE_OPENSSL_INIT_CRYPTO)
|
||||
|
||||
check_function_exists(OSSL_PARAM_BLD_new HAVE_OSSL_PARAM_BLD_NEW)
|
||||
|
||||
check_symbol_exists(SSL_dane_enable "openssl/ssl.h" HAVE_SSL_DANE_ENABLE)
|
||||
check_symbol_exists(SSL_CTX_set1_curves_list "openssl/ssl.h" HAVE_DECL_SSL_CTX_SET1_CURVES_LIST)
|
||||
check_symbol_exists(SSL_set1_curves_list "openssl/ssl.h" HAVE_DECL_SSL_SET1_CURVES_LIST)
|
||||
|
|
|
@ -1599,7 +1599,7 @@ getdns_context_set_follow_redirects(getdns_context *context,
|
|||
* contains at least two names: address_type (whose value is
|
||||
* a bindata; it is currently either "IPv4" or "IPv6") and
|
||||
* address_data (whose value is a bindata).
|
||||
* This implementation also accepts a list of addressxi
|
||||
* This implementation also accepts a list of address
|
||||
* bindatas. Or a list of rr_dicts for address records (i.e.
|
||||
* the additional section of a NS query for ".", or a with
|
||||
* getdns_fp2rr_list() converted root.hints file).
|
||||
|
|
|
@ -149,6 +149,9 @@ gldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l
|
|||
if (c != '\0' && c != '\n') {
|
||||
*t++ = c;
|
||||
}
|
||||
if (c == '\n' && line_nr) {
|
||||
*line_nr = *line_nr + 1;
|
||||
}
|
||||
if (c == '\\' && prev_c == '\\')
|
||||
prev_c = 0;
|
||||
else prev_c = c;
|
||||
|
|
|
@ -794,3 +794,18 @@ int gldns_b64url_pton(char const *src, size_t srcsize, uint8_t *target,
|
|||
}
|
||||
return gldns_b64_pton_base(src, srcsize, target, targsize, 1);
|
||||
}
|
||||
|
||||
int gldns_b64_contains_nonurl(char const *src, size_t srcsize)
|
||||
{
|
||||
const char* s = src;
|
||||
while(*s && srcsize) {
|
||||
char d = *s++;
|
||||
srcsize--;
|
||||
/* the '+' and the '/' and padding '=' is not allowed in b64
|
||||
* url encoding */
|
||||
if(d == '+' || d == '/' || d == '=') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ time_t gldns_mktime_from_utc(const struct tm *tm);
|
|||
* The function interprets time as the number of seconds since epoch
|
||||
* with respect to now using serial arithmetics (rfc1982).
|
||||
* That number of seconds is then converted to broken-out time information.
|
||||
* This is especially usefull when converting the inception and expiration
|
||||
* This is especially useful when converting the inception and expiration
|
||||
* fields of RRSIG records.
|
||||
*
|
||||
* \param[in] time number of seconds since epoch (midnight, January 1st, 1970)
|
||||
|
@ -102,6 +102,7 @@ size_t gldns_b64_pton_calculate_size(size_t srcsize);
|
|||
int gldns_b64_pton(char const *src, uint8_t *target, size_t targsize);
|
||||
int gldns_b64url_pton(char const *src, size_t srcsize, uint8_t *target,
|
||||
size_t targsize);
|
||||
int gldns_b64_contains_nonurl(char const *src, size_t srcsize);
|
||||
|
||||
/**
|
||||
* calculates the size needed to store the result of b32_ntop
|
||||
|
|
|
@ -155,6 +155,9 @@ static const gldns_rdf_type type_csync_wireformat[] = {
|
|||
static const gldns_rdf_type type_zonemd_wireformat[] = {
|
||||
GLDNS_RDF_TYPE_INT32, GLDNS_RDF_TYPE_INT8, GLDNS_RDF_TYPE_INT8, GLDNS_RDF_TYPE_HEX
|
||||
};
|
||||
static const gldns_rdf_type type_svcb_wireformat[] = {
|
||||
GLDNS_RDF_TYPE_INT16, GLDNS_RDF_TYPE_DNAME
|
||||
};
|
||||
/* nsec3 is some vars, followed by same type of data of nsec */
|
||||
static const gldns_rdf_type type_nsec3_wireformat[] = {
|
||||
/* GLDNS_RDF_TYPE_NSEC3_VARS, GLDNS_RDF_TYPE_NSEC3_NEXT_OWNER, GLDNS_RDF_TYPE_NSEC*/
|
||||
|
@ -388,8 +391,10 @@ static gldns_rr_descriptor rdata_field_descriptors[] = {
|
|||
{GLDNS_RR_TYPE_CSYNC, "CSYNC", 3, 3, type_csync_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
|
||||
/* 63 */
|
||||
{GLDNS_RR_TYPE_ZONEMD, "ZONEMD", 4, 4, type_zonemd_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
|
||||
{(enum gldns_enum_rr_type)0, "TYPE64", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
|
||||
{(enum gldns_enum_rr_type)0, "TYPE65", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
|
||||
/* 64 */
|
||||
{GLDNS_RR_TYPE_SVCB, "SVCB", 2, 2, type_svcb_wireformat, GLDNS_RDF_TYPE_SVCPARAM, GLDNS_RR_NO_COMPRESS, 0 },
|
||||
/* 65 */
|
||||
{GLDNS_RR_TYPE_HTTPS, "HTTPS", 2, 2, type_svcb_wireformat, GLDNS_RDF_TYPE_SVCPARAM, GLDNS_RR_NO_COMPRESS, 0 },
|
||||
{(enum gldns_enum_rr_type)0, "TYPE66", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
|
||||
{(enum gldns_enum_rr_type)0, "TYPE67", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
|
||||
{(enum gldns_enum_rr_type)0, "TYPE68", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
|
||||
|
|
|
@ -196,8 +196,8 @@ enum gldns_enum_rr_type
|
|||
GLDNS_RR_TYPE_OPENPGPKEY = 61, /* RFC 7929 */
|
||||
GLDNS_RR_TYPE_CSYNC = 62, /* RFC 7477 */
|
||||
GLDNS_RR_TYPE_ZONEMD = 63, /* RFC8976 */
|
||||
GLDNS_RR_TYPE_SVCB = 64,
|
||||
GLDNS_RR_TYPE_HTTPS = 65,
|
||||
GLDNS_RR_TYPE_SVCB = 64, /* draft-ietf-dnsop-svcb-https-04 */
|
||||
GLDNS_RR_TYPE_HTTPS = 65, /* draft-ietf-dnsop-svcb-https-04 */
|
||||
|
||||
GLDNS_RR_TYPE_SPF = 99, /* RFC 4408 */
|
||||
|
||||
|
@ -360,8 +360,13 @@ enum gldns_enum_rdf_type
|
|||
/** TSIG extended 16bit error value */
|
||||
GLDNS_RDF_TYPE_TSIGERROR,
|
||||
|
||||
/* draft-ietf-dnsop-svcb-https-05:
|
||||
* each SvcParam consisting of a SvcParamKey=SvcParamValue pair or
|
||||
* a standalone SvcParamKey */
|
||||
GLDNS_RDF_TYPE_SVCPARAM,
|
||||
|
||||
/* Aliases */
|
||||
GLDNS_RDF_TYPE_BITMAP = GLDNS_RDF_TYPE_NSEC
|
||||
GLDNS_RDF_TYPE_BITMAP = GLDNS_RDF_TYPE_NSEC,
|
||||
};
|
||||
typedef enum gldns_enum_rdf_type gldns_rdf_type;
|
||||
|
||||
|
|
|
@ -26,11 +26,12 @@
|
|||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
/** bits for the offset */
|
||||
#define RET_OFFSET_MASK (((unsigned)(~GLDNS_WIREPARSE_MASK))>>GLDNS_WIREPARSE_SHIFT)
|
||||
/** return an error */
|
||||
#define RET_ERR(e, off) ((int)((e)|((off)<<GLDNS_WIREPARSE_SHIFT)))
|
||||
#define RET_ERR(e, off) ((int)(((e)&GLDNS_WIREPARSE_MASK)|(((off)&RET_OFFSET_MASK)<<GLDNS_WIREPARSE_SHIFT)))
|
||||
/** Move parse error but keep its ID */
|
||||
#define RET_ERR_SHIFT(e, move) RET_ERR(GLDNS_WIREPARSE_ERROR(e), GLDNS_WIREPARSE_OFFSET(e)+(move));
|
||||
#define GLDNS_IP6ADDRLEN (128/8)
|
||||
|
||||
/*
|
||||
* No special care is taken, all dots are translated into
|
||||
|
@ -545,9 +546,10 @@ gldns_parse_rdf_token(gldns_buffer* strbuf, char* token, size_t token_len,
|
|||
{
|
||||
size_t slen;
|
||||
|
||||
/* skip spaces */
|
||||
/* skip spaces and tabs */
|
||||
while(gldns_buffer_remaining(strbuf) > 0 && !*quoted &&
|
||||
*(gldns_buffer_current(strbuf)) == ' ') {
|
||||
(*(gldns_buffer_current(strbuf)) == ' ' ||
|
||||
*(gldns_buffer_current(strbuf)) == '\t')) {
|
||||
gldns_buffer_skip(strbuf, 1);
|
||||
}
|
||||
|
||||
|
@ -603,7 +605,10 @@ gldns_affix_token(gldns_buffer* strbuf, char* token, size_t* token_len,
|
|||
size_t addstrlen = 0;
|
||||
|
||||
/* add space */
|
||||
if(addlen < 1) return 0;
|
||||
/* when addlen < 2, the token buffer is full considering the NULL byte
|
||||
* from strlen and will lead to buffer overflow with the second
|
||||
* assignement below. */
|
||||
if(addlen < 2) return 0;
|
||||
token[*token_strlen] = ' ';
|
||||
token[++(*token_strlen)] = 0;
|
||||
|
||||
|
@ -616,6 +621,122 @@ gldns_affix_token(gldns_buffer* strbuf, char* token, size_t* token_len,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int gldns_str2wire_svcparam_key_cmp(const void *a, const void *b)
|
||||
{
|
||||
return gldns_read_uint16(*(uint8_t**) a)
|
||||
- gldns_read_uint16(*(uint8_t**) b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add constraints to the SVCB RRs which involve the whole set
|
||||
*/
|
||||
static int gldns_str2wire_check_svcbparams(uint8_t* rdata, uint16_t rdata_len)
|
||||
{
|
||||
size_t nparams = 0, i;
|
||||
uint8_t new_rdata[GLDNS_MAX_RDFLEN];
|
||||
uint8_t* new_rdata_ptr = new_rdata;
|
||||
uint8_t* svcparams[MAX_NUMBER_OF_SVCPARAMS];
|
||||
uint8_t* rdata_ptr = rdata;
|
||||
uint16_t rdata_remaining = rdata_len;
|
||||
|
||||
/* find the SvcParams */
|
||||
while (rdata_remaining) {
|
||||
uint16_t svcbparam_len;
|
||||
|
||||
svcparams[nparams] = rdata_ptr;
|
||||
if (rdata_remaining < 4)
|
||||
return GLDNS_WIREPARSE_ERR_SVCPARAM_BROKEN_RDATA;
|
||||
svcbparam_len = gldns_read_uint16(rdata_ptr + 2);
|
||||
rdata_remaining -= 4;
|
||||
rdata_ptr += 4;
|
||||
|
||||
if (rdata_remaining < svcbparam_len)
|
||||
return GLDNS_WIREPARSE_ERR_SVCPARAM_BROKEN_RDATA;
|
||||
rdata_remaining -= svcbparam_len;
|
||||
rdata_ptr += svcbparam_len;
|
||||
|
||||
nparams += 1;
|
||||
if (nparams >= MAX_NUMBER_OF_SVCPARAMS)
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_TOO_MANY_PARAMS;
|
||||
}
|
||||
|
||||
/* In draft-ietf-dnsop-svcb-https-06 Section 7:
|
||||
*
|
||||
* In wire format, the keys are represented by their numeric
|
||||
* values in network byte order, concatenated in ascending order.
|
||||
*/
|
||||
qsort((void *)svcparams
|
||||
,nparams
|
||||
,sizeof(uint8_t*)
|
||||
,gldns_str2wire_svcparam_key_cmp);
|
||||
|
||||
|
||||
/* The code below revolves around sematic errors in the SVCParam set.
|
||||
* So long as we do not distinguish between running Unbound as a primary
|
||||
* or as a secondary, we default to secondary behavior and we ignore the
|
||||
* sematic errors. */
|
||||
|
||||
#ifdef SVCB_SEMANTIC_ERRORS
|
||||
{
|
||||
uint8_t* mandatory = NULL;
|
||||
/* In draft-ietf-dnsop-svcb-https-06 Section 7:
|
||||
*
|
||||
* Keys (...) MUST NOT appear more than once.
|
||||
*
|
||||
* If they key has already been seen, we have a duplicate
|
||||
*/
|
||||
for(i=0; i < nparams; i++) {
|
||||
uint16_t key = gldns_read_uint16(svcparams[i]);
|
||||
if(i + 1 < nparams && key == gldns_read_uint16(svcparams[i+1]))
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_DUPLICATE_KEYS;
|
||||
if(key == SVCB_KEY_MANDATORY)
|
||||
mandatory = svcparams[i];
|
||||
}
|
||||
|
||||
/* 4. verify that all the SvcParamKeys in mandatory are present */
|
||||
if(mandatory) {
|
||||
/* Divide by sizeof(uint16_t)*/
|
||||
uint16_t mandatory_nkeys = gldns_read_uint16(mandatory + 2) / sizeof(uint16_t);
|
||||
|
||||
/* Guaranteed by gldns_str2wire_svcparam_key_value */
|
||||
assert(mandatory_nkeys > 0);
|
||||
|
||||
for(i=0; i < mandatory_nkeys; i++) {
|
||||
uint16_t mandatory_key = gldns_read_uint16(
|
||||
mandatory
|
||||
+ 2 * sizeof(uint16_t)
|
||||
+ i * sizeof(uint16_t));
|
||||
uint8_t found = 0;
|
||||
size_t j;
|
||||
|
||||
for(j=0; j < nparams; j++) {
|
||||
if(mandatory_key == gldns_read_uint16(svcparams[j])) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_MISSING_PARAM;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Write rdata in correct order */
|
||||
for (i = 0; i < nparams; i++) {
|
||||
uint16_t svcparam_len = gldns_read_uint16(svcparams[i] + 2)
|
||||
+ 2 * sizeof(uint16_t);
|
||||
|
||||
if ((unsigned)(new_rdata_ptr - new_rdata) + svcparam_len > sizeof(new_rdata))
|
||||
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
|
||||
memcpy(new_rdata_ptr, svcparams[i], svcparam_len);
|
||||
new_rdata_ptr += svcparam_len;
|
||||
}
|
||||
memcpy(rdata, new_rdata, rdata_len);
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
|
||||
/** parse rdata from string into rr buffer(-remainder after dname). */
|
||||
static int
|
||||
rrinternal_parse_rdata(gldns_buffer* strbuf, char* token, size_t token_len,
|
||||
|
@ -713,6 +834,42 @@ rrinternal_parse_rdata(gldns_buffer* strbuf, char* token, size_t token_len,
|
|||
/* write rdata length */
|
||||
gldns_write_uint16(rr+dname_len+8, (uint16_t)(rr_cur_len-dname_len-10));
|
||||
*rr_len = rr_cur_len;
|
||||
/* SVCB/HTTPS handling */
|
||||
if (rr_type == GLDNS_RR_TYPE_SVCB || rr_type == GLDNS_RR_TYPE_HTTPS) {
|
||||
size_t rdata_len = rr_cur_len - dname_len - 10;
|
||||
uint8_t *rdata = rr+dname_len + 10;
|
||||
|
||||
/* skip 1st rdata field SvcPriority (uint16_t) */
|
||||
if (rdata_len < sizeof(uint16_t))
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
|
||||
rdata_len -= sizeof(uint16_t);
|
||||
rdata += sizeof(uint16_t);
|
||||
|
||||
/* skip 2nd rdata field dname */
|
||||
while (rdata_len && *rdata != 0) {
|
||||
uint8_t label_len;
|
||||
|
||||
if (*rdata & 0xC0)
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
|
||||
label_len = *rdata + 1;
|
||||
if (rdata_len < label_len)
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
|
||||
rdata_len -= label_len;
|
||||
rdata += label_len;
|
||||
}
|
||||
/* The root label is one more character, so smaller
|
||||
* than 1 + 1 means no Svcparam Keys */
|
||||
if (rdata_len < 2 || *rdata != 0)
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
|
||||
rdata_len -= 1;
|
||||
rdata += 1;
|
||||
return gldns_str2wire_check_svcbparams(rdata, rdata_len);
|
||||
|
||||
}
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
|
||||
|
@ -939,6 +1096,524 @@ int gldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len,
|
|||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
gldns_str2wire_svcparam_key_lookup(const char *key, size_t key_len)
|
||||
{
|
||||
char buf[64];
|
||||
char *endptr;
|
||||
unsigned long int key_value;
|
||||
|
||||
if (key_len >= 4 && key_len <= 8 && !strncmp(key, "key", 3)) {
|
||||
memcpy(buf, key + 3, key_len - 3);
|
||||
buf[key_len - 3] = 0;
|
||||
key_value = strtoul(buf, &endptr, 10);
|
||||
|
||||
if (endptr > buf /* digits seen */
|
||||
&& *endptr == 0 /* no non-digit chars after digits */
|
||||
&& key_value <= 65535) /* no overflow */
|
||||
return key_value;
|
||||
|
||||
} else switch (key_len) {
|
||||
case sizeof("mandatory")-1:
|
||||
if (!strncmp(key, "mandatory", sizeof("mandatory")-1))
|
||||
return SVCB_KEY_MANDATORY;
|
||||
if (!strncmp(key, "echconfig", sizeof("echconfig")-1))
|
||||
return SVCB_KEY_ECH; /* allow "echconfig as well as "ech" */
|
||||
break;
|
||||
|
||||
case sizeof("alpn")-1:
|
||||
if (!strncmp(key, "alpn", sizeof("alpn")-1))
|
||||
return SVCB_KEY_ALPN;
|
||||
if (!strncmp(key, "port", sizeof("port")-1))
|
||||
return SVCB_KEY_PORT;
|
||||
break;
|
||||
|
||||
case sizeof("no-default-alpn")-1:
|
||||
if (!strncmp( key , "no-default-alpn"
|
||||
, sizeof("no-default-alpn")-1))
|
||||
return SVCB_KEY_NO_DEFAULT_ALPN;
|
||||
break;
|
||||
|
||||
case sizeof("ipv4hint")-1:
|
||||
if (!strncmp(key, "ipv4hint", sizeof("ipv4hint")-1))
|
||||
return SVCB_KEY_IPV4HINT;
|
||||
if (!strncmp(key, "ipv6hint", sizeof("ipv6hint")-1))
|
||||
return SVCB_KEY_IPV6HINT;
|
||||
break;
|
||||
|
||||
case sizeof("ech")-1:
|
||||
if (!strncmp(key, "ech", sizeof("ech")-1))
|
||||
return SVCB_KEY_ECH;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Although the returned value might be used by the caller,
|
||||
* the parser has erred, so the zone will not be loaded.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
gldns_str2wire_svcparam_port(const char* val, uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
unsigned long int port;
|
||||
char *endptr;
|
||||
|
||||
if (*rd_len < 6)
|
||||
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
|
||||
port = strtoul(val, &endptr, 10);
|
||||
|
||||
if (endptr > val /* digits seen */
|
||||
&& *endptr == 0 /* no non-digit chars after digits */
|
||||
&& port <= 65535) { /* no overflow */
|
||||
|
||||
gldns_write_uint16(rd, SVCB_KEY_PORT);
|
||||
gldns_write_uint16(rd + 2, sizeof(uint16_t));
|
||||
gldns_write_uint16(rd + 4, port);
|
||||
*rd_len = 6;
|
||||
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_PORT_VALUE_SYNTAX;
|
||||
}
|
||||
|
||||
static int
|
||||
gldns_str2wire_svcbparam_ipv4hint(const char* val, uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
size_t count;
|
||||
char ip_str[INET_ADDRSTRLEN+1];
|
||||
char *next_ip_str;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, count = 1; val[i]; i++) {
|
||||
if (val[i] == ',')
|
||||
count += 1;
|
||||
if (count > SVCB_MAX_COMMA_SEPARATED_VALUES) {
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_IPV4_TOO_MANY_ADDRESSES;
|
||||
}
|
||||
}
|
||||
|
||||
if (*rd_len < (GLDNS_IP4ADDRLEN * count) + 4)
|
||||
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
|
||||
/* count is number of comma's in val + 1; so the actual number of IPv4
|
||||
* addresses in val
|
||||
*/
|
||||
gldns_write_uint16(rd, SVCB_KEY_IPV4HINT);
|
||||
gldns_write_uint16(rd + 2, GLDNS_IP4ADDRLEN * count);
|
||||
*rd_len = 4;
|
||||
|
||||
while (count) {
|
||||
if (!(next_ip_str = strchr(val, ','))) {
|
||||
if (inet_pton(AF_INET, val, rd + *rd_len) != 1)
|
||||
break;
|
||||
*rd_len += GLDNS_IP4ADDRLEN;
|
||||
|
||||
assert(count == 1);
|
||||
|
||||
} else if (next_ip_str - val >= (int)sizeof(ip_str))
|
||||
break;
|
||||
|
||||
else {
|
||||
memcpy(ip_str, val, next_ip_str - val);
|
||||
ip_str[next_ip_str - val] = 0;
|
||||
if (inet_pton(AF_INET, ip_str, rd + *rd_len) != 1) {
|
||||
break;
|
||||
}
|
||||
*rd_len += GLDNS_IP4ADDRLEN;
|
||||
|
||||
val = next_ip_str + 1;
|
||||
}
|
||||
count--;
|
||||
}
|
||||
if (count) /* verify that we parsed all values */
|
||||
return GLDNS_WIREPARSE_ERR_SYNTAX_IP4;
|
||||
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
gldns_str2wire_svcbparam_ipv6hint(const char* val, uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
size_t count;
|
||||
char ip_str[INET6_ADDRSTRLEN+1];
|
||||
char *next_ip_str;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, count = 1; val[i]; i++) {
|
||||
if (val[i] == ',')
|
||||
count += 1;
|
||||
if (count > SVCB_MAX_COMMA_SEPARATED_VALUES) {
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_IPV6_TOO_MANY_ADDRESSES;
|
||||
}
|
||||
}
|
||||
|
||||
if (*rd_len < (GLDNS_IP6ADDRLEN * count) + 4)
|
||||
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
|
||||
/* count is number of comma's in val + 1; so the actual number of IPv6
|
||||
* addresses in val
|
||||
*/
|
||||
gldns_write_uint16(rd, SVCB_KEY_IPV6HINT);
|
||||
gldns_write_uint16(rd + 2, GLDNS_IP6ADDRLEN * count);
|
||||
*rd_len = 4;
|
||||
|
||||
while (count) {
|
||||
if (!(next_ip_str = strchr(val, ','))) {
|
||||
if (inet_pton(AF_INET6, val, rd + *rd_len) != 1)
|
||||
break;
|
||||
*rd_len += GLDNS_IP6ADDRLEN;
|
||||
|
||||
assert(count == 1);
|
||||
|
||||
} else if (next_ip_str - val >= (int)sizeof(ip_str))
|
||||
break;
|
||||
|
||||
else {
|
||||
memcpy(ip_str, val, next_ip_str - val);
|
||||
ip_str[next_ip_str - val] = 0;
|
||||
if (inet_pton(AF_INET6, ip_str, rd + *rd_len) != 1) {
|
||||
break;
|
||||
}
|
||||
*rd_len += GLDNS_IP6ADDRLEN;
|
||||
|
||||
val = next_ip_str + 1;
|
||||
}
|
||||
count--;
|
||||
}
|
||||
if (count) /* verify that we parsed all values */
|
||||
return GLDNS_WIREPARSE_ERR_SYNTAX_IP6;
|
||||
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
|
||||
/* compare function used for sorting uint16_t's */
|
||||
static int
|
||||
gldns_network_uint16_cmp(const void *a, const void *b)
|
||||
{
|
||||
return ((int)gldns_read_uint16(a)) - ((int)gldns_read_uint16(b));
|
||||
}
|
||||
|
||||
static int
|
||||
gldns_str2wire_svcbparam_mandatory(const char* val, uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
size_t i, count, val_len;
|
||||
char* next_key;
|
||||
|
||||
val_len = strlen(val);
|
||||
|
||||
for (i = 0, count = 1; val[i]; i++) {
|
||||
if (val[i] == ',')
|
||||
count += 1;
|
||||
if (count > SVCB_MAX_COMMA_SEPARATED_VALUES) {
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_TOO_MANY_KEYS;
|
||||
}
|
||||
}
|
||||
if (sizeof(uint16_t) * (count + 2) > *rd_len)
|
||||
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
|
||||
gldns_write_uint16(rd, SVCB_KEY_MANDATORY);
|
||||
gldns_write_uint16(rd + 2, sizeof(uint16_t) * count);
|
||||
*rd_len = 4;
|
||||
|
||||
while (1) {
|
||||
int svcparamkey;
|
||||
|
||||
if (!(next_key = strchr(val, ','))) {
|
||||
svcparamkey = gldns_str2wire_svcparam_key_lookup(val, val_len);
|
||||
|
||||
if (svcparamkey < 0) {
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_UNKNOWN_KEY;
|
||||
}
|
||||
|
||||
gldns_write_uint16(rd + *rd_len, svcparamkey);
|
||||
*rd_len += 2;
|
||||
break;
|
||||
} else {
|
||||
svcparamkey = gldns_str2wire_svcparam_key_lookup(val, next_key - val);
|
||||
|
||||
if (svcparamkey < 0) {
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_UNKNOWN_KEY;
|
||||
}
|
||||
|
||||
gldns_write_uint16(rd + *rd_len,
|
||||
svcparamkey);
|
||||
*rd_len += 2;
|
||||
}
|
||||
|
||||
val_len -= next_key - val + 1;
|
||||
val = next_key + 1; /* skip the comma */
|
||||
}
|
||||
|
||||
/* In draft-ietf-dnsop-svcb-https-06 Section 7:
|
||||
*
|
||||
* "In wire format, the keys are represented by their numeric
|
||||
* values in network byte order, concatenated in ascending order."
|
||||
*/
|
||||
qsort((void *)(rd + 4), count, sizeof(uint16_t), gldns_network_uint16_cmp);
|
||||
|
||||
/* The code below revolves around sematic errors in the SVCParam set.
|
||||
* So long as we do not distinguish between running Unbound as a primary
|
||||
* or as a secondary, we default to secondary behavior and we ignore the
|
||||
* semantic errors. */
|
||||
#ifdef SVCB_SEMANTIC_ERRORS
|
||||
/* In draft-ietf-dnsop-svcb-https-06 Section 8
|
||||
* automatically mandatory MUST NOT appear in its own value-list
|
||||
*/
|
||||
if (gldns_read_uint16(rd + 4) == SVCB_KEY_MANDATORY)
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_IN_MANDATORY;
|
||||
|
||||
/* Guarantee key uniqueness. After the sort we only need to
|
||||
* compare neighbouring keys */
|
||||
if (count > 1) {
|
||||
for (i = 0; i < count - 1; i++) {
|
||||
uint8_t* current_pos = (rd + 4 + (sizeof(uint16_t) * i));
|
||||
uint16_t key = gldns_read_uint16(current_pos);
|
||||
|
||||
if (key == gldns_read_uint16(current_pos + 2)) {
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_DUPLICATE_KEY;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
gldns_str2wire_svcbparam_ech_value(const char* val, uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
uint8_t buffer[GLDNS_MAX_RDFLEN];
|
||||
int wire_len;
|
||||
|
||||
/* single 0 represents empty buffer */
|
||||
if(strcmp(val, "0") == 0) {
|
||||
if (*rd_len < 4)
|
||||
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
gldns_write_uint16(rd, SVCB_KEY_ECH);
|
||||
gldns_write_uint16(rd + 2, 0);
|
||||
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
|
||||
wire_len = gldns_b64_pton(val, buffer, GLDNS_MAX_RDFLEN);
|
||||
|
||||
if (wire_len <= 0) {
|
||||
return GLDNS_WIREPARSE_ERR_SYNTAX_B64;
|
||||
} else if ((unsigned)wire_len + 4 > *rd_len) {
|
||||
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
} else {
|
||||
gldns_write_uint16(rd, SVCB_KEY_ECH);
|
||||
gldns_write_uint16(rd + 2, wire_len);
|
||||
memcpy(rd + 4, buffer, wire_len);
|
||||
*rd_len = 4 + wire_len;
|
||||
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
gldns_str2wire_svcbparam_parse_next_unescaped_comma(const char *val)
|
||||
{
|
||||
while (*val) {
|
||||
/* Only return when the comma is not escaped*/
|
||||
if (*val == '\\'){
|
||||
++val;
|
||||
if (!*val)
|
||||
break;
|
||||
} else if (*val == ',')
|
||||
return val;
|
||||
|
||||
val++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The source is already properly unescaped, this double unescaping is purely to allow for
|
||||
* comma's in comma separated alpn lists.
|
||||
*
|
||||
* In draft-ietf-dnsop-svcb-https-06 Section 7:
|
||||
* To enable simpler parsing, this SvcParamValue MUST NOT contain escape sequences.
|
||||
*/
|
||||
static size_t
|
||||
gldns_str2wire_svcbparam_parse_copy_unescaped(uint8_t *dst,
|
||||
const char *src, size_t len)
|
||||
{
|
||||
uint8_t *orig_dst = dst;
|
||||
|
||||
while (len) {
|
||||
if (*src == '\\') {
|
||||
src++;
|
||||
len--;
|
||||
if (!len)
|
||||
break;
|
||||
}
|
||||
*dst++ = *src++;
|
||||
len--;
|
||||
}
|
||||
return (size_t)(dst - orig_dst);
|
||||
}
|
||||
|
||||
static int
|
||||
gldns_str2wire_svcbparam_alpn_value(const char* val,
|
||||
uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
uint8_t unescaped_dst[GLDNS_MAX_RDFLEN];
|
||||
uint8_t *dst = unescaped_dst;
|
||||
const char *next_str;
|
||||
size_t str_len;
|
||||
size_t dst_len;
|
||||
size_t val_len;
|
||||
|
||||
val_len = strlen(val);
|
||||
|
||||
if (val_len > sizeof(unescaped_dst)) {
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_ALPN_KEY_TOO_LARGE;
|
||||
}
|
||||
while (val_len) {
|
||||
size_t key_len;
|
||||
|
||||
str_len = (next_str = gldns_str2wire_svcbparam_parse_next_unescaped_comma(val))
|
||||
? (size_t)(next_str - val) : val_len;
|
||||
|
||||
if (str_len > 255) {
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_ALPN_KEY_TOO_LARGE;
|
||||
}
|
||||
|
||||
key_len = gldns_str2wire_svcbparam_parse_copy_unescaped(dst + 1, val, str_len);
|
||||
*dst++ = key_len;
|
||||
dst += key_len;
|
||||
|
||||
if (!next_str)
|
||||
break;
|
||||
|
||||
/* skip the comma in the next iteration */
|
||||
val_len -= next_str - val + 1;
|
||||
val = next_str + 1;
|
||||
}
|
||||
dst_len = dst - unescaped_dst;
|
||||
if (*rd_len < 4 + dst_len)
|
||||
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
gldns_write_uint16(rd, SVCB_KEY_ALPN);
|
||||
gldns_write_uint16(rd + 2, dst_len);
|
||||
memcpy(rd + 4, unescaped_dst, dst_len);
|
||||
*rd_len = 4 + dst_len;
|
||||
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
gldns_str2wire_svcparam_value(const char *key, size_t key_len,
|
||||
const char *val, uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
size_t str_len;
|
||||
int svcparamkey = gldns_str2wire_svcparam_key_lookup(key, key_len);
|
||||
|
||||
if (svcparamkey < 0) {
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_UNKNOWN_KEY;
|
||||
}
|
||||
|
||||
/* key without value */
|
||||
if (val == NULL) {
|
||||
switch (svcparamkey) {
|
||||
#ifdef SVCB_SEMANTIC_ERRORS
|
||||
case SVCB_KEY_MANDATORY:
|
||||
case SVCB_KEY_ALPN:
|
||||
case SVCB_KEY_PORT:
|
||||
case SVCB_KEY_IPV4HINT:
|
||||
case SVCB_KEY_IPV6HINT:
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_MISSING_PARAM;
|
||||
#endif
|
||||
default:
|
||||
if (*rd_len < 4)
|
||||
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
gldns_write_uint16(rd, svcparamkey);
|
||||
gldns_write_uint16(rd + 2, 0);
|
||||
*rd_len = 4;
|
||||
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* value is non-empty */
|
||||
switch (svcparamkey) {
|
||||
case SVCB_KEY_PORT:
|
||||
return gldns_str2wire_svcparam_port(val, rd, rd_len);
|
||||
case SVCB_KEY_IPV4HINT:
|
||||
return gldns_str2wire_svcbparam_ipv4hint(val, rd, rd_len);
|
||||
case SVCB_KEY_IPV6HINT:
|
||||
return gldns_str2wire_svcbparam_ipv6hint(val, rd, rd_len);
|
||||
case SVCB_KEY_MANDATORY:
|
||||
return gldns_str2wire_svcbparam_mandatory(val, rd, rd_len);
|
||||
#ifdef SVCB_SEMANTIC_ERRORS
|
||||
case SVCB_KEY_NO_DEFAULT_ALPN:
|
||||
return GLDNS_WIREPARSE_ERR_SVCB_NO_DEFAULT_ALPN_VALUE;
|
||||
#endif
|
||||
case SVCB_KEY_ECH:
|
||||
return gldns_str2wire_svcbparam_ech_value(val, rd, rd_len);
|
||||
case SVCB_KEY_ALPN:
|
||||
return gldns_str2wire_svcbparam_alpn_value(val, rd, rd_len);
|
||||
default:
|
||||
str_len = strlen(val);
|
||||
if (*rd_len < 4 + str_len)
|
||||
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
gldns_write_uint16(rd, svcparamkey);
|
||||
gldns_write_uint16(rd + 2, str_len);
|
||||
memcpy(rd + 4, val, str_len);
|
||||
*rd_len = 4 + str_len;
|
||||
|
||||
return GLDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
|
||||
return GLDNS_WIREPARSE_ERR_GENERAL;
|
||||
}
|
||||
|
||||
static int gldns_str2wire_svcparam_buf(const char* str, uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
const char* eq_pos;
|
||||
char unescaped_val[GLDNS_MAX_RDFLEN];
|
||||
char* val_out = unescaped_val;
|
||||
const char* val_in;
|
||||
|
||||
eq_pos = strchr(str, '=');
|
||||
|
||||
/* case: key=value */
|
||||
if (eq_pos != NULL && eq_pos[1]) {
|
||||
val_in = eq_pos + 1;
|
||||
|
||||
/* unescape characters and "" blocks */
|
||||
if (*val_in == '"') {
|
||||
val_in++;
|
||||
while (*val_in != '"'
|
||||
&& (unsigned)(val_out - unescaped_val + 1) < sizeof(unescaped_val)
|
||||
&& gldns_parse_char( (uint8_t*) val_out, &val_in)) {
|
||||
val_out++;
|
||||
}
|
||||
} else {
|
||||
while ((unsigned)(val_out - unescaped_val + 1) < sizeof(unescaped_val)
|
||||
&& gldns_parse_char( (uint8_t*) val_out, &val_in)) {
|
||||
val_out++;
|
||||
}
|
||||
}
|
||||
*val_out = 0;
|
||||
|
||||
return gldns_str2wire_svcparam_value(str, eq_pos - str,
|
||||
unescaped_val[0] ? unescaped_val : NULL, rd, rd_len);
|
||||
}
|
||||
/* case: key= */
|
||||
else if (eq_pos != NULL && !(eq_pos[1])) {
|
||||
return gldns_str2wire_svcparam_value(str, eq_pos - str, NULL, rd, rd_len);
|
||||
}
|
||||
/* case: key */
|
||||
else {
|
||||
return gldns_str2wire_svcparam_value(str, strlen(str), NULL, rd, rd_len);
|
||||
}
|
||||
}
|
||||
|
||||
int gldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len,
|
||||
gldns_rdf_type rdftype)
|
||||
{
|
||||
|
@ -1013,6 +1688,8 @@ int gldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len,
|
|||
return gldns_str2wire_int16_data_buf(str, rd, len);
|
||||
case GLDNS_RDF_TYPE_AMTRELAY:
|
||||
return gldns_str2wire_amtrelay_buf(str, rd, len);
|
||||
case GLDNS_RDF_TYPE_SVCPARAM:
|
||||
return gldns_str2wire_svcparam_buf(str, rd, len);
|
||||
case GLDNS_RDF_TYPE_UNKNOWN:
|
||||
case GLDNS_RDF_TYPE_SERVICE:
|
||||
return GLDNS_WIREPARSE_ERR_NOT_IMPL;
|
||||
|
|
|
@ -23,10 +23,27 @@ extern "C" {
|
|||
#endif
|
||||
struct gldns_struct_lookup_table;
|
||||
|
||||
#define GLDNS_IP4ADDRLEN (32/8)
|
||||
#define GLDNS_IP6ADDRLEN (128/8)
|
||||
|
||||
/** buffer to read an RR, cannot be larger than 64K because of packet size */
|
||||
#define GLDNS_RR_BUF_SIZE 65535 /* bytes */
|
||||
#define GLDNS_DEFAULT_TTL 3600
|
||||
|
||||
/* SVCB keys currently defined in draft-ietf-dnsop-svcb-https */
|
||||
#define SVCB_KEY_MANDATORY 0
|
||||
#define SVCB_KEY_ALPN 1
|
||||
#define SVCB_KEY_NO_DEFAULT_ALPN 2
|
||||
#define SVCB_KEY_PORT 3
|
||||
#define SVCB_KEY_IPV4HINT 4
|
||||
#define SVCB_KEY_ECH 5
|
||||
#define SVCB_KEY_IPV6HINT 6
|
||||
#define SVCPARAMKEY_COUNT 7
|
||||
|
||||
#define MAX_NUMBER_OF_SVCPARAMS 64
|
||||
|
||||
#define SVCB_MAX_COMMA_SEPARATED_VALUES 1000
|
||||
|
||||
/*
|
||||
* To convert class and type to string see
|
||||
* gldns_get_rr_class_by_name(str)
|
||||
|
@ -170,7 +187,7 @@ uint8_t* gldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len);
|
|||
#define GLDNS_WIREPARSE_MASK 0x0fff
|
||||
#define GLDNS_WIREPARSE_SHIFT 12
|
||||
#define GLDNS_WIREPARSE_ERROR(e) ((e)&GLDNS_WIREPARSE_MASK)
|
||||
#define GLDNS_WIREPARSE_OFFSET(e) (((e)&~GLDNS_WIREPARSE_MASK)>>GLDNS_WIREPARSE_SHIFT)
|
||||
#define GLDNS_WIREPARSE_OFFSET(e) ((((unsigned)(e))&~GLDNS_WIREPARSE_MASK)>>GLDNS_WIREPARSE_SHIFT)
|
||||
/* use lookuptable to get error string, gldns_wireparse_errors */
|
||||
#define GLDNS_WIREPARSE_ERR_OK 0
|
||||
#define GLDNS_WIREPARSE_ERR_GENERAL 342
|
||||
|
@ -204,6 +221,20 @@ uint8_t* gldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len);
|
|||
#define GLDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW 370
|
||||
#define GLDNS_WIREPARSE_ERR_INCLUDE 371
|
||||
#define GLDNS_WIREPARSE_ERR_PARENTHESIS 372
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_UNKNOWN_KEY 373
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_MISSING_PARAM 374
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_TOO_MANY_PARAMS 375
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_DUPLICATE_KEYS 376
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_TOO_MANY_KEYS 377
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_MISSING_PARAM 378
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_DUPLICATE_KEY 379
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_IN_MANDATORY 380
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_PORT_VALUE_SYNTAX 381
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_IPV4_TOO_MANY_ADDRESSES 382
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_IPV6_TOO_MANY_ADDRESSES 383
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_ALPN_KEY_TOO_LARGE 384
|
||||
#define GLDNS_WIREPARSE_ERR_SVCB_NO_DEFAULT_ALPN_VALUE 385
|
||||
#define GLDNS_WIREPARSE_ERR_SVCPARAM_BROKEN_RDATA 386
|
||||
|
||||
/**
|
||||
* Get reference to a constant string for the (parse) error.
|
||||
|
|
|
@ -151,6 +151,30 @@ static gldns_lookup_table gldns_wireparse_errors_data[] = {
|
|||
{ GLDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW, "Syntax error, integer overflow" },
|
||||
{ GLDNS_WIREPARSE_ERR_INCLUDE, "$INCLUDE directive was seen in the zone" },
|
||||
{ GLDNS_WIREPARSE_ERR_PARENTHESIS, "Parse error, parenthesis mismatch" },
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_UNKNOWN_KEY, "Unknown SvcParamKey"},
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_MISSING_PARAM, "SvcParam is missing a SvcParamValue"},
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_DUPLICATE_KEYS, "Duplicate SVCB key found"},
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_TOO_MANY_KEYS, "Too many keys in mandatory" },
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_TOO_MANY_PARAMS,
|
||||
"Too many SvcParams. Unbound only allows 63 entries" },
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_MISSING_PARAM,
|
||||
"Mandatory SvcParamKey is missing"},
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_DUPLICATE_KEY,
|
||||
"Keys in SvcParam mandatory MUST be unique" },
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_MANDATORY_IN_MANDATORY,
|
||||
"mandatory MUST not be included as mandatory parameter" },
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_PORT_VALUE_SYNTAX,
|
||||
"Could not parse port SvcParamValue" },
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_IPV4_TOO_MANY_ADDRESSES,
|
||||
"Too many IPv4 addresses in ipv4hint" },
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_IPV6_TOO_MANY_ADDRESSES,
|
||||
"Too many IPv6 addresses in ipv6hint" },
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_ALPN_KEY_TOO_LARGE,
|
||||
"Alpn strings need to be smaller than 255 chars"},
|
||||
{ GLDNS_WIREPARSE_ERR_SVCB_NO_DEFAULT_ALPN_VALUE,
|
||||
"No-default-alpn should not have a value" },
|
||||
{ GLDNS_WIREPARSE_ERR_SVCPARAM_BROKEN_RDATA,
|
||||
"General SVCParam error" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
gldns_lookup_table* gldns_wireparse_errors = gldns_wireparse_errors_data;
|
||||
|
@ -198,6 +222,12 @@ static gldns_lookup_table gldns_tsig_errors_data[] = {
|
|||
};
|
||||
gldns_lookup_table* gldns_tsig_errors = gldns_tsig_errors_data;
|
||||
|
||||
/* draft-ietf-dnsop-svcb-https-06: 6. Initial SvcParamKeys */
|
||||
const char *svcparamkey_strs[] = {
|
||||
"mandatory", "alpn", "no-default-alpn", "port",
|
||||
"ipv4hint", "ech", "ipv6hint"
|
||||
};
|
||||
|
||||
char* gldns_wire2str_pkt(uint8_t* data, size_t len)
|
||||
{
|
||||
size_t slen = (size_t)gldns_wire2str_pkt_buf(data, len, NULL, 0);
|
||||
|
@ -789,6 +819,7 @@ int gldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
|
|||
unsigned i, counter=0;
|
||||
unsigned maxcompr = 1000; /* loop detection, max compr ptrs */
|
||||
int in_buf = 1;
|
||||
size_t dname_len = 0;
|
||||
if(comprloop) {
|
||||
if(*comprloop != 0)
|
||||
maxcompr = 30; /* for like ipv6 reverse name, per label */
|
||||
|
@ -844,6 +875,16 @@ int gldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
|
|||
labellen = (uint8_t)*dlen;
|
||||
else if(!in_buf && pos+(size_t)labellen > pkt+pktlen)
|
||||
labellen = (uint8_t)(pkt + pktlen - pos);
|
||||
dname_len += ((size_t)labellen)+1;
|
||||
if(dname_len > GLDNS_MAX_DOMAINLEN) {
|
||||
/* dname_len counts the uncompressed length we have
|
||||
* seen so far, and the domain name has become too
|
||||
* long, prevent the loop from printing overly long
|
||||
* content. */
|
||||
w += gldns_str_print(s, slen,
|
||||
"ErrorDomainNameTooLong");
|
||||
return w;
|
||||
}
|
||||
for(i=0; i<(unsigned)labellen; i++) {
|
||||
w += dname_char_print(s, slen, *pos++);
|
||||
}
|
||||
|
@ -942,6 +983,253 @@ int gldns_wire2str_ttl_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
|
|||
return gldns_str_print(s, slen, "%u", (unsigned)ttl);
|
||||
}
|
||||
|
||||
static int
|
||||
gldns_print_svcparamkey(char** s, size_t* slen, uint16_t svcparamkey)
|
||||
{
|
||||
if (svcparamkey < SVCPARAMKEY_COUNT) {
|
||||
return gldns_str_print(s, slen, "%s", svcparamkey_strs[svcparamkey]);
|
||||
}
|
||||
else {
|
||||
return gldns_str_print(s, slen, "key%d", (int)svcparamkey);
|
||||
}
|
||||
}
|
||||
|
||||
static int gldns_wire2str_svcparam_port2str(char** s,
|
||||
size_t* slen, uint16_t data_len, uint8_t* data)
|
||||
{
|
||||
int w = 0;
|
||||
|
||||
if (data_len != 2)
|
||||
return -1; /* wireformat error, a short is 2 bytes */
|
||||
w = gldns_str_print(s, slen, "=%d", (int)gldns_read_uint16(data));
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static int gldns_wire2str_svcparam_ipv4hint2str(char** s,
|
||||
size_t* slen, uint16_t data_len, uint8_t* data)
|
||||
{
|
||||
char ip_str[INET_ADDRSTRLEN + 1];
|
||||
|
||||
int w = 0;
|
||||
|
||||
assert(data_len > 0);
|
||||
|
||||
if ((data_len % GLDNS_IP4ADDRLEN) == 0) {
|
||||
if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) == NULL)
|
||||
return -1; /* wireformat error, incorrect size or inet family */
|
||||
|
||||
w += gldns_str_print(s, slen, "=%s", ip_str);
|
||||
data += GLDNS_IP4ADDRLEN;
|
||||
|
||||
while ((data_len -= GLDNS_IP4ADDRLEN) > 0) {
|
||||
if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) == NULL)
|
||||
return -1; /* wireformat error, incorrect size or inet family */
|
||||
|
||||
w += gldns_str_print(s, slen, ",%s", ip_str);
|
||||
data += GLDNS_IP4ADDRLEN;
|
||||
}
|
||||
} else
|
||||
return -1;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static int gldns_wire2str_svcparam_ipv6hint2str(char** s,
|
||||
size_t* slen, uint16_t data_len, uint8_t* data)
|
||||
{
|
||||
char ip_str[INET6_ADDRSTRLEN + 1];
|
||||
|
||||
int w = 0;
|
||||
|
||||
assert(data_len > 0);
|
||||
|
||||
if ((data_len % GLDNS_IP6ADDRLEN) == 0) {
|
||||
if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) == NULL)
|
||||
return -1; /* wireformat error, incorrect size or inet family */
|
||||
|
||||
w += gldns_str_print(s, slen, "=%s", ip_str);
|
||||
data += GLDNS_IP6ADDRLEN;
|
||||
|
||||
while ((data_len -= GLDNS_IP6ADDRLEN) > 0) {
|
||||
if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) == NULL)
|
||||
return -1; /* wireformat error, incorrect size or inet family */
|
||||
|
||||
w += gldns_str_print(s, slen, ",%s", ip_str);
|
||||
data += GLDNS_IP6ADDRLEN;
|
||||
}
|
||||
} else
|
||||
return -1;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static int gldns_wire2str_svcparam_mandatory2str(char** s,
|
||||
size_t* slen, uint16_t data_len, uint8_t* data)
|
||||
{
|
||||
int w = 0;
|
||||
|
||||
assert(data_len > 0);
|
||||
|
||||
if (data_len % sizeof(uint16_t))
|
||||
return -1; // wireformat error, data_len must be multiple of shorts
|
||||
w += gldns_str_print(s, slen, "=");
|
||||
w += gldns_print_svcparamkey(s, slen, gldns_read_uint16(data));
|
||||
data += 2;
|
||||
|
||||
while ((data_len -= sizeof(uint16_t))) {
|
||||
w += gldns_str_print(s, slen, ",");
|
||||
w += gldns_print_svcparamkey(s, slen, gldns_read_uint16(data));
|
||||
data += 2;
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static int gldns_wire2str_svcparam_alpn2str(char** s,
|
||||
size_t* slen, uint16_t data_len, uint8_t* data)
|
||||
{
|
||||
uint8_t *dp = (void *)data;
|
||||
int w = 0;
|
||||
|
||||
assert(data_len > 0); /* Guaranteed by gldns_wire2str_svcparam_scan */
|
||||
|
||||
w += gldns_str_print(s, slen, "=\"");
|
||||
while (data_len) {
|
||||
/* alpn is list of length byte (str_len) followed by a string of that size */
|
||||
uint8_t i, str_len = *dp++;
|
||||
|
||||
if (str_len > --data_len)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < str_len; i++) {
|
||||
if (dp[i] == '"' || dp[i] == '\\')
|
||||
w += gldns_str_print(s, slen, "\\\\\\%c", dp[i]);
|
||||
|
||||
else if (dp[i] == ',')
|
||||
w += gldns_str_print(s, slen, "\\\\%c", dp[i]);
|
||||
|
||||
else if (!isprint(dp[i]))
|
||||
w += gldns_str_print(s, slen, "\\%03u", (unsigned) dp[i]);
|
||||
|
||||
else
|
||||
w += gldns_str_print(s, slen, "%c", dp[i]);
|
||||
}
|
||||
dp += str_len;
|
||||
if ((data_len -= str_len))
|
||||
w += gldns_str_print(s, slen, "%s", ",");
|
||||
}
|
||||
w += gldns_str_print(s, slen, "\"");
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static int gldns_wire2str_svcparam_ech2str(char** s,
|
||||
size_t* slen, uint16_t data_len, uint8_t* data)
|
||||
{
|
||||
int size;
|
||||
int w = 0;
|
||||
|
||||
assert(data_len > 0); /* Guaranteed by gldns_wire2str_svcparam_scan */
|
||||
|
||||
w += gldns_str_print(s, slen, "=\"");
|
||||
|
||||
if ((size = gldns_b64_ntop(data, data_len, *s, *slen)) < 0)
|
||||
return -1;
|
||||
|
||||
(*s) += size;
|
||||
(*slen) -= size;
|
||||
|
||||
w += gldns_str_print(s, slen, "\"");
|
||||
|
||||
return w + size;
|
||||
}
|
||||
|
||||
int gldns_wire2str_svcparam_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
|
||||
{
|
||||
uint8_t ch;
|
||||
uint16_t svcparamkey, data_len;
|
||||
int written_chars = 0;
|
||||
int r, i;
|
||||
|
||||
/* verify that we have enough data to read svcparamkey and data_len */
|
||||
if(*dlen < 4)
|
||||
return -1;
|
||||
|
||||
svcparamkey = gldns_read_uint16(*d);
|
||||
data_len = gldns_read_uint16(*d+2);
|
||||
*d += 4;
|
||||
*dlen -= 4;
|
||||
|
||||
/* verify that we have data_len data */
|
||||
if (data_len > *dlen)
|
||||
return -1;
|
||||
|
||||
written_chars += gldns_print_svcparamkey(s, slen, svcparamkey);
|
||||
if (!data_len) {
|
||||
|
||||
/* Some SvcParams MUST have values */
|
||||
switch (svcparamkey) {
|
||||
case SVCB_KEY_ALPN:
|
||||
case SVCB_KEY_PORT:
|
||||
case SVCB_KEY_IPV4HINT:
|
||||
case SVCB_KEY_IPV6HINT:
|
||||
case SVCB_KEY_MANDATORY:
|
||||
return -1;
|
||||
default:
|
||||
return written_chars;
|
||||
}
|
||||
}
|
||||
|
||||
switch (svcparamkey) {
|
||||
case SVCB_KEY_PORT:
|
||||
r = gldns_wire2str_svcparam_port2str(s, slen, data_len, *d);
|
||||
break;
|
||||
case SVCB_KEY_IPV4HINT:
|
||||
r = gldns_wire2str_svcparam_ipv4hint2str(s, slen, data_len, *d);
|
||||
break;
|
||||
case SVCB_KEY_IPV6HINT:
|
||||
r = gldns_wire2str_svcparam_ipv6hint2str(s, slen, data_len, *d);
|
||||
break;
|
||||
case SVCB_KEY_MANDATORY:
|
||||
r = gldns_wire2str_svcparam_mandatory2str(s, slen, data_len, *d);
|
||||
break;
|
||||
case SVCB_KEY_NO_DEFAULT_ALPN:
|
||||
return -1; /* wireformat error, should not have a value */
|
||||
case SVCB_KEY_ALPN:
|
||||
r = gldns_wire2str_svcparam_alpn2str(s, slen, data_len, *d);
|
||||
break;
|
||||
case SVCB_KEY_ECH:
|
||||
r = gldns_wire2str_svcparam_ech2str(s, slen, data_len, *d);
|
||||
break;
|
||||
default:
|
||||
r = gldns_str_print(s, slen, "=\"");
|
||||
|
||||
for (i = 0; i < data_len; i++) {
|
||||
ch = (*d)[i];
|
||||
|
||||
if (ch == '"' || ch == '\\')
|
||||
r += gldns_str_print(s, slen, "\\%c", ch);
|
||||
|
||||
else if (!isprint(ch))
|
||||
r += gldns_str_print(s, slen, "\\%03u", (unsigned) ch);
|
||||
|
||||
else
|
||||
r += gldns_str_print(s, slen, "%c", ch);
|
||||
|
||||
}
|
||||
r += gldns_str_print(s, slen, "\"");
|
||||
break;
|
||||
}
|
||||
if (r <= 0)
|
||||
return -1; /* wireformat error */
|
||||
|
||||
written_chars += r;
|
||||
*d += data_len;
|
||||
*dlen -= data_len;
|
||||
return written_chars;
|
||||
}
|
||||
|
||||
int gldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
|
||||
int rdftype, uint8_t* pkt, size_t pktlen, int* comprloop)
|
||||
{
|
||||
|
@ -1022,6 +1310,8 @@ int gldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
|
|||
case GLDNS_RDF_TYPE_AMTRELAY:
|
||||
return gldns_wire2str_amtrelay_scan(d, dlen, s, slen, pkt,
|
||||
pktlen, comprloop);
|
||||
case GLDNS_RDF_TYPE_SVCPARAM:
|
||||
return gldns_wire2str_svcparam_scan(d, dlen, s, slen);
|
||||
case GLDNS_RDF_TYPE_TSIGERROR:
|
||||
return gldns_wire2str_tsigerror_scan(d, dlen, s, slen);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ char* gldns_wire2str_pkt(uint8_t* data, size_t len);
|
|||
char* gldns_wire2str_rr(uint8_t* rr, size_t len);
|
||||
|
||||
/**
|
||||
* Conver wire dname to a string.
|
||||
* Convert wire dname to a string.
|
||||
* @param dname: the dname in uncompressed wireformat.
|
||||
* @param dname_len: length of the dname.
|
||||
* @return string or NULL on failure.
|
||||
|
@ -494,6 +494,18 @@ int gldns_wire2str_opcode_buf(int opcode, char* str, size_t len);
|
|||
int gldns_wire2str_dname_buf(uint8_t* dname, size_t dname_len, char* str,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* Convert wire SVCB to a string with user buffer.
|
||||
* @param d: the SVCB data in uncompressed wireformat.
|
||||
* @param dlen: length of the SVCB data.
|
||||
* @param s: the string to write to.
|
||||
* @param slen: length of string.
|
||||
* @return the number of characters for this element, excluding zerobyte.
|
||||
* Is larger or equal than str_len if output was truncated.
|
||||
*/
|
||||
int gldns_wire2str_svcparam_scan(uint8_t** d, size_t* dlen, char** s,
|
||||
size_t* slen);
|
||||
|
||||
/**
|
||||
* Scan wireformat rdf field to string, with user buffers.
|
||||
* It shifts the arguments to move along (see gldns_wire2str_pkt_scan).
|
||||
|
|
|
@ -29,12 +29,19 @@
|
|||
#ifdef HAVE_OPENSSL_BN_H
|
||||
#include <openssl/bn.h>
|
||||
#endif
|
||||
#ifdef HAVE_OPENSSL_PARAM_BUILD_H
|
||||
# include <openssl/param_build.h>
|
||||
#else
|
||||
# ifdef HAVE_OPENSSL_RSA_H
|
||||
# include <openssl/rsa.h>
|
||||
# endif
|
||||
# ifdef HAVE_OPENSSL_DSA_H
|
||||
# include <openssl/dsa.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_OPENSSL_DSA_H
|
||||
#include <openssl/dsa.h>
|
||||
#endif
|
||||
#ifdef HAVE_OPENSSL_RSA_H
|
||||
#include <openssl/rsa.h>
|
||||
#endif
|
||||
|
@ -77,6 +84,7 @@ gldns_key_EVP_load_gost_id(void)
|
|||
if(!e) {
|
||||
/* load it ourself, in case statically linked */
|
||||
ENGINE_load_builtin_engines();
|
||||
ENGINE_load_dynamic();
|
||||
e = ENGINE_by_id("gost");
|
||||
}
|
||||
if(!e) {
|
||||
|
@ -115,49 +123,71 @@ void gldns_key_EVP_unload_gost(void)
|
|||
#endif /* ifndef OPENSSL_NO_ENGINE */
|
||||
#endif /* USE_GOST */
|
||||
|
||||
DSA *
|
||||
gldns_key_buf2dsa_raw(unsigned char* key, size_t len)
|
||||
/* Retrieve params as BIGNUM from raw buffer */
|
||||
static int
|
||||
gldns_key_dsa_buf_bignum(unsigned char* key, size_t len, BIGNUM** p,
|
||||
BIGNUM** q, BIGNUM** g, BIGNUM** y)
|
||||
{
|
||||
uint8_t T;
|
||||
uint16_t length;
|
||||
uint16_t offset;
|
||||
DSA *dsa;
|
||||
BIGNUM *Q; BIGNUM *P;
|
||||
BIGNUM *G; BIGNUM *Y;
|
||||
|
||||
if(len == 0)
|
||||
return NULL;
|
||||
return 0;
|
||||
T = (uint8_t)key[0];
|
||||
length = (64 + T * 8);
|
||||
offset = 1;
|
||||
|
||||
if (T > 8) {
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length)
|
||||
return NULL;
|
||||
return 0;
|
||||
|
||||
Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL);
|
||||
*q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL);
|
||||
offset += SHA_DIGEST_LENGTH;
|
||||
|
||||
P = BN_bin2bn(key+offset, (int)length, NULL);
|
||||
*p = BN_bin2bn(key+offset, (int)length, NULL);
|
||||
offset += length;
|
||||
|
||||
G = BN_bin2bn(key+offset, (int)length, NULL);
|
||||
*g = BN_bin2bn(key+offset, (int)length, NULL);
|
||||
offset += length;
|
||||
|
||||
Y = BN_bin2bn(key+offset, (int)length, NULL);
|
||||
*y = BN_bin2bn(key+offset, (int)length, NULL);
|
||||
|
||||
/* create the key and set its properties */
|
||||
if(!Q || !P || !G || !Y || !(dsa = DSA_new())) {
|
||||
BN_free(Q);
|
||||
BN_free(P);
|
||||
BN_free(G);
|
||||
BN_free(Y);
|
||||
return NULL;
|
||||
if(!*q || !*p || !*g || !*y) {
|
||||
BN_free(*q);
|
||||
BN_free(*p);
|
||||
BN_free(*g);
|
||||
BN_free(*y);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_DSA_SET0_PQG) && defined(HAVE_DSA_SET0_KEY)
|
||||
#ifndef HAVE_OSSL_PARAM_BLD_NEW
|
||||
DSA *
|
||||
gldns_key_buf2dsa_raw(unsigned char* key, size_t len)
|
||||
{
|
||||
DSA *dsa;
|
||||
BIGNUM *Q=NULL, *P=NULL, *G=NULL, *Y=NULL;
|
||||
if(!gldns_key_dsa_buf_bignum(key, len, &P, &Q, &G, &Y)) {
|
||||
return NULL;
|
||||
}
|
||||
/* create the key and set its properties */
|
||||
if(!(dsa = DSA_new())) {
|
||||
return NULL;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || \
|
||||
(defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x02070000f)
|
||||
#ifndef S_SPLINT_S
|
||||
dsa->p = P;
|
||||
dsa->q = Q;
|
||||
dsa->g = G;
|
||||
dsa->pub_key = Y;
|
||||
#endif /* splint */
|
||||
|
||||
#else /* OPENSSL_VERSION_NUMBER */
|
||||
if (!DSA_set0_pqg(dsa, P, Q, G)) {
|
||||
/* QPG not yet attached, need to free */
|
||||
BN_free(Q);
|
||||
|
@ -174,33 +204,115 @@ gldns_key_buf2dsa_raw(unsigned char* key, size_t len)
|
|||
BN_free(Y);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
# ifndef S_SPLINT_S
|
||||
dsa->p = P;
|
||||
dsa->q = Q;
|
||||
dsa->g = G;
|
||||
dsa->pub_key = Y;
|
||||
# endif /* splint */
|
||||
#endif
|
||||
|
||||
return dsa;
|
||||
}
|
||||
#endif /* HAVE_OSSL_PARAM_BLD_NEW */
|
||||
|
||||
RSA *
|
||||
gldns_key_buf2rsa_raw(unsigned char* key, size_t len)
|
||||
EVP_PKEY *gldns_key_dsa2pkey_raw(unsigned char* key, size_t len)
|
||||
{
|
||||
#ifdef HAVE_OSSL_PARAM_BLD_NEW
|
||||
EVP_PKEY* evp_key = NULL;
|
||||
EVP_PKEY_CTX* ctx;
|
||||
BIGNUM *p=NULL, *q=NULL, *g=NULL, *y=NULL;
|
||||
OSSL_PARAM_BLD* param_bld;
|
||||
OSSL_PARAM* params = NULL;
|
||||
if(!gldns_key_dsa_buf_bignum(key, len, &p, &q, &g, &y)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
param_bld = OSSL_PARAM_BLD_new();
|
||||
if(!param_bld) {
|
||||
BN_free(p);
|
||||
BN_free(q);
|
||||
BN_free(g);
|
||||
BN_free(y);
|
||||
return NULL;
|
||||
}
|
||||
if(!OSSL_PARAM_BLD_push_BN(param_bld, "p", p) ||
|
||||
!OSSL_PARAM_BLD_push_BN(param_bld, "g", g) ||
|
||||
!OSSL_PARAM_BLD_push_BN(param_bld, "q", q) ||
|
||||
!OSSL_PARAM_BLD_push_BN(param_bld, "pub", y)) {
|
||||
OSSL_PARAM_BLD_free(param_bld);
|
||||
BN_free(p);
|
||||
BN_free(q);
|
||||
BN_free(g);
|
||||
BN_free(y);
|
||||
return NULL;
|
||||
}
|
||||
params = OSSL_PARAM_BLD_to_param(param_bld);
|
||||
OSSL_PARAM_BLD_free(param_bld);
|
||||
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL);
|
||||
if(!ctx) {
|
||||
OSSL_PARAM_free(params);
|
||||
BN_free(p);
|
||||
BN_free(q);
|
||||
BN_free(g);
|
||||
BN_free(y);
|
||||
return NULL;
|
||||
}
|
||||
if(EVP_PKEY_fromdata_init(ctx) <= 0) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
BN_free(p);
|
||||
BN_free(q);
|
||||
BN_free(g);
|
||||
BN_free(y);
|
||||
return NULL;
|
||||
}
|
||||
if(EVP_PKEY_fromdata(ctx, &evp_key, EVP_PKEY_PUBLIC_KEY, params) <= 0) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
BN_free(p);
|
||||
BN_free(q);
|
||||
BN_free(g);
|
||||
BN_free(y);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
BN_free(p);
|
||||
BN_free(q);
|
||||
BN_free(g);
|
||||
BN_free(y);
|
||||
return evp_key;
|
||||
#else
|
||||
DSA* dsa;
|
||||
EVP_PKEY* evp_key = EVP_PKEY_new();
|
||||
if(!evp_key) {
|
||||
return NULL;
|
||||
}
|
||||
dsa = gldns_key_buf2dsa_raw(key, len);
|
||||
if(!dsa) {
|
||||
EVP_PKEY_free(evp_key);
|
||||
return NULL;
|
||||
}
|
||||
if(EVP_PKEY_assign_DSA(evp_key, dsa) == 0) {
|
||||
DSA_free(dsa);
|
||||
EVP_PKEY_free(evp_key);
|
||||
return NULL;
|
||||
}
|
||||
return evp_key;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Retrieve params as BIGNUM from raw buffer, n is modulus, e is exponent */
|
||||
static int
|
||||
gldns_key_rsa_buf_bignum(unsigned char* key, size_t len, BIGNUM** n,
|
||||
BIGNUM** e)
|
||||
{
|
||||
uint16_t offset;
|
||||
uint16_t exp;
|
||||
uint16_t int16;
|
||||
RSA *rsa;
|
||||
BIGNUM *modulus;
|
||||
BIGNUM *exponent;
|
||||
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
return 0;
|
||||
if (key[0] == 0) {
|
||||
if(len < 3)
|
||||
return NULL;
|
||||
return 0;
|
||||
memmove(&int16, key+1, 2);
|
||||
exp = ntohs(int16);
|
||||
offset = 3;
|
||||
|
@ -211,46 +323,140 @@ gldns_key_buf2rsa_raw(unsigned char* key, size_t len)
|
|||
|
||||
/* key length at least one */
|
||||
if(len < (size_t)offset + exp + 1)
|
||||
return NULL;
|
||||
return 0;
|
||||
|
||||
/* Exponent */
|
||||
exponent = BN_new();
|
||||
if(!exponent) return NULL;
|
||||
(void) BN_bin2bn(key+offset, (int)exp, exponent);
|
||||
*e = BN_new();
|
||||
if(!*e) return 0;
|
||||
(void) BN_bin2bn(key+offset, (int)exp, *e);
|
||||
offset += exp;
|
||||
|
||||
/* Modulus */
|
||||
modulus = BN_new();
|
||||
if(!modulus) {
|
||||
BN_free(exponent);
|
||||
return NULL;
|
||||
*n = BN_new();
|
||||
if(!*n) {
|
||||
BN_free(*e);
|
||||
return 0;
|
||||
}
|
||||
/* length of the buffer must match the key length! */
|
||||
(void) BN_bin2bn(key+offset, (int)(len - offset), modulus);
|
||||
(void) BN_bin2bn(key+offset, (int)(len - offset), *n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef HAVE_OSSL_PARAM_BLD_NEW
|
||||
RSA *
|
||||
gldns_key_buf2rsa_raw(unsigned char* key, size_t len)
|
||||
{
|
||||
BIGNUM* modulus = NULL;
|
||||
BIGNUM* exponent = NULL;
|
||||
RSA *rsa;
|
||||
if(!gldns_key_rsa_buf_bignum(key, len, &modulus, &exponent))
|
||||
return NULL;
|
||||
rsa = RSA_new();
|
||||
if(!rsa) {
|
||||
BN_free(exponent);
|
||||
BN_free(modulus);
|
||||
return NULL;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || \
|
||||
(defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x02070000f)
|
||||
#ifndef S_SPLINT_S
|
||||
rsa->n = modulus;
|
||||
rsa->e = exponent;
|
||||
#endif /* splint */
|
||||
|
||||
#if defined(HAVE_RSA_SET0_KEY)
|
||||
#else /* OPENSSL_VERSION_NUMBER */
|
||||
if (!RSA_set0_key(rsa, modulus, exponent, NULL)) {
|
||||
BN_free(exponent);
|
||||
BN_free(modulus);
|
||||
RSA_free(rsa);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
# ifndef S_SPLINT_S
|
||||
rsa->n = modulus;
|
||||
rsa->e = exponent;
|
||||
# endif /* splint */
|
||||
#endif
|
||||
|
||||
return rsa;
|
||||
}
|
||||
#endif /* HAVE_OSSL_PARAM_BLD_NEW */
|
||||
|
||||
EVP_PKEY* gldns_key_rsa2pkey_raw(unsigned char* key, size_t len)
|
||||
{
|
||||
#ifdef HAVE_OSSL_PARAM_BLD_NEW
|
||||
EVP_PKEY* evp_key = NULL;
|
||||
EVP_PKEY_CTX* ctx;
|
||||
BIGNUM *n=NULL, *e=NULL;
|
||||
OSSL_PARAM_BLD* param_bld;
|
||||
OSSL_PARAM* params = NULL;
|
||||
|
||||
if(!gldns_key_rsa_buf_bignum(key, len, &n, &e)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
param_bld = OSSL_PARAM_BLD_new();
|
||||
if(!param_bld) {
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
return NULL;
|
||||
}
|
||||
if(!OSSL_PARAM_BLD_push_BN(param_bld, "n", n)) {
|
||||
OSSL_PARAM_BLD_free(param_bld);
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
return NULL;
|
||||
}
|
||||
if(!OSSL_PARAM_BLD_push_BN(param_bld, "e", e)) {
|
||||
OSSL_PARAM_BLD_free(param_bld);
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
return NULL;
|
||||
}
|
||||
params = OSSL_PARAM_BLD_to_param(param_bld);
|
||||
OSSL_PARAM_BLD_free(param_bld);
|
||||
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
|
||||
if(!ctx) {
|
||||
OSSL_PARAM_free(params);
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
return NULL;
|
||||
}
|
||||
if(EVP_PKEY_fromdata_init(ctx) <= 0) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
return NULL;
|
||||
}
|
||||
if(EVP_PKEY_fromdata(ctx, &evp_key, EVP_PKEY_PUBLIC_KEY, params) <= 0) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
return evp_key;
|
||||
#else
|
||||
RSA* rsa;
|
||||
EVP_PKEY *evp_key = EVP_PKEY_new();
|
||||
if(!evp_key) {
|
||||
return NULL;
|
||||
}
|
||||
rsa = gldns_key_buf2rsa_raw(key, len);
|
||||
if(!rsa) {
|
||||
EVP_PKEY_free(evp_key);
|
||||
return NULL;
|
||||
}
|
||||
if(EVP_PKEY_assign_RSA(evp_key, rsa) == 0) {
|
||||
RSA_free(rsa);
|
||||
EVP_PKEY_free(evp_key);
|
||||
return NULL;
|
||||
}
|
||||
return evp_key;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_GOST
|
||||
EVP_PKEY*
|
||||
|
@ -281,6 +487,62 @@ gldns_gost2pkey_raw(unsigned char* key, size_t keylen)
|
|||
EVP_PKEY*
|
||||
gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo)
|
||||
{
|
||||
#ifdef HAVE_OSSL_PARAM_BLD_NEW
|
||||
unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
|
||||
EVP_PKEY *evp_key = NULL;
|
||||
EVP_PKEY_CTX* ctx;
|
||||
OSSL_PARAM_BLD* param_bld;
|
||||
OSSL_PARAM* params = NULL;
|
||||
char* group = NULL;
|
||||
|
||||
/* check length, which uncompressed must be 2 bignums */
|
||||
if(algo == GLDNS_ECDSAP256SHA256) {
|
||||
if(keylen != 2*256/8) return NULL;
|
||||
group = "prime256v1";
|
||||
} else if(algo == GLDNS_ECDSAP384SHA384) {
|
||||
if(keylen != 2*384/8) return NULL;
|
||||
group = "P-384";
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
if(keylen+1 > sizeof(buf)) { /* sanity check */
|
||||
return NULL;
|
||||
}
|
||||
/* prepend the 0x04 for uncompressed format */
|
||||
buf[0] = POINT_CONVERSION_UNCOMPRESSED;
|
||||
memmove(buf+1, key, keylen);
|
||||
|
||||
param_bld = OSSL_PARAM_BLD_new();
|
||||
if(!param_bld) {
|
||||
return NULL;
|
||||
}
|
||||
if(!OSSL_PARAM_BLD_push_utf8_string(param_bld, "group", group, 0) ||
|
||||
!OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", buf, keylen+1)) {
|
||||
OSSL_PARAM_BLD_free(param_bld);
|
||||
return NULL;
|
||||
}
|
||||
params = OSSL_PARAM_BLD_to_param(param_bld);
|
||||
OSSL_PARAM_BLD_free(param_bld);
|
||||
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
|
||||
if(!ctx) {
|
||||
OSSL_PARAM_free(params);
|
||||
return NULL;
|
||||
}
|
||||
if(EVP_PKEY_fromdata_init(ctx) <= 0) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
return NULL;
|
||||
}
|
||||
if(EVP_PKEY_fromdata(ctx, &evp_key, EVP_PKEY_PUBLIC_KEY, params) <= 0) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
return NULL;
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
return evp_key;
|
||||
#else
|
||||
unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
|
||||
const unsigned char* pp = buf;
|
||||
EVP_PKEY *evp_key;
|
||||
|
@ -317,6 +579,7 @@ gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo)
|
|||
return NULL;
|
||||
}
|
||||
return evp_key;
|
||||
#endif /* HAVE_OSSL_PARAM_BLD_NEW */
|
||||
}
|
||||
#endif /* USE_ECDSA */
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ int gldns_key_EVP_load_gost_id(void);
|
|||
/** Release the engine reference held for the GOST engine. */
|
||||
void gldns_key_EVP_unload_gost(void);
|
||||
|
||||
#ifndef HAVE_OSSL_PARAM_BLD_NEW
|
||||
/**
|
||||
* Like gldns_key_buf2dsa, but uses raw buffer.
|
||||
* \param[in] key the uncompressed wireformat of the key.
|
||||
|
@ -44,6 +45,15 @@ void gldns_key_EVP_unload_gost(void);
|
|||
* \return a DSA * structure with the key material
|
||||
*/
|
||||
DSA *gldns_key_buf2dsa_raw(unsigned char* key, size_t len);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Converts a holding buffer with DSA key material to EVP PKEY in openssl.
|
||||
* \param[in] key the uncompressed wireformat of the key.
|
||||
* \param[in] len length of key data
|
||||
* \return the key or NULL on error.
|
||||
*/
|
||||
EVP_PKEY *gldns_key_dsa2pkey_raw(unsigned char* key, size_t len);
|
||||
|
||||
/**
|
||||
* Converts a holding buffer with key material to EVP PKEY in openssl.
|
||||
|
@ -64,6 +74,7 @@ EVP_PKEY* gldns_gost2pkey_raw(unsigned char* key, size_t keylen);
|
|||
*/
|
||||
EVP_PKEY* gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo);
|
||||
|
||||
#ifndef HAVE_OSSL_PARAM_BLD_NEW
|
||||
/**
|
||||
* Like gldns_key_buf2rsa, but uses raw buffer.
|
||||
* \param[in] key the uncompressed wireformat of the key.
|
||||
|
@ -71,6 +82,15 @@ EVP_PKEY* gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo);
|
|||
* \return a RSA * structure with the key material
|
||||
*/
|
||||
RSA *gldns_key_buf2rsa_raw(unsigned char* key, size_t len);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Converts a holding buffer with RSA key material to EVP PKEY in openssl.
|
||||
* \param[in] key the uncompressed wireformat of the key.
|
||||
* \param[in] len length of key data
|
||||
* \return the key or NULL on error.
|
||||
*/
|
||||
EVP_PKEY* gldns_key_rsa2pkey_raw(unsigned char* key, size_t len);
|
||||
|
||||
/**
|
||||
* Converts a holding buffer with key material to EVP PKEY in openssl.
|
||||
|
|
|
@ -514,29 +514,13 @@ static int
|
|||
setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
|
||||
unsigned char* key, size_t keylen)
|
||||
{
|
||||
#if defined(USE_DSA) && defined(USE_SHA1)
|
||||
DSA* dsa;
|
||||
#endif
|
||||
RSA* rsa;
|
||||
|
||||
switch(algo) {
|
||||
#if defined(USE_DSA) && defined(USE_SHA1)
|
||||
case LDNS_DSA:
|
||||
case LDNS_DSA_NSEC3:
|
||||
*evp_key = EVP_PKEY_new();
|
||||
*evp_key = sldns_key_dsa2pkey_raw(key, keylen);
|
||||
if(!*evp_key) {
|
||||
log_err("verify: malloc failure in crypto");
|
||||
return 0;
|
||||
}
|
||||
dsa = sldns_key_buf2dsa_raw(key, keylen);
|
||||
if(!dsa) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
"sldns_key_buf2dsa_raw failed");
|
||||
return 0;
|
||||
}
|
||||
if(EVP_PKEY_assign_DSA(*evp_key, dsa) == 0) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
"EVP_PKEY_assign_DSA failed");
|
||||
verbose(VERB_QUERY, "verify: sldns_key_dsa2pkey failed");
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_EVP_DSS1
|
||||
|
@ -559,20 +543,9 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
|
|||
#if defined(HAVE_EVP_SHA512) && defined(USE_SHA2)
|
||||
case LDNS_RSASHA512:
|
||||
#endif
|
||||
*evp_key = EVP_PKEY_new();
|
||||
*evp_key = sldns_key_rsa2pkey_raw(key, keylen);
|
||||
if(!*evp_key) {
|
||||
log_err("verify: malloc failure in crypto");
|
||||
return 0;
|
||||
}
|
||||
rsa = sldns_key_buf2rsa_raw(key, keylen);
|
||||
if(!rsa) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
"sldns_key_buf2rsa_raw SHA failed");
|
||||
return 0;
|
||||
}
|
||||
if(EVP_PKEY_assign_RSA(*evp_key, rsa) == 0) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
"EVP_PKEY_assign_RSA SHA failed");
|
||||
verbose(VERB_QUERY, "verify: sldns_key_rsa2pkey SHA failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -596,20 +569,9 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
|
|||
#endif /* defined(USE_SHA1) || (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2)) */
|
||||
|
||||
case LDNS_RSAMD5:
|
||||
*evp_key = EVP_PKEY_new();
|
||||
*evp_key = sldns_key_rsa2pkey_raw(key, keylen);
|
||||
if(!*evp_key) {
|
||||
log_err("verify: malloc failure in crypto");
|
||||
return 0;
|
||||
}
|
||||
rsa = sldns_key_buf2rsa_raw(key, keylen);
|
||||
if(!rsa) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
"sldns_key_buf2rsa_raw MD5 failed");
|
||||
return 0;
|
||||
}
|
||||
if(EVP_PKEY_assign_RSA(*evp_key, rsa) == 0) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
"EVP_PKEY_assign_RSA MD5 failed");
|
||||
verbose(VERB_QUERY, "verify: sldns_key_rsa2pkey MD5 failed");
|
||||
return 0;
|
||||
}
|
||||
*digest_type = EVP_md5();
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
#define sldns_ecdsa2pkey_raw gldns_ecdsa2pkey_raw
|
||||
#define sldns_buffer_begin gldns_buffer_begin
|
||||
#define sldns_buffer_limit gldns_buffer_limit
|
||||
#define sldns_key_dsa2pkey_raw gldns_key_dsa2pkey_raw
|
||||
#define sldns_key_rsa2pkey_raw gldns_key_rsa2pkey_raw
|
||||
|
||||
#include "util/val_secalgo.h"
|
||||
|
||||
|
|
|
@ -54,6 +54,11 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy.
|
|||
#include <stdio.h> /* defines printf for tests */
|
||||
#include <time.h> /* defines time_t for timings in the test */
|
||||
|
||||
/*
|
||||
* If our build system provides endianness info, signalled by
|
||||
* HAVE_TARGET_ENDIANNESS and the presence or absence of TARGET_IS_BIG_ENDIAN,
|
||||
* use that. Otherwise try to work out the endianness.
|
||||
*/
|
||||
#if defined(HAVE_TARGET_ENDIANNESS)
|
||||
# if defined(TARGET_IS_BIG_ENDIAN)
|
||||
# define HASH_LITTLE_ENDIAN 0
|
||||
|
@ -63,9 +68,55 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy.
|
|||
# define HASH_BIG_ENDIAN 0
|
||||
# endif
|
||||
#else
|
||||
# error "Target endianness required."
|
||||
# include <sys/param.h> /* attempt to define endianness */
|
||||
# ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h> /* attempt to define endianness (solaris) */
|
||||
# endif
|
||||
# if defined(linux) || defined(__OpenBSD__)
|
||||
# ifdef HAVE_ENDIAN_H
|
||||
# include <endian.h> /* attempt to define endianness */
|
||||
# else
|
||||
# include <machine/endian.h> /* on older OpenBSD */
|
||||
# endif
|
||||
# endif
|
||||
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
||||
# include <sys/endian.h> /* attempt to define endianness */
|
||||
# endif
|
||||
/*
|
||||
* My best guess at if you are big-endian or little-endian. This may
|
||||
* need adjustment.
|
||||
*/
|
||||
# if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
|
||||
__BYTE_ORDER == __LITTLE_ENDIAN) || \
|
||||
(defined(i386) || defined(__i386__) || defined(__i486__) || \
|
||||
defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL) || defined(__x86))
|
||||
# define HASH_LITTLE_ENDIAN 1
|
||||
# define HASH_BIG_ENDIAN 0
|
||||
# elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
|
||||
__BYTE_ORDER == __BIG_ENDIAN) || \
|
||||
(defined(sparc) || defined(__sparc) || defined(__sparc__) || defined(POWERPC) || defined(mc68000) || defined(sel))
|
||||
# define HASH_LITTLE_ENDIAN 0
|
||||
# define HASH_BIG_ENDIAN 1
|
||||
# elif defined(_MACHINE_ENDIAN_H_)
|
||||
/* test for machine_endian_h protects failure if some are empty strings */
|
||||
# if defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && _BYTE_ORDER == _BIG_ENDIAN
|
||||
# define HASH_LITTLE_ENDIAN 0
|
||||
# define HASH_BIG_ENDIAN 1
|
||||
# endif
|
||||
# if defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
# define HASH_LITTLE_ENDIAN 1
|
||||
# define HASH_BIG_ENDIAN 0
|
||||
# endif /* _MACHINE_ENDIAN_H_ */
|
||||
# else
|
||||
# define HASH_LITTLE_ENDIAN 0
|
||||
# define HASH_BIG_ENDIAN 0
|
||||
# endif
|
||||
#endif /* defined(HAVE_TARGET_ENDIANNESS) */
|
||||
|
||||
#define hashsize(n) ((uint32_t)1<<(n))
|
||||
#define hashmask(n) (hashsize(n)-1)
|
||||
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
|
||||
|
||||
/* random initial value */
|
||||
static uint32_t raninit = (uint32_t)0xdeadbeef;
|
||||
|
||||
|
@ -75,10 +126,6 @@ hash_set_raninit(uint32_t v)
|
|||
raninit = v;
|
||||
}
|
||||
|
||||
#define hashsize(n) ((uint32_t)1<<(n))
|
||||
#define hashmask(n) (hashsize(n)-1)
|
||||
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
mix -- mix 3 32-bit values reversibly.
|
||||
|
|
Loading…
Reference in New Issue