xref: /openbsd-src/lib/libtls/tls_conninfo.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: tls_conninfo.c,v 1.11 2016/08/22 17:12:35 jsing Exp $ */
2 /*
3  * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
4  * Copyright (c) 2015 Bob Beck <beck@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <stdio.h>
20 
21 #include <openssl/x509.h>
22 
23 #include <tls.h>
24 #include "tls_internal.h"
25 
26 static int
27 tls_hex_string(const unsigned char *in, size_t inlen, char **out,
28     size_t *outlen)
29 {
30 	static const char hex[] = "0123456789abcdef";
31 	size_t i, len;
32 	char *p;
33 
34 	if (outlen != NULL)
35 		*outlen = 0;
36 
37 	if (inlen >= SIZE_MAX)
38 		return (-1);
39 	if ((*out = reallocarray(NULL, inlen + 1, 2)) == NULL)
40 		return (-1);
41 
42 	p = *out;
43 	len = 0;
44 	for (i = 0; i < inlen; i++) {
45 		p[len++] = hex[(in[i] >> 4) & 0x0f];
46 		p[len++] = hex[in[i] & 0x0f];
47 	}
48 	p[len++] = 0;
49 
50 	if (outlen != NULL)
51 		*outlen = len;
52 
53 	return (0);
54 }
55 
56 static int
57 tls_get_peer_cert_hash(struct tls *ctx, char **hash)
58 {
59 	char d[EVP_MAX_MD_SIZE], *dhex = NULL;
60 	int dlen, rv = -1;
61 
62 	*hash = NULL;
63 	if (ctx->ssl_peer_cert == NULL)
64 		return (0);
65 
66 	if (X509_digest(ctx->ssl_peer_cert, EVP_sha256(), d, &dlen) != 1) {
67 		tls_set_errorx(ctx, "digest failed");
68 		goto err;
69 	}
70 
71 	if (tls_hex_string(d, dlen, &dhex, NULL) != 0) {
72 		tls_set_errorx(ctx, "digest hex string failed");
73 		goto err;
74 	}
75 
76 	if (asprintf(hash, "SHA256:%s", dhex) == -1) {
77 		tls_set_errorx(ctx, "out of memory");
78 		*hash = NULL;
79 		goto err;
80 	}
81 
82 	rv = 0;
83 
84 err:
85 	free(dhex);
86 
87 	return (rv);
88 }
89 
90 static int
91 tls_get_peer_cert_issuer(struct tls *ctx,  char **issuer)
92 {
93 	X509_NAME *name = NULL;
94 
95 	*issuer = NULL;
96 	if (ctx->ssl_peer_cert == NULL)
97 		return (-1);
98 	if ((name = X509_get_issuer_name(ctx->ssl_peer_cert)) == NULL)
99 		return (-1);
100 	*issuer = X509_NAME_oneline(name, 0, 0);
101 	if (*issuer == NULL)
102 		return (-1);
103 	return (0);
104 }
105 
106 static int
107 tls_get_peer_cert_subject(struct tls *ctx, char **subject)
108 {
109 	X509_NAME *name = NULL;
110 
111 	*subject = NULL;
112 	if (ctx->ssl_peer_cert == NULL)
113 		return (-1);
114 	if ((name = X509_get_subject_name(ctx->ssl_peer_cert)) == NULL)
115 		return (-1);
116 	*subject = X509_NAME_oneline(name, 0, 0);
117 	if (*subject == NULL)
118 		return (-1);
119 	return (0);
120 }
121 
122 static int
123 tls_get_peer_cert_times(struct tls *ctx, time_t *notbefore,
124     time_t *notafter)
125 {
126 	struct tm before_tm, after_tm;
127 	ASN1_TIME *before, *after;
128 
129 	if (ctx->ssl_peer_cert == NULL)
130 		return (-1);
131 
132 	memset(&before_tm, 0, sizeof(before_tm));
133 	memset(&after_tm, 0, sizeof(after_tm));
134 
135 	if ((before = X509_get_notBefore(ctx->ssl_peer_cert)) == NULL)
136 		goto err;
137 	if ((after = X509_get_notAfter(ctx->ssl_peer_cert)) == NULL)
138 		goto err;
139 	if (asn1_time_parse(before->data, before->length, &before_tm, 0) == -1)
140 		goto err;
141 	if (asn1_time_parse(after->data, after->length, &after_tm, 0) == -1)
142 		goto err;
143 	if ((*notbefore = timegm(&before_tm)) == -1)
144 		goto err;
145 	if ((*notafter = timegm(&after_tm)) == -1)
146 		goto err;
147 
148 	return (0);
149 
150  err:
151 	return (-1);
152 }
153 
154 static int
155 tls_get_peer_cert_info(struct tls *ctx)
156 {
157 	if (ctx->ssl_peer_cert == NULL)
158 		return (0);
159 
160 	if (tls_get_peer_cert_hash(ctx, &ctx->conninfo->hash) == -1)
161 		goto err;
162 	if (tls_get_peer_cert_subject(ctx, &ctx->conninfo->subject) == -1)
163 		goto err;
164 	if (tls_get_peer_cert_issuer(ctx, &ctx->conninfo->issuer) == -1)
165 		goto err;
166 	if (tls_get_peer_cert_times(ctx, &ctx->conninfo->notbefore,
167 	    &ctx->conninfo->notafter) == -1)
168 		goto err;
169 
170 	return (0);
171 
172  err:
173 	return (-1);
174 }
175 
176 static int
177 tls_conninfo_alpn_proto(struct tls *ctx)
178 {
179 	const unsigned char *p;
180 	unsigned int len;
181 
182 	free(ctx->conninfo->alpn);
183 	ctx->conninfo->alpn = NULL;
184 
185 	SSL_get0_alpn_selected(ctx->ssl_conn, &p, &len);
186 	if (len > 0) {
187 		if ((ctx->conninfo->alpn = malloc(len + 1)) == NULL)
188 			return (-1);
189 		memcpy(ctx->conninfo->alpn, p, len);
190 		ctx->conninfo->alpn[len] = '\0';
191 	}
192 
193 	return (0);
194 }
195 
196 int
197 tls_conninfo_populate(struct tls *ctx)
198 {
199 	const char *tmp;
200 
201 	tls_conninfo_free(ctx->conninfo);
202 
203 	if ((ctx->conninfo = calloc(1, sizeof(struct tls_conninfo))) == NULL) {
204 		tls_set_errorx(ctx, "out of memory");
205 		goto err;
206 	}
207 
208 	if (tls_conninfo_alpn_proto(ctx) == -1)
209 		goto err;
210 
211 	if ((tmp = SSL_get_cipher(ctx->ssl_conn)) == NULL)
212 		goto err;
213 	ctx->conninfo->cipher = strdup(tmp);
214 	if (ctx->conninfo->cipher == NULL)
215 		goto err;
216 
217 	if (ctx->servername != NULL) {
218 		if ((ctx->conninfo->servername =
219 		    strdup(ctx->servername)) == NULL)
220 			goto err;
221 	}
222 
223 	if ((tmp = SSL_get_version(ctx->ssl_conn)) == NULL)
224 		goto err;
225 	ctx->conninfo->version = strdup(tmp);
226 	if (ctx->conninfo->version == NULL)
227 		goto err;
228 
229 	if (tls_get_peer_cert_info(ctx) == -1)
230 		goto err;
231 
232 	return (0);
233 
234  err:
235 	tls_conninfo_free(ctx->conninfo);
236 	ctx->conninfo = NULL;
237 
238 	return (-1);
239 }
240 
241 void
242 tls_conninfo_free(struct tls_conninfo *conninfo)
243 {
244 	if (conninfo == NULL)
245 		return;
246 
247 	free(conninfo->alpn);
248 	conninfo->alpn = NULL;
249 	free(conninfo->cipher);
250 	conninfo->cipher = NULL;
251 	free(conninfo->version);
252 	conninfo->version = NULL;
253 
254 	free(conninfo->hash);
255 	conninfo->hash = NULL;
256 	free(conninfo->issuer);
257 	conninfo->issuer = NULL;
258 	free(conninfo->subject);
259 	conninfo->subject = NULL;
260 
261 	free(conninfo);
262 }
263 
264 const char *
265 tls_conn_alpn_selected(struct tls *ctx)
266 {
267 	if (ctx->conninfo == NULL)
268 		return (NULL);
269 	return (ctx->conninfo->alpn);
270 }
271 
272 const char *
273 tls_conn_cipher(struct tls *ctx)
274 {
275 	if (ctx->conninfo == NULL)
276 		return (NULL);
277 	return (ctx->conninfo->cipher);
278 }
279 
280 const char *
281 tls_conn_servername(struct tls *ctx)
282 {
283 	if (ctx->conninfo == NULL)
284 		return (NULL);
285 	return (ctx->conninfo->servername);
286 }
287 
288 const char *
289 tls_conn_version(struct tls *ctx)
290 {
291 	if (ctx->conninfo == NULL)
292 		return (NULL);
293 	return (ctx->conninfo->version);
294 }
295