+
+
+/*
+
+Call this for each TLSA record found for the target, after the
+DANE setup has been done on the ssl connection handle.
+
+Arguments:
+ ssl Connection handle
+ usage TLSA record field
+ selector TLSA record field
+ mdname ??? message digest name?
+ data ??? TLSA record megalump?
+ dlen length of data
+
+Return
+ -1 on error
+ 0 action not taken
+ 1 record accepted
+*/
+
+int
+DANESSL_add_tlsa(SSL *ssl, uint8_t usage, uint8_t selector, const char *mdname,
+ unsigned const char *data, size_t dlen)
+{
+ssl_dane *dane;
+dane_selector_list s = 0;
+dane_mtype_list m = 0;
+dane_data_list d = 0;
+dane_cert_list xlist = 0;
+dane_pkey_list klist = 0;
+const EVP_MD *md = 0;
+
+DEBUG(D_tls) debug_printf("Dane add-tlsa: usage %u sel %u mdname \"%s\"\n",
+ usage, selector, mdname);
+
+if(dane_idx < 0 || !(dane = SSL_get_ex_data(ssl, dane_idx)))
+ {
+ DANEerr(DANESSL_F_ADD_TLSA, DANESSL_R_INIT);
+ return -1;
+ }
+
+if (usage > DANESSL_USAGE_LAST)
+ {
+ DANEerr(DANESSL_F_ADD_TLSA, DANESSL_R_BAD_USAGE);
+ return 0;
+ }
+if (selector > DANESSL_SELECTOR_LAST)
+ {
+ DANEerr(DANESSL_F_ADD_TLSA, DANESSL_R_BAD_SELECTOR);
+ return 0;
+ }
+
+/* Support built-in standard one-digit mtypes */
+if (mdname && *mdname && mdname[1] == '\0')
+ switch (*mdname - '0')
+ {
+ case DANESSL_MATCHING_FULL: mdname = 0; break;
+ case DANESSL_MATCHING_2256: mdname = "sha256"; break;
+ case DANESSL_MATCHING_2512: mdname = "sha512"; break;
+ }
+if (mdname && *mdname && !(md = EVP_get_digestbyname(mdname)))
+ {
+ DANEerr(DANESSL_F_ADD_TLSA, DANESSL_R_BAD_DIGEST);
+ return 0;
+ }
+if (mdname && *mdname && dlen != EVP_MD_size(md))
+ {
+ DANEerr(DANESSL_F_ADD_TLSA, DANESSL_R_BAD_DATA_LENGTH);
+ return 0;
+ }
+if (!data)
+ {
+ DANEerr(DANESSL_F_ADD_TLSA, DANESSL_R_BAD_NULL_DATA);
+ return 0;
+ }
+
+/*
+ * Full Certificate or Public Key when NULL or empty digest name
+ */
+if (!mdname || !*mdname)
+ {
+ X509 *x = 0;
+ EVP_PKEY *k = 0;
+ const unsigned char *p = data;
+
+#define xklistinit(lvar, ltype, var, freeFunc) do { \
+ (lvar) = (ltype) OPENSSL_malloc(sizeof(*(lvar))); \
+ if ((lvar) == 0) { \
+ DANEerr(DANESSL_F_ADD_TLSA, ERR_R_MALLOC_FAILURE); \
+ freeFunc((var)); \
+ return 0; \
+ } \
+ (lvar)->next = 0; \
+ lvar->value = var; \
+ } while (0)
+#define xkfreeret(ret) do { \
+ if (xlist) list_free(xlist, cert_free); \
+ if (klist) list_free(klist, pkey_free); \
+ return (ret); \
+ } while (0)
+
+ switch (selector)
+ {
+ case DANESSL_SELECTOR_CERT:
+ if (!d2i_X509(&x, &p, dlen) || dlen != p - data)
+ {
+ if (x)
+ X509_free(x);
+ DANEerr(DANESSL_F_ADD_TLSA, DANESSL_R_BAD_CERT);
+ return 0;
+ }
+ k = X509_get_pubkey(x);
+ EVP_PKEY_free(k);
+ if (k == 0)
+ {
+ X509_free(x);
+ DANEerr(DANESSL_F_ADD_TLSA, DANESSL_R_BAD_CERT_PKEY);
+ return 0;
+ }
+ if (usage == DANESSL_USAGE_DANE_TA)
+ xklistinit(xlist, dane_cert_list, x, X509_free);
+ break;
+
+ case DANESSL_SELECTOR_SPKI:
+ if (!d2i_PUBKEY(&k, &p, dlen) || dlen != p - data)
+ {
+ if (k)
+ EVP_PKEY_free(k);
+ DANEerr(DANESSL_F_ADD_TLSA, DANESSL_R_BAD_PKEY);
+ return 0;
+ }
+ if (usage == DANESSL_USAGE_DANE_TA)
+ xklistinit(klist, dane_pkey_list, k, EVP_PKEY_free);
+ break;