/*++ /* NAME /* tls_dane 3 /* SUMMARY /* Support for RFC 6698, 7671, 7672 (DANE) certificate matching /* SYNOPSIS /* #include <tls.h> /* /* void tls_dane_loglevel(log_param, log_level); /* const char *log_param; /* const char *log_level; /* /* int tls_dane_avail() /* /* void tls_dane_flush() /* /* TLS_DANE *tls_dane_alloc() /* /* void tls_tlsa_free(tlsa) /* TLS_TLSA *tlsa; /* /* void tls_dane_free(dane) /* TLS_DANE *dane; /* /* void tls_dane_add_fpt_digests(dane, pkey_only, digest, delim, smtp_mode) /* TLS_DANE *dane; /* int pkey_only; /* const char *digest; /* const char *delim; /* int smtp_mode; /* /* TLS_TLSA *tlsa_prepend(tlsa, usage, selector, mtype, data, len) /* TLS_TLSA *tlsa; /* uint8_t usage; /* uint8_t selector; /* uint8_t mtype; /* const unsigned char *data; /* uint16_t length; /* /* int tls_dane_load_trustfile(dane, tafile) /* TLS_DANE *dane; /* const char *tafile; /* /* TLS_DANE *tls_dane_resolve(port, proto, hostrr, forcetlsa) /* unsigned port; /* const char *proto; /* DNS_RR *hostrr; /* int forcetlsa; /* /* void tls_dane_digest_init(ctx, fpt_alg) /* SSL_CTX *ctx; /* const EVP_MD *fpt_alg; /* /* void tls_dane_enable(TLScontext) /* TLS_SESS_STATE *TLScontext; /* /* void tls_dane_log(TLScontext) /* TLS_SESS_STATE *TLScontext; /* /* int tls_dane_unusable(dane) /* const TLS_DANE *dane; /* /* int tls_dane_notfound(dane) /* const TLS_DANE *dane; /* DESCRIPTION /* tls_dane_loglevel() allows the policy lookup functions in the DANE /* library to examine the application's TLS loglevel in and possibly /* produce a more detailed activity log. /* /* tls_dane_avail() returns true if the features required to support DANE /* are present in libresolv. /* /* tls_dane_flush() flushes all entries from the cache, and deletes /* the cache. /* /* tls_dane_alloc() returns a pointer to a newly allocated TLS_DANE /* structure with null ta and ee digest sublists. /* /* tls_tlsa_free() frees a TLSA record linked list. /* /* tls_dane_free() frees the structure allocated by tls_dane_alloc(). /* /* tls_dane_digest_init() configures OpenSSL to support the configured /* DANE TLSA digests and private-use fingerprint digest. /* /* tlsa_prepend() prepends a TLSA record to the head of a linked list /* which may be null when the list is empty. The result value is the /* new list head. /* /* tls_dane_add_fpt_digests() splits "digest" using the characters in /* "delim" as delimiters and generates corresponding synthetic DANE TLSA /* records with matching type 255 (private-use), which we associated with /* the configured fingerprint digest algorithm. This is an incremental /* interface, that builds a TLS_DANE structure outside the cache by /* manually adding entries. /* /* tls_dane_load_trustfile() imports trust-anchor certificates and /* public keys from a file (rather than DNS TLSA records). /* /* tls_dane_resolve() maps a (port, protocol, hostrr) tuple to a /* corresponding TLS_DANE policy structure found in the DNS. The port /* argument is in network byte order. A null pointer is returned when /* the DNS query for the TLSA record tempfailed. In all other cases the /* return value is a pointer to the corresponding TLS_DANE structure. /* The caller must free the structure via tls_dane_free(). /* /* tls_dane_enable() enables DANE-style certificate checks for connections /* that are configured with TLSA records. The TLSA records may be from /* DNS (at the "dane", "dane-only" and "half-dane" security levels), or be /* synthetic in support of either the "fingerprint" level or local trust /* anchor based validation with the "secure" and "verify" levels. The /* return value is the number of "usable" TLSA records loaded, or negative /* if a record failed to load due to an internal OpenSSL problems, rather /* than an issue with the record making that record "unusable". /* /* tls_dane_log() logs successful verification via DNS-based or /* synthetic DANE TLSA RRs (fingerprint or "tafile"). /* /* tls_dane_unusable() checks whether a cached TLS_DANE record is /* the result of a validated RRset, with no usable elements. In /* this case, TLS is mandatory, but certificate verification is /* not DANE-based. /* /* tls_dane_notfound() checks whether a cached TLS_DANE record is /* the result of a validated DNS lookup returning NODATA. In /* this case, TLS is not required by RFC, though users may elect /* a mandatory TLS fallback policy. /* /* Arguments: /* .IP ctx /* SSL context to be configured with the chosen digest algorithms. /* .IP fpt_alg /* The OpenSSL EVP digest algorithm handle for the fingerprint digest. /* .IP pkey_only /* When true, generate "fingerprint" TLSA records for just the public /* keys. Otherwise, for both certificates and public keys. /* .IP tlsa /* TLSA record linked list head, initially NULL. /* .IP usage /* DANE TLSA certificate usage field. /* .IP selector /* DANE TLSA selector field. /* .IP mtype /* DANE TLSA matching type field /* .IP data /* DANE TLSA associated data field (raw binary form), copied for internal /* use. The caller is responsible for freeing his own copy. /* .IP length /* Length of DANE TLSA associated DATA field. /* .IP dane /* Pointer to a TLS_DANE structure that lists the valid trust-anchor /* and end-entity full-certificate and/or public-key digests. /* .IP port /* The TCP port in network byte order. /* .IP proto /* Almost certainly "tcp". /* .IP hostrr /* DNS_RR pointer to TLSA base domain data. /* .IP forcetlsa /* When true, TLSA lookups are performed even when the qname and rname /* are insecure. This is only useful in the unlikely case that DLV is /* used to secure the TLSA RRset in an otherwise insecure zone. /* .IP log_param /* The TLS log level parameter name whose value is the log_level argument. /* .IP log_level /* The application TLS log level, which may affect dane lookup verbosity. /* .IP digest /* The digest (or list of digests concatenated with characters from /* "delim") to be added to the TLS_DANE record. /* .IP delim /* The set of delimiter characters used above. /* .IP smtp_mode /* Is the caller an SMTP client or an LMTP client? /* .IP tafile; /* A file with trust anchor certificates or public keys in PEM format. /* LICENSE /* .ad /* .fi /* This software is free. You can do with it whatever you want. /* The original author kindly requests that you acknowledge /* the use of his software. /* AUTHOR(S) /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /* /* Wietse Venema /* Google, Inc. /* 111 8th Avenue /* New York, NY 10011, USA /* /* Viktor Dukhovni
/*--*/
TLS_DANE *tls_dane_resolve(unsigned port, constchar *proto, DNS_RR *hostrr, int forcetlsa)
{
TLS_DANE *dane = 0; int iscname = strcasecmp(hostrr->rname, hostrr->qname); int isvalid = 1;
if (!tls_dane_avail()) return (0); /* Error */
/* *BydefaultsuppressTLSAlookupsforhostsinnon-DNSSECzones.If *thehostzoneisnotDNSSECvalidated,theTLSAqnamesub-domainis *safelyassumedtonotbeinaDNSSECLook-asideValidationchildzone.
*/ if (!forcetlsa && !hostrr->dnssec_valid) {
isvalid = iscname ? qname_secure(hostrr->qname) : 0; if (isvalid < 0) return (0); /* Error */
} if (!isvalid) {
dane = tls_dane_alloc();
dane->flags = TLS_DANE_FLAG_NORRS;
} else { if (!dane_cache)
dane_cache = ctable_create(CACHE_SIZE, dane_lookup, dane_free, 0);
/* *Trythernamefirstifsecure,ifnothingthere,trytheqnameif *different.Note,lookuperrorsaredistinctfromsuccesswith *nothingfound.Ifthernamelookupfailswedon'ttrytheqname.
*/ if (hostrr->dnssec_valid) {
dane = resolve_host(hostrr->rname, proto, port); if (tls_dane_notfound(dane) && iscname) {
tls_dane_free(dane);
dane = 0;
}
} if (!dane)
dane = resolve_host(hostrr->qname, proto, port); if (dane->flags & TLS_DANE_FLAG_ERROR) { /* We don't return this object. */
tls_dane_free(dane);
dane = 0;
}
}
return (dane);
}
/* tls_dane_load_trustfile - load trust anchor certs or keys from file */
int tls_dane_load_trustfile(TLS_DANE *dane, constchar *tafile)
{
BIO *bp; char *name = 0; char *header = 0; unsignedchar *data = 0; long len; int tacount; char *errtype = 0; /* if error: cert or pkey? */
save = cp = mystrdup(var_tls_dane_digests); while ((algname = mystrtok(&cp, CHARS_COMMA_SP)) != 0) { char *algcode = split_at(algname, '='); int codepoint = -1;
if (algcode && *algcode) { unsignedlong l; char *endcp;
/* *XXX:safe_strtoul()doesnotflagemptyorwhite-spaceonly *input.Sincewegetalgcodebysplittingwhite-space/comma *delimitedtokens,thisisnotaproblemhere.
*/
l = safe_strtoul(algcode, &endcp, 10); if ((l == 0 && (errno == EINVAL || endcp == algcode))
|| l >= 255 || *endcp) {
msg_warn("Invalid matching type number in %s: %s=%s",
VAR_TLS_DANE_DIGESTS, algname, algcode); continue;
} if (l == 0 || l == 255) {
msg_warn("Reserved matching type number in %s: %s=%s",
VAR_TLS_DANE_DIGESTS, algname, algcode); continue;
}
codepoint = l;
} /* Disable any codepoint gaps */ if (codepoint > maxtype) { while (++maxtype < codepoint)
mtypes[codepoint].alg = NULL;
maxtype = codepoint;
} /* Handle explicitly disabled codepoints */ if (*algname == 0) { /* Skip empty specifiers */ if (codepoint < 0) continue;
mtypes[codepoint].alg = NULL; continue;
} switch (codepoint) { case -1: if (strcasecmp(algname, LN_sha256) == 0)
codepoint = 1; /* SHA2-256(1) */ elseif (strcasecmp(algname, LN_sha512) == 0)
codepoint = 2; /* SHA2-512(2) */ else {
msg_warn("%s: digest algorithm %s needs an explicit number",
VAR_TLS_DANE_DIGESTS, algname); continue;
} break; case1: if (strcasecmp(algname, LN_sha256) != 0) {
msg_warn("%s: matching type 1 can only be %s",
VAR_TLS_DANE_DIGESTS, LN_sha256); continue;
}
algname = LN_sha256; break; case2: if (strcasecmp(algname, LN_sha512) != 0) {
msg_warn("%s: matching type 2 can only be %s",
VAR_TLS_DANE_DIGESTS, LN_sha512); continue;
}
algname = LN_sha512; break; default: break;
}
if (mtypes[codepoint].ord != 0) {
msg_warn("%s: matching type %d specified more than once",
VAR_TLS_DANE_DIGESTS, codepoint); continue;
}
mtypes[codepoint].ord = ++ord;
staticvoid load_tlsa_args(SSL *ssl, char *argv[])
{ const EVP_MD *md = 0;
X509 *cert = 0;
BIO *bp; unsignedchar *buf; unsignedchar *buf2; int len;
uint8_t u = atoi(argv[1]);
uint8_t s = atoi(argv[2]);
uint8_t m = atoi(argv[3]);
EVP_PKEY *pkey;
/* Unsupported usages are fatal */ switch (u) { case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION: case DNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE: break; default:
msg_fatal("unsupported certificate usage %u", u);
}
/* Unsupported selectors are fatal */ switch (s) { case DNS_TLSA_SELECTOR_FULL_CERTIFICATE: case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO: break; default:
msg_fatal("unsupported selector %u", s);
}
/* Unsupported selectors are fatal */ switch (m) { case DNS_TLSA_MATCHING_TYPE_NO_HASH_USED: case DNS_TLSA_MATCHING_TYPE_SHA256: case DNS_TLSA_MATCHING_TYPE_SHA512: break; default:
msg_fatal("unsupported matching type %u", m);
}
if ((bp = BIO_new_file(argv[4], "r")) == NULL)
msg_fatal("error opening %s: %m", argv[4]); if (!PEM_read_bio_X509(bp, &cert, 0, 0)) {
tls_print_errors();
msg_fatal("error loading certificate from %s: %m", argv[4]);
}
BIO_free(bp);
/* *ExtractASN.1DERformofcertificateorpublickey.
*/ switch (s) { case DNS_TLSA_SELECTOR_FULL_CERTIFICATE:
len = i2d_X509(cert, NULL); if (len > 0xffff)
msg_fatal("certificate too long: %d", len);
buf2 = buf = (unsignedchar *) mymalloc(len);
i2d_X509(cert, &buf2); break; case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
pkey = X509_get_pubkey(cert);
len = i2d_PUBKEY(pkey, NULL); if (len > 0xffff)
msg_fatal("public key too long: %d", len);
buf2 = buf = (unsignedchar *) mymalloc(len);
i2d_PUBKEY(pkey, &buf2);
EVP_PKEY_free(pkey); break;
}
X509_free(cert);
OPENSSL_assert(buf2 - buf == len);
switch (m) { case0: break; case1: if ((md = tls_digest_byname(LN_sha256, NULL)) == 0)
msg_fatal("Digest %s not found", LN_sha256); break; case2: if ((md = tls_digest_byname(LN_sha512, NULL)) == 0)
msg_fatal("Digest %s not found", LN_sha512); break; default:
msg_fatal("Unsupported DANE mtype: %d", m);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.