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