xref: /freebsd/contrib/sendmail/src/tlsh.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
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