Fix DANE for multiple-MX when all TLSA lookup defer. Bug 1634
[exim.git] / src / src / dane-openssl.c
index 7815570758f32c84a7322c3c7c2aff64f06354a0..6345b39ca459cd1461985fa5c8d6edb7d2212cb3 100644 (file)
@@ -202,9 +202,9 @@ for(matched = 0; !matched && slist; slist = slist->next)
   {
   dane_mtype_list m;
   unsigned char mdbuf[EVP_MAX_MD_SIZE];
-  unsigned char *buf;
+  unsigned char *buf = NULL;
   unsigned char *buf2;
-  unsigned int len;
+  unsigned int len = 0;
 
   /*
    * Extract ASN.1 DER form of certificate or public key.
@@ -679,6 +679,7 @@ int matched;
 matched = match(dane->selectors[SSL_DANE_USAGE_FIXED_LEAF], cert, 0);
 if(matched > 0)
   if(!ctx->chain)
+    {
     if(  (ctx->chain = sk_X509_new_null())
       && sk_X509_push(ctx->chain, cert))
       CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
@@ -687,6 +688,7 @@ if(matched > 0)
       DANEerr(DANE_F_CHECK_END_ENTITY, ERR_R_MALLOC_FAILURE);
       return -1;
       }
+    }
 return matched;
 }
 
@@ -714,12 +716,14 @@ for(hosts = dane->hosts; hosts; hosts = hosts->next)
    * Sub-domain match: certid is any sub-domain of hostname.
    */
   if(match_subdomain)
+    {
     if(  (idlen = strlen(certid)) > (domlen = strlen(domain)) + 1
       && certid[idlen - domlen - 1] == '.'
       && !strcasecmp(certid + (idlen - domlen), domain))
       return 1;
     else
       continue;
+    }
 
   /*
    * Exact match and initial "*" match. The initial "*" in a certid
@@ -859,6 +863,8 @@ X509 *cert = ctx->cert;             /* XXX: accessor? */
 int matched = 0;
 int chain_length = sk_X509_num(ctx->chain);
 
+DEBUG(D_tls) debug_printf("Dane verify-chain\n");
+
 issuer_rrs = dane->selectors[SSL_DANE_USAGE_LIMIT_ISSUER];
 leaf_rrs = dane->selectors[SSL_DANE_USAGE_LIMIT_LEAF];
 ctx->verify = dane->verify;
@@ -950,6 +956,8 @@ int (*cb)(int, X509_STORE_CTX *) = ctx->verify_cb;
 int matched;
 X509 *cert = ctx->cert;             /* XXX: accessor? */
 
+DEBUG(D_tls) debug_printf("Dane verify-cert\n");
+
 if(ssl_idx < 0)
   ssl_idx = SSL_get_ex_data_X509_STORE_CTX_idx();
 if(dane_idx < 0)
@@ -1058,12 +1066,30 @@ list_free(((dane_selector) p)->mtype, dane_mtype_free);
 OPENSSL_free(p);
 }
 
+
+
+/*
+
+Tidy up once the connection is finished with.
+
+Arguments
+  ssl          The ssl connection handle
+
+=> Before calling SSL_free()
+tls_close() and tls_getc() [the error path] are the obvious places.
+Could we do it earlier - right after verification?  In tls_client_start()
+right after SSL_connect() returns, in that case.
+
+*/
+
 void
 DANESSL_cleanup(SSL *ssl)
 {
 ssl_dane *dane;
 int u;
 
+DEBUG(D_tls) debug_printf("Dane lib-cleanup\n");
+
 if(dane_idx < 0 || !(dane = SSL_get_ex_data(ssl, dane_idx)))
   return;
 (void) SSL_set_ex_data(ssl, dane_idx, 0);
@@ -1105,6 +1131,28 @@ while(*src)
 return head;
 }
 
+
+
+
+/*
+
+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)
@@ -1117,6 +1165,9 @@ 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(DANE_F_SSL_DANE_ADD_TLSA, DANE_R_DANE_INIT);
@@ -1254,6 +1305,30 @@ else if(klist)
 return 1;
 }
 
+
+
+
+/*
+Call this once we have an ssl connection handle but before
+making the TLS connection.
+
+=> In tls_client_start() after the call to SSL_new()
+and before the call to SSL_connect().  Exactly where
+probably does not matter.
+We probably want to keep our existing SNI handling;
+call this with NULL.
+
+Arguments:
+  ssl          Connection handle
+  sni_domain   Optional peer server name
+  hostnames    list of names to chack against peer cert
+
+Return
+  -1 on fatal error
+  0  nonfatal error
+  1  success
+*/
+
 int
 DANESSL_init(SSL *ssl, const char *sni_domain, const char **hostnames)
 {
@@ -1262,12 +1337,14 @@ int i;
 #ifdef OPENSSL_INTERNAL
 SSL_CTX *sctx = SSL_get_SSL_CTX(ssl);
 
+
 if(sctx->app_verify_callback != verify_cert)
   {
   DANEerr(DANE_F_SSL_DANE_INIT, DANE_R_SCTX_INIT);
   return -1;
   }
 #else
+DEBUG(D_tls) debug_printf("Dane ssl-init\n");
 if(dane_idx < 0)
   {
   DANEerr(DANE_F_SSL_DANE_INIT, DANE_R_LIBRARY_INIT);
@@ -1290,6 +1367,9 @@ if(!SSL_set_ex_data(ssl, dane_idx, dane))
   return 0;
   }
 
+dane->verify = 0;
+dane->hosts = 0;
+dane->thost = 0;
 dane->pkeys = 0;
 dane->certs = 0;
 dane->chain = 0;
@@ -1312,9 +1392,29 @@ if(hostnames && !(dane->hosts = host_list_init(hostnames)))
 return 1;
 }
 
+
+/*
+
+Call this once we have a context to work with, but
+before DANESSL_init()
+
+=> in tls_client_start(), after tls_init() call gives us the ctx,
+if we decide we want to (policy) and can (TLSA records available)
+replacing (? what about fallback) everything from testing tls_verify_hosts
+down to just before calling SSL_new() for the conn handle.
+
+Arguments
+  ctx          SSL context
+
+Return
+  -1   Error
+  1    Success
+*/
+
 int
 DANESSL_CTX_init(SSL_CTX *ctx)
 {
+DEBUG(D_tls) debug_printf("Dane ctx-init\n");
 if(dane_idx >= 0)
   {
   SSL_CTX_set_cert_verify_callback(ctx, verify_cert, 0);
@@ -1383,9 +1483,24 @@ if(!EVP_get_digestbyname(LN_sha512)) EVP_add_digest(EVP_sha512());
 dane_idx = SSL_get_ex_new_index(0, 0, 0, 0, 0);
 }
 
+
+
+/*
+
+Call this once.  Probably early in startup will do; may need
+to be after SSL library init.
+
+=> put after call to tls_init() for now
+
+Return
+  1    Success
+  0    Fail
+*/
+
 int
 DANESSL_library_init(void)
 {
+DEBUG(D_tls) debug_printf("Dane lib-init\n");
 if(err_lib_dane < 0)
   init_once(&err_lib_dane, ERR_get_next_error_library, dane_init);
 
@@ -1399,6 +1514,7 @@ DANEerr(DANE_F_SSL_DANE_LIBRARY_INIT, DANE_R_DANE_SUPPORT);
 return 0;
 }
 
+
 #endif /* OPENSSL_VERSION_NUMBER */
 /* vi: aw ai sw=2
 */