15b0945b5SGregory Neil Shapiro /* 25b0945b5SGregory Neil Shapiro * Copyright (c) 2015 Proofpoint, Inc. and its suppliers. 35b0945b5SGregory Neil Shapiro * All rights reserved. 45b0945b5SGregory Neil Shapiro * 55b0945b5SGregory Neil Shapiro * By using this file, you agree to the terms and conditions set 65b0945b5SGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of 75b0945b5SGregory Neil Shapiro * the sendmail distribution. 85b0945b5SGregory Neil Shapiro * 95b0945b5SGregory Neil Shapiro */ 105b0945b5SGregory Neil Shapiro 115b0945b5SGregory Neil Shapiro #include <sendmail.h> 125b0945b5SGregory Neil Shapiro 135b0945b5SGregory Neil Shapiro SM_RCSID("@(#)$Id: tls.c,v 8.127 2013-11-27 02:51:11 gshapiro Exp $") 145b0945b5SGregory Neil Shapiro 155b0945b5SGregory Neil Shapiro #if STARTTLS 165b0945b5SGregory Neil Shapiro # include <tls.h> 175b0945b5SGregory Neil Shapiro 185b0945b5SGregory Neil Shapiro /* 195b0945b5SGregory Neil Shapiro ** DATA2HEX -- create a printable hex string from binary data ("%02X:") 205b0945b5SGregory Neil Shapiro ** 215b0945b5SGregory Neil Shapiro ** Parameters: 225b0945b5SGregory Neil Shapiro ** buf -- data 235b0945b5SGregory Neil Shapiro ** len -- length of data 245b0945b5SGregory Neil Shapiro ** hex -- output buffer 255b0945b5SGregory Neil Shapiro ** hlen -- length of output buffer 265b0945b5SGregory Neil Shapiro ** 275b0945b5SGregory Neil Shapiro ** Returns: 285b0945b5SGregory Neil Shapiro ** <0: errno 295b0945b5SGregory Neil Shapiro ** >0: length of data in hex 305b0945b5SGregory Neil Shapiro */ 315b0945b5SGregory Neil Shapiro 325b0945b5SGregory Neil Shapiro int 335b0945b5SGregory Neil Shapiro data2hex(buf, blen, hex, hlen) 345b0945b5SGregory Neil Shapiro unsigned char *buf; 355b0945b5SGregory Neil Shapiro int blen; 365b0945b5SGregory Neil Shapiro unsigned char *hex; 375b0945b5SGregory Neil Shapiro int hlen; 385b0945b5SGregory Neil Shapiro { 395b0945b5SGregory Neil Shapiro int r, h; 405b0945b5SGregory Neil Shapiro static const char hexcodes[] = "0123456789ABCDEF"; 415b0945b5SGregory Neil Shapiro 425b0945b5SGregory Neil Shapiro SM_REQUIRE(buf != NULL); 435b0945b5SGregory Neil Shapiro SM_REQUIRE(hex != NULL); 445b0945b5SGregory Neil Shapiro if (blen * 3 + 2 > hlen) 455b0945b5SGregory Neil Shapiro return -ERANGE; 465b0945b5SGregory Neil Shapiro 475b0945b5SGregory Neil Shapiro for (r = 0, h = 0; r < blen && h + 3 < hlen; r++) 485b0945b5SGregory Neil Shapiro { 495b0945b5SGregory Neil Shapiro hex[h++] = hexcodes[(buf[r] & 0xf0) >> 4]; 505b0945b5SGregory Neil Shapiro hex[h++] = hexcodes[(buf[r] & 0x0f)]; 515b0945b5SGregory Neil Shapiro if (r + 1 < blen) 525b0945b5SGregory Neil Shapiro hex[h++] = ':'; 535b0945b5SGregory Neil Shapiro } 545b0945b5SGregory Neil Shapiro if (h >= hlen) 555b0945b5SGregory Neil Shapiro return -ERANGE; 565b0945b5SGregory Neil Shapiro hex[h] = '\0'; 575b0945b5SGregory Neil Shapiro return h; 585b0945b5SGregory Neil Shapiro } 595b0945b5SGregory Neil Shapiro 60*2fb4f839SGregory Neil Shapiro # if DANE 61*2fb4f839SGregory Neil Shapiro 625b0945b5SGregory Neil Shapiro /* 635b0945b5SGregory Neil Shapiro ** TLS_DATA_MD -- calculate MD for data 645b0945b5SGregory Neil Shapiro ** 655b0945b5SGregory Neil Shapiro ** Parameters: 665b0945b5SGregory Neil Shapiro ** buf -- data (in and out!) 675b0945b5SGregory Neil Shapiro ** len -- length of data 685b0945b5SGregory Neil Shapiro ** md -- digest algorithm 695b0945b5SGregory Neil Shapiro ** 705b0945b5SGregory Neil Shapiro ** Returns: 715b0945b5SGregory Neil Shapiro ** <=0: cert fp calculation failed 725b0945b5SGregory Neil Shapiro ** >0: len of fp 735b0945b5SGregory Neil Shapiro ** 745b0945b5SGregory Neil Shapiro ** Side Effects: 755b0945b5SGregory Neil Shapiro ** writes digest to buf 765b0945b5SGregory Neil Shapiro */ 775b0945b5SGregory Neil Shapiro 785b0945b5SGregory Neil Shapiro static int 795b0945b5SGregory Neil Shapiro tls_data_md(buf, len, md) 805b0945b5SGregory Neil Shapiro unsigned char *buf; 815b0945b5SGregory Neil Shapiro int len; 825b0945b5SGregory Neil Shapiro const EVP_MD *md; 835b0945b5SGregory Neil Shapiro { 845b0945b5SGregory Neil Shapiro unsigned int md_len; 855b0945b5SGregory Neil Shapiro EVP_MD_CTX *mdctx; 865b0945b5SGregory Neil Shapiro unsigned char md_buf[EVP_MAX_MD_SIZE]; 875b0945b5SGregory Neil Shapiro 885b0945b5SGregory Neil Shapiro SM_REQUIRE(buf != NULL); 895b0945b5SGregory Neil Shapiro SM_REQUIRE(md != NULL); 905b0945b5SGregory Neil Shapiro SM_REQUIRE(len >= EVP_MAX_MD_SIZE); 915b0945b5SGregory Neil Shapiro 925b0945b5SGregory Neil Shapiro mdctx = EVP_MD_CTX_create(); 935b0945b5SGregory Neil Shapiro if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) 945b0945b5SGregory Neil Shapiro return -EINVAL; 955b0945b5SGregory Neil Shapiro if (EVP_DigestUpdate(mdctx, (void *)buf, len) != 1) 965b0945b5SGregory Neil Shapiro return -EINVAL; 975b0945b5SGregory Neil Shapiro if (EVP_DigestFinal_ex(mdctx, md_buf, &md_len) != 1) 985b0945b5SGregory Neil Shapiro return -EINVAL; 995b0945b5SGregory Neil Shapiro EVP_MD_CTX_destroy(mdctx); 1005b0945b5SGregory Neil Shapiro 1015b0945b5SGregory Neil Shapiro if (md_len > len) 1025b0945b5SGregory Neil Shapiro return -ERANGE; 1035b0945b5SGregory Neil Shapiro (void) memcpy(buf, md_buf, md_len); 1045b0945b5SGregory Neil Shapiro return (int)md_len; 1055b0945b5SGregory Neil Shapiro } 1065b0945b5SGregory Neil Shapiro 1075b0945b5SGregory Neil Shapiro /* 1085b0945b5SGregory Neil Shapiro ** PUBKEY_FP -- get public key fingerprint 1095b0945b5SGregory Neil Shapiro ** 1105b0945b5SGregory Neil Shapiro ** Parameters: 1115b0945b5SGregory Neil Shapiro ** cert -- TLS cert 1125b0945b5SGregory Neil Shapiro ** mdalg -- name of digest algorithm 1135b0945b5SGregory Neil Shapiro ** fp -- (pointer to) fingerprint buffer 1145b0945b5SGregory Neil Shapiro ** 1155b0945b5SGregory Neil Shapiro ** Returns: 1165b0945b5SGregory Neil Shapiro ** <=0: cert fp calculation failed 1175b0945b5SGregory Neil Shapiro ** >0: len of fp 1185b0945b5SGregory Neil Shapiro */ 1195b0945b5SGregory Neil Shapiro 1205b0945b5SGregory Neil Shapiro int 1215b0945b5SGregory Neil Shapiro pubkey_fp(cert, mdalg, fp) 1225b0945b5SGregory Neil Shapiro X509 *cert; 1235b0945b5SGregory Neil Shapiro const char *mdalg; 1245b0945b5SGregory Neil Shapiro char **fp; 1255b0945b5SGregory Neil Shapiro { 1265b0945b5SGregory Neil Shapiro int len, r; 1275b0945b5SGregory Neil Shapiro unsigned char *buf, *end; 1285b0945b5SGregory Neil Shapiro const EVP_MD *md; 1295b0945b5SGregory Neil Shapiro 1305b0945b5SGregory Neil Shapiro SM_ASSERT(cert != NULL); 1315b0945b5SGregory Neil Shapiro SM_ASSERT(fp != NULL); 1325b0945b5SGregory Neil Shapiro SM_ASSERT(mdalg != NULL); 1335b0945b5SGregory Neil Shapiro 1345b0945b5SGregory Neil Shapiro len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); 1355b0945b5SGregory Neil Shapiro 1365b0945b5SGregory Neil Shapiro /* what's an acceptable upper limit? */ 1375b0945b5SGregory Neil Shapiro if (len <= 0 || len >= 8192) 1385b0945b5SGregory Neil Shapiro return -EINVAL; 1395b0945b5SGregory Neil Shapiro if (len < EVP_MAX_MD_SIZE) 1405b0945b5SGregory Neil Shapiro len = EVP_MAX_MD_SIZE; 1415b0945b5SGregory Neil Shapiro end = buf = sm_malloc(len); 1425b0945b5SGregory Neil Shapiro if (NULL == buf) 1435b0945b5SGregory Neil Shapiro return -ENOMEM; 1445b0945b5SGregory Neil Shapiro 1455b0945b5SGregory Neil Shapiro if ('\0' == mdalg[0]) 1465b0945b5SGregory Neil Shapiro { 1475b0945b5SGregory Neil Shapiro r = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end); 1485b0945b5SGregory Neil Shapiro if (r <= 0 || r != len) 1495b0945b5SGregory Neil Shapiro return -EINVAL; 1505b0945b5SGregory Neil Shapiro *fp = (char *)buf; 1515b0945b5SGregory Neil Shapiro return len; 1525b0945b5SGregory Neil Shapiro } 1535b0945b5SGregory Neil Shapiro 1545b0945b5SGregory Neil Shapiro md = EVP_get_digestbyname(mdalg); 1555b0945b5SGregory Neil Shapiro if (NULL == md) 156*2fb4f839SGregory Neil Shapiro { 157*2fb4f839SGregory Neil Shapiro SM_FREE(buf); 1585b0945b5SGregory Neil Shapiro return DANE_VRFY_FAIL; 159*2fb4f839SGregory Neil Shapiro } 1605b0945b5SGregory Neil Shapiro len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end); 1615b0945b5SGregory Neil Shapiro r = tls_data_md(buf, len, md); 1625b0945b5SGregory Neil Shapiro if (r < 0) 1635b0945b5SGregory Neil Shapiro sm_free(buf); 1645b0945b5SGregory Neil Shapiro else 1655b0945b5SGregory Neil Shapiro *fp = (char *)buf; 1665b0945b5SGregory Neil Shapiro return r; 1675b0945b5SGregory Neil Shapiro } 1685b0945b5SGregory Neil Shapiro 1695b0945b5SGregory Neil Shapiro /* 1705b0945b5SGregory Neil Shapiro ** DANE_TLSA_CHK -- check whether a TLSA RR is ok to use 1715b0945b5SGregory Neil Shapiro ** 1725b0945b5SGregory Neil Shapiro ** Parameters: 1735b0945b5SGregory Neil Shapiro ** rr -- RR 1745b0945b5SGregory Neil Shapiro ** len -- length of RR 1755b0945b5SGregory Neil Shapiro ** host -- name of host for RR (only for logging) 1765b0945b5SGregory Neil Shapiro ** log -- whether to log problems 1775b0945b5SGregory Neil Shapiro ** 1785b0945b5SGregory Neil Shapiro ** Returns: 1795b0945b5SGregory Neil Shapiro ** TLSA_*, see tls.h 1805b0945b5SGregory Neil Shapiro */ 1815b0945b5SGregory Neil Shapiro 1825b0945b5SGregory Neil Shapiro int 1835b0945b5SGregory Neil Shapiro dane_tlsa_chk(rr, len, host, log) 1845b0945b5SGregory Neil Shapiro const char *rr; 1855b0945b5SGregory Neil Shapiro int len; 1865b0945b5SGregory Neil Shapiro const char *host; 1875b0945b5SGregory Neil Shapiro bool log; 1885b0945b5SGregory Neil Shapiro { 1895b0945b5SGregory Neil Shapiro int alg; 1905b0945b5SGregory Neil Shapiro 1915b0945b5SGregory Neil Shapiro if (len < 4) 1925b0945b5SGregory Neil Shapiro { 1935b0945b5SGregory Neil Shapiro if (log && LogLevel > 8) 1945b0945b5SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 1955b0945b5SGregory Neil Shapiro "TLSA=%s, len=%d, status=bogus", 1965b0945b5SGregory Neil Shapiro host, len); 1975b0945b5SGregory Neil Shapiro return TLSA_BOGUS; 1985b0945b5SGregory Neil Shapiro } 1995b0945b5SGregory Neil Shapiro SM_ASSERT(rr != NULL); 2005b0945b5SGregory Neil Shapiro 2015b0945b5SGregory Neil Shapiro alg = (int)rr[2]; 202*2fb4f839SGregory Neil Shapiro if ((int)rr[0] == 3 && (int)rr[1] == 1 && (alg >= 0 && alg <= 2)) 2035b0945b5SGregory Neil Shapiro return alg; 2045b0945b5SGregory Neil Shapiro if (log && LogLevel > 9) 2055b0945b5SGregory Neil Shapiro sm_syslog(LOG_NOTICE, NOQID, 2065b0945b5SGregory Neil Shapiro "TLSA=%s, type=%d-%d-%d:%02x, status=unsupported", 2075b0945b5SGregory Neil Shapiro host, (int)rr[0], (int)rr[1], (int)rr[2], 2085b0945b5SGregory Neil Shapiro (int)rr[3]); 2095b0945b5SGregory Neil Shapiro return TLSA_UNSUPP; 2105b0945b5SGregory Neil Shapiro } 2115b0945b5SGregory Neil Shapiro 2125b0945b5SGregory Neil Shapiro /* 2135b0945b5SGregory Neil Shapiro ** DANE_TLSA_CLR -- clear data in a dane_tlsa structure (for use) 2145b0945b5SGregory Neil Shapiro ** 2155b0945b5SGregory Neil Shapiro ** Parameters: 2165b0945b5SGregory Neil Shapiro ** dane_tlsa -- dane_tlsa to clear 2175b0945b5SGregory Neil Shapiro ** 2185b0945b5SGregory Neil Shapiro ** Returns: 2195b0945b5SGregory Neil Shapiro ** 1 if NULL 2205b0945b5SGregory Neil Shapiro ** 0 if ok 2215b0945b5SGregory Neil Shapiro */ 2225b0945b5SGregory Neil Shapiro 2235b0945b5SGregory Neil Shapiro int 2245b0945b5SGregory Neil Shapiro dane_tlsa_clr(dane_tlsa) 2255b0945b5SGregory Neil Shapiro dane_tlsa_P dane_tlsa; 2265b0945b5SGregory Neil Shapiro { 2275b0945b5SGregory Neil Shapiro int i; 2285b0945b5SGregory Neil Shapiro 2295b0945b5SGregory Neil Shapiro if (dane_tlsa == NULL) 2305b0945b5SGregory Neil Shapiro return 1; 2315b0945b5SGregory Neil Shapiro for (i = 0; i < dane_tlsa->dane_tlsa_n; i++) 2325b0945b5SGregory Neil Shapiro { 2335b0945b5SGregory Neil Shapiro SM_FREE(dane_tlsa->dane_tlsa_rr[i]); 2345b0945b5SGregory Neil Shapiro dane_tlsa->dane_tlsa_len[i] = 0; 2355b0945b5SGregory Neil Shapiro } 2365b0945b5SGregory Neil Shapiro SM_FREE(dane_tlsa->dane_tlsa_sni); 2375b0945b5SGregory Neil Shapiro memset(dane_tlsa, '\0', sizeof(*dane_tlsa)); 2385b0945b5SGregory Neil Shapiro return 0; 2395b0945b5SGregory Neil Shapiro 2405b0945b5SGregory Neil Shapiro } 2415b0945b5SGregory Neil Shapiro 2425b0945b5SGregory Neil Shapiro /* 2435b0945b5SGregory Neil Shapiro ** DANE_TLSA_FREE -- free a dane_tlsa structure 2445b0945b5SGregory Neil Shapiro ** 2455b0945b5SGregory Neil Shapiro ** Parameters: 2465b0945b5SGregory Neil Shapiro ** dane_tlsa -- dane_tlsa to free 2475b0945b5SGregory Neil Shapiro ** 2485b0945b5SGregory Neil Shapiro ** Returns: 2495b0945b5SGregory Neil Shapiro ** 0 if ok 2505b0945b5SGregory Neil Shapiro ** 1 if NULL 2515b0945b5SGregory Neil Shapiro */ 2525b0945b5SGregory Neil Shapiro 2535b0945b5SGregory Neil Shapiro int 2545b0945b5SGregory Neil Shapiro dane_tlsa_free(dane_tlsa) 2555b0945b5SGregory Neil Shapiro dane_tlsa_P dane_tlsa; 2565b0945b5SGregory Neil Shapiro { 2575b0945b5SGregory Neil Shapiro if (dane_tlsa == NULL) 2585b0945b5SGregory Neil Shapiro return 1; 2595b0945b5SGregory Neil Shapiro dane_tlsa_clr(dane_tlsa); 2605b0945b5SGregory Neil Shapiro SM_FREE(dane_tlsa); 2615b0945b5SGregory Neil Shapiro return 0; 2625b0945b5SGregory Neil Shapiro 2635b0945b5SGregory Neil Shapiro } 2645b0945b5SGregory Neil Shapiro # endif /* DANE */ 2655b0945b5SGregory Neil Shapiro 2665b0945b5SGregory Neil Shapiro #endif /* STARTTLS */ 267