xref: /freebsd/contrib/sendmail/src/tlsh.c (revision 5b0945b57059d1cde0831d3afea7ec56c7d79508)
1*5b0945b5SGregory Neil Shapiro /*
2*5b0945b5SGregory Neil Shapiro  * Copyright (c) 2015 Proofpoint, Inc. and its suppliers.
3*5b0945b5SGregory Neil Shapiro  *	All rights reserved.
4*5b0945b5SGregory Neil Shapiro  *
5*5b0945b5SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
6*5b0945b5SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
7*5b0945b5SGregory Neil Shapiro  * the sendmail distribution.
8*5b0945b5SGregory Neil Shapiro  *
9*5b0945b5SGregory Neil Shapiro  */
10*5b0945b5SGregory Neil Shapiro 
11*5b0945b5SGregory Neil Shapiro #include <sendmail.h>
12*5b0945b5SGregory Neil Shapiro 
13*5b0945b5SGregory Neil Shapiro SM_RCSID("@(#)$Id: tls.c,v 8.127 2013-11-27 02:51:11 gshapiro Exp $")
14*5b0945b5SGregory Neil Shapiro 
15*5b0945b5SGregory Neil Shapiro #if STARTTLS
16*5b0945b5SGregory Neil Shapiro # include <tls.h>
17*5b0945b5SGregory Neil Shapiro 
18*5b0945b5SGregory Neil Shapiro /*
19*5b0945b5SGregory Neil Shapiro **  DATA2HEX -- create a printable hex string from binary data ("%02X:")
20*5b0945b5SGregory Neil Shapiro **
21*5b0945b5SGregory Neil Shapiro **	Parameters:
22*5b0945b5SGregory Neil Shapiro **		buf -- data
23*5b0945b5SGregory Neil Shapiro **		len -- length of data
24*5b0945b5SGregory Neil Shapiro **		hex -- output buffer
25*5b0945b5SGregory Neil Shapiro **		hlen -- length of output buffer
26*5b0945b5SGregory Neil Shapiro **
27*5b0945b5SGregory Neil Shapiro **	Returns:
28*5b0945b5SGregory Neil Shapiro **		<0: errno
29*5b0945b5SGregory Neil Shapiro **		>0: length of data in hex
30*5b0945b5SGregory Neil Shapiro */
31*5b0945b5SGregory Neil Shapiro 
32*5b0945b5SGregory Neil Shapiro int
33*5b0945b5SGregory Neil Shapiro data2hex(buf, blen, hex, hlen)
34*5b0945b5SGregory Neil Shapiro 	unsigned char *buf;
35*5b0945b5SGregory Neil Shapiro 	int blen;
36*5b0945b5SGregory Neil Shapiro 	unsigned char *hex;
37*5b0945b5SGregory Neil Shapiro 	int hlen;
38*5b0945b5SGregory Neil Shapiro {
39*5b0945b5SGregory Neil Shapiro 	int r, h;
40*5b0945b5SGregory Neil Shapiro 	static const char hexcodes[] = "0123456789ABCDEF";
41*5b0945b5SGregory Neil Shapiro 
42*5b0945b5SGregory Neil Shapiro 	SM_REQUIRE(buf != NULL);
43*5b0945b5SGregory Neil Shapiro 	SM_REQUIRE(hex != NULL);
44*5b0945b5SGregory Neil Shapiro 	if (blen * 3 + 2 > hlen)
45*5b0945b5SGregory Neil Shapiro 		return -ERANGE;
46*5b0945b5SGregory Neil Shapiro 
47*5b0945b5SGregory Neil Shapiro 	for (r = 0, h = 0; r < blen && h + 3 < hlen; r++)
48*5b0945b5SGregory Neil Shapiro 	{
49*5b0945b5SGregory Neil Shapiro 		hex[h++] = hexcodes[(buf[r] & 0xf0) >> 4];
50*5b0945b5SGregory Neil Shapiro 		hex[h++] = hexcodes[(buf[r] & 0x0f)];
51*5b0945b5SGregory Neil Shapiro 		if (r + 1 < blen)
52*5b0945b5SGregory Neil Shapiro 			hex[h++] = ':';
53*5b0945b5SGregory Neil Shapiro 	}
54*5b0945b5SGregory Neil Shapiro 	if (h >= hlen)
55*5b0945b5SGregory Neil Shapiro 		return -ERANGE;
56*5b0945b5SGregory Neil Shapiro 	hex[h] = '\0';
57*5b0945b5SGregory Neil Shapiro 	return h;
58*5b0945b5SGregory Neil Shapiro }
59*5b0945b5SGregory Neil Shapiro 
60*5b0945b5SGregory Neil Shapiro /*
61*5b0945b5SGregory Neil Shapiro **  TLS_DATA_MD -- calculate MD for data
62*5b0945b5SGregory Neil Shapiro **
63*5b0945b5SGregory Neil Shapiro **	Parameters:
64*5b0945b5SGregory Neil Shapiro **		buf -- data (in and out!)
65*5b0945b5SGregory Neil Shapiro **		len -- length of data
66*5b0945b5SGregory Neil Shapiro **		md -- digest algorithm
67*5b0945b5SGregory Neil Shapiro **
68*5b0945b5SGregory Neil Shapiro **	Returns:
69*5b0945b5SGregory Neil Shapiro **		<=0: cert fp calculation failed
70*5b0945b5SGregory Neil Shapiro **		>0: len of fp
71*5b0945b5SGregory Neil Shapiro **
72*5b0945b5SGregory Neil Shapiro **	Side Effects:
73*5b0945b5SGregory Neil Shapiro **		writes digest to buf
74*5b0945b5SGregory Neil Shapiro */
75*5b0945b5SGregory Neil Shapiro 
76*5b0945b5SGregory Neil Shapiro static int
77*5b0945b5SGregory Neil Shapiro tls_data_md(buf, len, md)
78*5b0945b5SGregory Neil Shapiro 	unsigned char *buf;
79*5b0945b5SGregory Neil Shapiro 	int len;
80*5b0945b5SGregory Neil Shapiro 	const EVP_MD *md;
81*5b0945b5SGregory Neil Shapiro {
82*5b0945b5SGregory Neil Shapiro 	unsigned int md_len;
83*5b0945b5SGregory Neil Shapiro 	EVP_MD_CTX *mdctx;
84*5b0945b5SGregory Neil Shapiro 	unsigned char md_buf[EVP_MAX_MD_SIZE];
85*5b0945b5SGregory Neil Shapiro 
86*5b0945b5SGregory Neil Shapiro 	SM_REQUIRE(buf != NULL);
87*5b0945b5SGregory Neil Shapiro 	SM_REQUIRE(md != NULL);
88*5b0945b5SGregory Neil Shapiro 	SM_REQUIRE(len >= EVP_MAX_MD_SIZE);
89*5b0945b5SGregory Neil Shapiro 
90*5b0945b5SGregory Neil Shapiro 	mdctx = EVP_MD_CTX_create();
91*5b0945b5SGregory Neil Shapiro 	if (EVP_DigestInit_ex(mdctx, md, NULL) != 1)
92*5b0945b5SGregory Neil Shapiro 		return -EINVAL;
93*5b0945b5SGregory Neil Shapiro 	if (EVP_DigestUpdate(mdctx, (void *)buf, len) != 1)
94*5b0945b5SGregory Neil Shapiro 		return -EINVAL;
95*5b0945b5SGregory Neil Shapiro 	if (EVP_DigestFinal_ex(mdctx, md_buf, &md_len) != 1)
96*5b0945b5SGregory Neil Shapiro 		return -EINVAL;
97*5b0945b5SGregory Neil Shapiro 	EVP_MD_CTX_destroy(mdctx);
98*5b0945b5SGregory Neil Shapiro 
99*5b0945b5SGregory Neil Shapiro 	if (md_len > len)
100*5b0945b5SGregory Neil Shapiro 		return -ERANGE;
101*5b0945b5SGregory Neil Shapiro 	(void) memcpy(buf, md_buf, md_len);
102*5b0945b5SGregory Neil Shapiro 	return (int)md_len;
103*5b0945b5SGregory Neil Shapiro }
104*5b0945b5SGregory Neil Shapiro 
105*5b0945b5SGregory Neil Shapiro #if DANE
106*5b0945b5SGregory Neil Shapiro 
107*5b0945b5SGregory Neil Shapiro /*
108*5b0945b5SGregory Neil Shapiro **  PUBKEY_FP -- get public key fingerprint
109*5b0945b5SGregory Neil Shapiro **
110*5b0945b5SGregory Neil Shapiro **	Parameters:
111*5b0945b5SGregory Neil Shapiro **		cert -- TLS cert
112*5b0945b5SGregory Neil Shapiro **		mdalg -- name of digest algorithm
113*5b0945b5SGregory Neil Shapiro **		fp -- (pointer to) fingerprint buffer
114*5b0945b5SGregory Neil Shapiro **
115*5b0945b5SGregory Neil Shapiro **	Returns:
116*5b0945b5SGregory Neil Shapiro **		<=0: cert fp calculation failed
117*5b0945b5SGregory Neil Shapiro **		>0: len of fp
118*5b0945b5SGregory Neil Shapiro */
119*5b0945b5SGregory Neil Shapiro 
120*5b0945b5SGregory Neil Shapiro int
121*5b0945b5SGregory Neil Shapiro pubkey_fp(cert, mdalg, fp)
122*5b0945b5SGregory Neil Shapiro 	X509 *cert;
123*5b0945b5SGregory Neil Shapiro 	const char *mdalg;
124*5b0945b5SGregory Neil Shapiro 	char **fp;
125*5b0945b5SGregory Neil Shapiro {
126*5b0945b5SGregory Neil Shapiro 	int len, r;
127*5b0945b5SGregory Neil Shapiro 	unsigned char *buf, *end;
128*5b0945b5SGregory Neil Shapiro 	const EVP_MD *md;
129*5b0945b5SGregory Neil Shapiro 
130*5b0945b5SGregory Neil Shapiro 	SM_ASSERT(cert != NULL);
131*5b0945b5SGregory Neil Shapiro 	SM_ASSERT(fp != NULL);
132*5b0945b5SGregory Neil Shapiro 	SM_ASSERT(mdalg != NULL);
133*5b0945b5SGregory Neil Shapiro 
134*5b0945b5SGregory Neil Shapiro 	len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
135*5b0945b5SGregory Neil Shapiro 
136*5b0945b5SGregory Neil Shapiro 	/* what's an acceptable upper limit? */
137*5b0945b5SGregory Neil Shapiro 	if (len <= 0 || len >= 8192)
138*5b0945b5SGregory Neil Shapiro 		return -EINVAL;
139*5b0945b5SGregory Neil Shapiro 	if (len < EVP_MAX_MD_SIZE)
140*5b0945b5SGregory Neil Shapiro 		len = EVP_MAX_MD_SIZE;
141*5b0945b5SGregory Neil Shapiro 	end = buf = sm_malloc(len);
142*5b0945b5SGregory Neil Shapiro 	if (NULL == buf)
143*5b0945b5SGregory Neil Shapiro 		return -ENOMEM;
144*5b0945b5SGregory Neil Shapiro 
145*5b0945b5SGregory Neil Shapiro 	if ('\0' == mdalg[0])
146*5b0945b5SGregory Neil Shapiro 	{
147*5b0945b5SGregory Neil Shapiro 		r = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end);
148*5b0945b5SGregory Neil Shapiro 		if (r <= 0 || r != len)
149*5b0945b5SGregory Neil Shapiro 			return -EINVAL;
150*5b0945b5SGregory Neil Shapiro 		*fp = (char *)buf;
151*5b0945b5SGregory Neil Shapiro 		return len;
152*5b0945b5SGregory Neil Shapiro 	}
153*5b0945b5SGregory Neil Shapiro 
154*5b0945b5SGregory Neil Shapiro 	md = EVP_get_digestbyname(mdalg);
155*5b0945b5SGregory Neil Shapiro 	if (NULL == md)
156*5b0945b5SGregory Neil Shapiro 		return DANE_VRFY_FAIL;
157*5b0945b5SGregory Neil Shapiro 	len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end);
158*5b0945b5SGregory Neil Shapiro 	r = tls_data_md(buf, len, md);
159*5b0945b5SGregory Neil Shapiro 	if (r < 0)
160*5b0945b5SGregory Neil Shapiro 		sm_free(buf);
161*5b0945b5SGregory Neil Shapiro 	else
162*5b0945b5SGregory Neil Shapiro 		*fp = (char *)buf;
163*5b0945b5SGregory Neil Shapiro 	return r;
164*5b0945b5SGregory Neil Shapiro }
165*5b0945b5SGregory Neil Shapiro 
166*5b0945b5SGregory Neil Shapiro /*
167*5b0945b5SGregory Neil Shapiro **  DANE_TLSA_CHK -- check whether a TLSA RR is ok to use
168*5b0945b5SGregory Neil Shapiro **
169*5b0945b5SGregory Neil Shapiro **	Parameters:
170*5b0945b5SGregory Neil Shapiro **		rr -- RR
171*5b0945b5SGregory Neil Shapiro **		len -- length of RR
172*5b0945b5SGregory Neil Shapiro **		host -- name of host for RR (only for logging)
173*5b0945b5SGregory Neil Shapiro **		log -- whether to log problems
174*5b0945b5SGregory Neil Shapiro **
175*5b0945b5SGregory Neil Shapiro **	Returns:
176*5b0945b5SGregory Neil Shapiro **		TLSA_*, see tls.h
177*5b0945b5SGregory Neil Shapiro */
178*5b0945b5SGregory Neil Shapiro 
179*5b0945b5SGregory Neil Shapiro int
180*5b0945b5SGregory Neil Shapiro dane_tlsa_chk(rr, len, host, log)
181*5b0945b5SGregory Neil Shapiro 	const char *rr;
182*5b0945b5SGregory Neil Shapiro 	int len;
183*5b0945b5SGregory Neil Shapiro 	const char *host;
184*5b0945b5SGregory Neil Shapiro 	bool log;
185*5b0945b5SGregory Neil Shapiro {
186*5b0945b5SGregory Neil Shapiro 	int alg;
187*5b0945b5SGregory Neil Shapiro 
188*5b0945b5SGregory Neil Shapiro 	if (len < 4)
189*5b0945b5SGregory Neil Shapiro 	{
190*5b0945b5SGregory Neil Shapiro 		if (log && LogLevel > 8)
191*5b0945b5SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
192*5b0945b5SGregory Neil Shapiro 				  "TLSA=%s, len=%d, status=bogus",
193*5b0945b5SGregory Neil Shapiro 				  host, len);
194*5b0945b5SGregory Neil Shapiro 		return TLSA_BOGUS;
195*5b0945b5SGregory Neil Shapiro 	}
196*5b0945b5SGregory Neil Shapiro 	SM_ASSERT(rr != NULL);
197*5b0945b5SGregory Neil Shapiro 
198*5b0945b5SGregory Neil Shapiro 	alg = (int)rr[2];
199*5b0945b5SGregory Neil Shapiro 	if ((int)rr[0] == 3 && (int)rr[1] == 1 && (alg >= 0 || alg <= 2))
200*5b0945b5SGregory Neil Shapiro 		return alg;
201*5b0945b5SGregory Neil Shapiro 	if (log && LogLevel > 9)
202*5b0945b5SGregory Neil Shapiro 		sm_syslog(LOG_NOTICE, NOQID,
203*5b0945b5SGregory Neil Shapiro 			  "TLSA=%s, type=%d-%d-%d:%02x, status=unsupported",
204*5b0945b5SGregory Neil Shapiro 			  host, (int)rr[0], (int)rr[1], (int)rr[2],
205*5b0945b5SGregory Neil Shapiro 			  (int)rr[3]);
206*5b0945b5SGregory Neil Shapiro 	return TLSA_UNSUPP;
207*5b0945b5SGregory Neil Shapiro }
208*5b0945b5SGregory Neil Shapiro 
209*5b0945b5SGregory Neil Shapiro /*
210*5b0945b5SGregory Neil Shapiro **  DANE_TLSA_CLR -- clear data in a dane_tlsa structure (for use)
211*5b0945b5SGregory Neil Shapiro **
212*5b0945b5SGregory Neil Shapiro **	Parameters:
213*5b0945b5SGregory Neil Shapiro **		dane_tlsa -- dane_tlsa to clear
214*5b0945b5SGregory Neil Shapiro **
215*5b0945b5SGregory Neil Shapiro **	Returns:
216*5b0945b5SGregory Neil Shapiro **		1 if NULL
217*5b0945b5SGregory Neil Shapiro **		0 if ok
218*5b0945b5SGregory Neil Shapiro */
219*5b0945b5SGregory Neil Shapiro 
220*5b0945b5SGregory Neil Shapiro int
221*5b0945b5SGregory Neil Shapiro dane_tlsa_clr(dane_tlsa)
222*5b0945b5SGregory Neil Shapiro 	dane_tlsa_P dane_tlsa;
223*5b0945b5SGregory Neil Shapiro {
224*5b0945b5SGregory Neil Shapiro 	int i;
225*5b0945b5SGregory Neil Shapiro 
226*5b0945b5SGregory Neil Shapiro 	if (dane_tlsa == NULL)
227*5b0945b5SGregory Neil Shapiro 		return 1;
228*5b0945b5SGregory Neil Shapiro 	for (i = 0; i < dane_tlsa->dane_tlsa_n; i++)
229*5b0945b5SGregory Neil Shapiro 	{
230*5b0945b5SGregory Neil Shapiro 		SM_FREE(dane_tlsa->dane_tlsa_rr[i]);
231*5b0945b5SGregory Neil Shapiro 		dane_tlsa->dane_tlsa_len[i] = 0;
232*5b0945b5SGregory Neil Shapiro 	}
233*5b0945b5SGregory Neil Shapiro 	SM_FREE(dane_tlsa->dane_tlsa_sni);
234*5b0945b5SGregory Neil Shapiro 	memset(dane_tlsa, '\0', sizeof(*dane_tlsa));
235*5b0945b5SGregory Neil Shapiro 	return 0;
236*5b0945b5SGregory Neil Shapiro 
237*5b0945b5SGregory Neil Shapiro }
238*5b0945b5SGregory Neil Shapiro 
239*5b0945b5SGregory Neil Shapiro /*
240*5b0945b5SGregory Neil Shapiro **  DANE_TLSA_FREE -- free a dane_tlsa structure
241*5b0945b5SGregory Neil Shapiro **
242*5b0945b5SGregory Neil Shapiro **	Parameters:
243*5b0945b5SGregory Neil Shapiro **		dane_tlsa -- dane_tlsa to free
244*5b0945b5SGregory Neil Shapiro **
245*5b0945b5SGregory Neil Shapiro **	Returns:
246*5b0945b5SGregory Neil Shapiro **		0 if ok
247*5b0945b5SGregory Neil Shapiro **		1 if NULL
248*5b0945b5SGregory Neil Shapiro */
249*5b0945b5SGregory Neil Shapiro 
250*5b0945b5SGregory Neil Shapiro int
251*5b0945b5SGregory Neil Shapiro dane_tlsa_free(dane_tlsa)
252*5b0945b5SGregory Neil Shapiro 	dane_tlsa_P dane_tlsa;
253*5b0945b5SGregory Neil Shapiro {
254*5b0945b5SGregory Neil Shapiro 	if (dane_tlsa == NULL)
255*5b0945b5SGregory Neil Shapiro 		return 1;
256*5b0945b5SGregory Neil Shapiro 	dane_tlsa_clr(dane_tlsa);
257*5b0945b5SGregory Neil Shapiro 	SM_FREE(dane_tlsa);
258*5b0945b5SGregory Neil Shapiro 	return 0;
259*5b0945b5SGregory Neil Shapiro 
260*5b0945b5SGregory Neil Shapiro }
261*5b0945b5SGregory Neil Shapiro #endif /* DANE */
262*5b0945b5SGregory Neil Shapiro 
263*5b0945b5SGregory Neil Shapiro #endif /* STARTTLS */
264