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
602fb4f839SGregory Neil Shapiro # if DANE
612fb4f839SGregory 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
tls_data_md(buf,len,md)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 /*
108*d39bd2c1SGregory Neil Shapiro ** PUBKEY_FP -- generate public key fingerprint
1095b0945b5SGregory Neil Shapiro **
1105b0945b5SGregory Neil Shapiro ** Parameters:
1115b0945b5SGregory Neil Shapiro ** cert -- TLS cert
1125b0945b5SGregory Neil Shapiro ** mdalg -- name of digest algorithm
113*d39bd2c1SGregory Neil Shapiro ** fp -- (pointer to) fingerprint buffer (output)
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
pubkey_fp(cert,mdalg,fp)1215b0945b5SGregory Neil Shapiro pubkey_fp(cert, mdalg, fp)
1225b0945b5SGregory Neil Shapiro X509 *cert;
1235b0945b5SGregory Neil Shapiro const char *mdalg;
124*d39bd2c1SGregory Neil Shapiro unsigned char **fp;
1255b0945b5SGregory Neil Shapiro {
1265b0945b5SGregory Neil Shapiro int len, r;
127*d39bd2c1SGregory Neil Shapiro unsigned char *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;
141*d39bd2c1SGregory Neil Shapiro *fp = end = sm_malloc(len);
142*d39bd2c1SGregory Neil Shapiro if (NULL == end)
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 return len;
1515b0945b5SGregory Neil Shapiro }
1525b0945b5SGregory Neil Shapiro
1535b0945b5SGregory Neil Shapiro md = EVP_get_digestbyname(mdalg);
1545b0945b5SGregory Neil Shapiro if (NULL == md)
1552fb4f839SGregory Neil Shapiro {
156*d39bd2c1SGregory Neil Shapiro SM_FREE(*fp);
1575b0945b5SGregory Neil Shapiro return DANE_VRFY_FAIL;
1582fb4f839SGregory Neil Shapiro }
1595b0945b5SGregory Neil Shapiro len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end);
160*d39bd2c1SGregory Neil Shapiro r = tls_data_md(*fp, len, md);
1615b0945b5SGregory Neil Shapiro if (r < 0)
162*d39bd2c1SGregory Neil Shapiro sm_free(*fp);
1635b0945b5SGregory Neil Shapiro return r;
1645b0945b5SGregory Neil Shapiro }
1655b0945b5SGregory Neil Shapiro
1665b0945b5SGregory Neil Shapiro /*
1675b0945b5SGregory Neil Shapiro ** DANE_TLSA_CHK -- check whether a TLSA RR is ok to use
1685b0945b5SGregory Neil Shapiro **
1695b0945b5SGregory Neil Shapiro ** Parameters:
1705b0945b5SGregory Neil Shapiro ** rr -- RR
1715b0945b5SGregory Neil Shapiro ** len -- length of RR
1725b0945b5SGregory Neil Shapiro ** host -- name of host for RR (only for logging)
1735b0945b5SGregory Neil Shapiro ** log -- whether to log problems
1745b0945b5SGregory Neil Shapiro **
1755b0945b5SGregory Neil Shapiro ** Returns:
176*d39bd2c1SGregory Neil Shapiro ** >=0: "alg" aka "matching type"
177*d39bd2c1SGregory Neil Shapiro ** <0: TLSA_*, see tls.h
1785b0945b5SGregory Neil Shapiro */
1795b0945b5SGregory Neil Shapiro
1805b0945b5SGregory Neil Shapiro int
dane_tlsa_chk(rr,len,host,log)1815b0945b5SGregory Neil Shapiro dane_tlsa_chk(rr, len, host, log)
182*d39bd2c1SGregory Neil Shapiro const unsigned char *rr;
1835b0945b5SGregory Neil Shapiro int len;
1845b0945b5SGregory Neil Shapiro const char *host;
1855b0945b5SGregory Neil Shapiro bool log;
1865b0945b5SGregory Neil Shapiro {
1875b0945b5SGregory Neil Shapiro int alg;
188*d39bd2c1SGregory Neil Shapiro # if HAVE_SSL_CTX_dane_enable
189*d39bd2c1SGregory Neil Shapiro int sel, usg;
190*d39bd2c1SGregory Neil Shapiro # endif
1915b0945b5SGregory Neil Shapiro
1925b0945b5SGregory Neil Shapiro if (len < 4)
1935b0945b5SGregory Neil Shapiro {
1945b0945b5SGregory Neil Shapiro if (log && LogLevel > 8)
1955b0945b5SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
1965b0945b5SGregory Neil Shapiro "TLSA=%s, len=%d, status=bogus",
1975b0945b5SGregory Neil Shapiro host, len);
1985b0945b5SGregory Neil Shapiro return TLSA_BOGUS;
1995b0945b5SGregory Neil Shapiro }
2005b0945b5SGregory Neil Shapiro SM_ASSERT(rr != NULL);
2015b0945b5SGregory Neil Shapiro
2025b0945b5SGregory Neil Shapiro alg = (int)rr[2];
203*d39bd2c1SGregory Neil Shapiro # if HAVE_SSL_CTX_dane_enable
204*d39bd2c1SGregory Neil Shapiro usg = (int)rr[0];
205*d39bd2c1SGregory Neil Shapiro sel = (int)rr[1];
206*d39bd2c1SGregory Neil Shapiro if (usg >= 2 && usg <= 3 && sel >= 0 && sel <= 1 &&
207*d39bd2c1SGregory Neil Shapiro alg >= 0 && alg <= 2)
208*d39bd2c1SGregory Neil Shapiro return alg;
209*d39bd2c1SGregory Neil Shapiro # else
2102fb4f839SGregory Neil Shapiro if ((int)rr[0] == 3 && (int)rr[1] == 1 && (alg >= 0 && alg <= 2))
2115b0945b5SGregory Neil Shapiro return alg;
212*d39bd2c1SGregory Neil Shapiro # endif
2135b0945b5SGregory Neil Shapiro if (log && LogLevel > 9)
2145b0945b5SGregory Neil Shapiro sm_syslog(LOG_NOTICE, NOQID,
2155b0945b5SGregory Neil Shapiro "TLSA=%s, type=%d-%d-%d:%02x, status=unsupported",
2165b0945b5SGregory Neil Shapiro host, (int)rr[0], (int)rr[1], (int)rr[2],
2175b0945b5SGregory Neil Shapiro (int)rr[3]);
2185b0945b5SGregory Neil Shapiro return TLSA_UNSUPP;
2195b0945b5SGregory Neil Shapiro }
2205b0945b5SGregory Neil Shapiro
2215b0945b5SGregory Neil Shapiro /*
2225b0945b5SGregory Neil Shapiro ** DANE_TLSA_CLR -- clear data in a dane_tlsa structure (for use)
2235b0945b5SGregory Neil Shapiro **
2245b0945b5SGregory Neil Shapiro ** Parameters:
2255b0945b5SGregory Neil Shapiro ** dane_tlsa -- dane_tlsa to clear
2265b0945b5SGregory Neil Shapiro **
2275b0945b5SGregory Neil Shapiro ** Returns:
2285b0945b5SGregory Neil Shapiro ** 1 if NULL
2295b0945b5SGregory Neil Shapiro ** 0 if ok
2305b0945b5SGregory Neil Shapiro */
2315b0945b5SGregory Neil Shapiro
2325b0945b5SGregory Neil Shapiro int
dane_tlsa_clr(dane_tlsa)2335b0945b5SGregory Neil Shapiro dane_tlsa_clr(dane_tlsa)
2345b0945b5SGregory Neil Shapiro dane_tlsa_P dane_tlsa;
2355b0945b5SGregory Neil Shapiro {
2365b0945b5SGregory Neil Shapiro int i;
2375b0945b5SGregory Neil Shapiro
2385b0945b5SGregory Neil Shapiro if (dane_tlsa == NULL)
2395b0945b5SGregory Neil Shapiro return 1;
2405b0945b5SGregory Neil Shapiro for (i = 0; i < dane_tlsa->dane_tlsa_n; i++)
2415b0945b5SGregory Neil Shapiro {
2425b0945b5SGregory Neil Shapiro SM_FREE(dane_tlsa->dane_tlsa_rr[i]);
2435b0945b5SGregory Neil Shapiro dane_tlsa->dane_tlsa_len[i] = 0;
2445b0945b5SGregory Neil Shapiro }
2455b0945b5SGregory Neil Shapiro SM_FREE(dane_tlsa->dane_tlsa_sni);
2465b0945b5SGregory Neil Shapiro memset(dane_tlsa, '\0', sizeof(*dane_tlsa));
2475b0945b5SGregory Neil Shapiro return 0;
2485b0945b5SGregory Neil Shapiro
2495b0945b5SGregory Neil Shapiro }
2505b0945b5SGregory Neil Shapiro
2515b0945b5SGregory Neil Shapiro /*
2525b0945b5SGregory Neil Shapiro ** DANE_TLSA_FREE -- free a dane_tlsa structure
2535b0945b5SGregory Neil Shapiro **
2545b0945b5SGregory Neil Shapiro ** Parameters:
2555b0945b5SGregory Neil Shapiro ** dane_tlsa -- dane_tlsa to free
2565b0945b5SGregory Neil Shapiro **
2575b0945b5SGregory Neil Shapiro ** Returns:
2585b0945b5SGregory Neil Shapiro ** 0 if ok
2595b0945b5SGregory Neil Shapiro ** 1 if NULL
2605b0945b5SGregory Neil Shapiro */
2615b0945b5SGregory Neil Shapiro
2625b0945b5SGregory Neil Shapiro int
dane_tlsa_free(dane_tlsa)2635b0945b5SGregory Neil Shapiro dane_tlsa_free(dane_tlsa)
2645b0945b5SGregory Neil Shapiro dane_tlsa_P dane_tlsa;
2655b0945b5SGregory Neil Shapiro {
2665b0945b5SGregory Neil Shapiro if (dane_tlsa == NULL)
2675b0945b5SGregory Neil Shapiro return 1;
2685b0945b5SGregory Neil Shapiro dane_tlsa_clr(dane_tlsa);
2695b0945b5SGregory Neil Shapiro SM_FREE(dane_tlsa);
2705b0945b5SGregory Neil Shapiro return 0;
2715b0945b5SGregory Neil Shapiro
2725b0945b5SGregory Neil Shapiro }
2735b0945b5SGregory Neil Shapiro # endif /* DANE */
2745b0945b5SGregory Neil Shapiro
2755b0945b5SGregory Neil Shapiro #endif /* STARTTLS */
276