xref: /openbsd-src/lib/libtls/tls_conninfo.c (revision 26433cb13cc3308103fce1cf0c8fcad1280ba684)
1*26433cb1Stb /* $OpenBSD: tls_conninfo.c,v 1.28 2024/12/10 08:40:30 tb Exp $ */
2ab8f2ec6Sbeck /*
3ab8f2ec6Sbeck  * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
4ab8f2ec6Sbeck  * Copyright (c) 2015 Bob Beck <beck@openbsd.org>
5ab8f2ec6Sbeck  *
6ab8f2ec6Sbeck  * Permission to use, copy, modify, and distribute this software for any
7ab8f2ec6Sbeck  * purpose with or without fee is hereby granted, provided that the above
8ab8f2ec6Sbeck  * copyright notice and this permission notice appear in all copies.
9ab8f2ec6Sbeck  *
10ab8f2ec6Sbeck  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ab8f2ec6Sbeck  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ab8f2ec6Sbeck  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ab8f2ec6Sbeck  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ab8f2ec6Sbeck  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15ab8f2ec6Sbeck  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16ab8f2ec6Sbeck  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ab8f2ec6Sbeck  */
18ab8f2ec6Sbeck 
19ab8f2ec6Sbeck #include <stdio.h>
20e6d77be9Sop #include <string.h>
21ab8f2ec6Sbeck 
22ac059987Sbeck #include <openssl/posix_time.h>
23ab8f2ec6Sbeck #include <openssl/x509.h>
24ab8f2ec6Sbeck 
25ab8f2ec6Sbeck #include <tls.h>
26ab8f2ec6Sbeck #include "tls_internal.h"
27ab8f2ec6Sbeck 
28ac059987Sbeck static int
29ac059987Sbeck tls_convert_notafter(struct tm *tm, time_t *out_time)
30ac059987Sbeck {
31ac059987Sbeck 	int64_t posix_time;
32ac059987Sbeck 
33ac059987Sbeck 	/* OPENSSL_timegm() fails if tm is not representable in a time_t */
34ac059987Sbeck 	if (OPENSSL_timegm(tm, out_time))
35ac059987Sbeck 		return 1;
36ac059987Sbeck 	if (!OPENSSL_tm_to_posix(tm, &posix_time))
37ac059987Sbeck 		return 0;
38ac059987Sbeck 	if (posix_time < INT32_MIN)
39ac059987Sbeck 		return 0;
40ac059987Sbeck 	*out_time = (posix_time > INT32_MAX) ? INT32_MAX : posix_time;
41ac059987Sbeck 	return 1;
42ac059987Sbeck }
439fdb873dSbeck 
44c793ca29Sbeck int
45ab8f2ec6Sbeck tls_hex_string(const unsigned char *in, size_t inlen, char **out,
46ab8f2ec6Sbeck     size_t *outlen)
47ab8f2ec6Sbeck {
48ab8f2ec6Sbeck 	static const char hex[] = "0123456789abcdef";
49ab8f2ec6Sbeck 	size_t i, len;
50ab8f2ec6Sbeck 	char *p;
51ab8f2ec6Sbeck 
52ab8f2ec6Sbeck 	if (outlen != NULL)
53ab8f2ec6Sbeck 		*outlen = 0;
54ab8f2ec6Sbeck 
55ab8f2ec6Sbeck 	if (inlen >= SIZE_MAX)
56ab8f2ec6Sbeck 		return (-1);
57ab8f2ec6Sbeck 	if ((*out = reallocarray(NULL, inlen + 1, 2)) == NULL)
58ab8f2ec6Sbeck 		return (-1);
59ab8f2ec6Sbeck 
60ab8f2ec6Sbeck 	p = *out;
61ab8f2ec6Sbeck 	len = 0;
62ab8f2ec6Sbeck 	for (i = 0; i < inlen; i++) {
63ab8f2ec6Sbeck 		p[len++] = hex[(in[i] >> 4) & 0x0f];
64ab8f2ec6Sbeck 		p[len++] = hex[in[i] & 0x0f];
65ab8f2ec6Sbeck 	}
66ab8f2ec6Sbeck 	p[len++] = 0;
67ab8f2ec6Sbeck 
68ab8f2ec6Sbeck 	if (outlen != NULL)
69ab8f2ec6Sbeck 		*outlen = len;
70ab8f2ec6Sbeck 
71ab8f2ec6Sbeck 	return (0);
72ab8f2ec6Sbeck }
73ab8f2ec6Sbeck 
74ab8f2ec6Sbeck static int
75ab8f2ec6Sbeck tls_get_peer_cert_hash(struct tls *ctx, char **hash)
76ab8f2ec6Sbeck {
77ab8f2ec6Sbeck 	*hash = NULL;
78ab8f2ec6Sbeck 	if (ctx->ssl_peer_cert == NULL)
79ab8f2ec6Sbeck 		return (0);
80ab8f2ec6Sbeck 
81c793ca29Sbeck 	if (tls_cert_hash(ctx->ssl_peer_cert, hash) == -1) {
821450a961Sjsing 		tls_set_errorx(ctx, TLS_ERROR_OUT_OF_MEMORY, "out of memory");
83ab8f2ec6Sbeck 		*hash = NULL;
84c793ca29Sbeck 		return -1;
85ab8f2ec6Sbeck 	}
86c793ca29Sbeck 	return 0;
87ab8f2ec6Sbeck }
88ab8f2ec6Sbeck 
89ab8f2ec6Sbeck static int
90ab8f2ec6Sbeck tls_get_peer_cert_issuer(struct tls *ctx,  char **issuer)
91ab8f2ec6Sbeck {
92ab8f2ec6Sbeck 	X509_NAME *name = NULL;
93ab8f2ec6Sbeck 
94ab8f2ec6Sbeck 	*issuer = NULL;
95ab8f2ec6Sbeck 	if (ctx->ssl_peer_cert == NULL)
96ab8f2ec6Sbeck 		return (-1);
97ab8f2ec6Sbeck 	if ((name = X509_get_issuer_name(ctx->ssl_peer_cert)) == NULL)
98ab8f2ec6Sbeck 		return (-1);
99ab8f2ec6Sbeck 	*issuer = X509_NAME_oneline(name, 0, 0);
100ab8f2ec6Sbeck 	if (*issuer == NULL)
101ab8f2ec6Sbeck 		return (-1);
102ab8f2ec6Sbeck 	return (0);
103ab8f2ec6Sbeck }
104ab8f2ec6Sbeck 
105ab8f2ec6Sbeck static int
106ab8f2ec6Sbeck tls_get_peer_cert_subject(struct tls *ctx, char **subject)
107ab8f2ec6Sbeck {
108ab8f2ec6Sbeck 	X509_NAME *name = NULL;
109ab8f2ec6Sbeck 
110ab8f2ec6Sbeck 	*subject = NULL;
111ab8f2ec6Sbeck 	if (ctx->ssl_peer_cert == NULL)
112ab8f2ec6Sbeck 		return (-1);
113ab8f2ec6Sbeck 	if ((name = X509_get_subject_name(ctx->ssl_peer_cert)) == NULL)
114ab8f2ec6Sbeck 		return (-1);
115ab8f2ec6Sbeck 	*subject = X509_NAME_oneline(name, 0, 0);
116ab8f2ec6Sbeck 	if (*subject == NULL)
117ab8f2ec6Sbeck 		return (-1);
118ab8f2ec6Sbeck 	return (0);
119ab8f2ec6Sbeck }
120ab8f2ec6Sbeck 
121f00a4e85Sbeck static int
122*26433cb1Stb tls_get_peer_cert_common_name(struct tls *ctx, char **common_name)
123*26433cb1Stb {
124*26433cb1Stb 	if (ctx->ssl_peer_cert == NULL)
125*26433cb1Stb 		return (-1);
126*26433cb1Stb 	return tls_get_common_name(ctx, ctx->ssl_peer_cert, NULL, common_name);
127*26433cb1Stb }
128*26433cb1Stb 
129*26433cb1Stb static int
130dc559dc0Sjsing tls_get_peer_cert_times(struct tls *ctx, time_t *notbefore,
131dc559dc0Sjsing     time_t *notafter)
132f00a4e85Sbeck {
133f00a4e85Sbeck 	struct tm before_tm, after_tm;
134f00a4e85Sbeck 	ASN1_TIME *before, *after;
135dc559dc0Sjsing 
136dc559dc0Sjsing 	if (ctx->ssl_peer_cert == NULL)
137dc559dc0Sjsing 		return (-1);
138f00a4e85Sbeck 
139f00a4e85Sbeck 	if ((before = X509_get_notBefore(ctx->ssl_peer_cert)) == NULL)
140f00a4e85Sbeck 		goto err;
141f00a4e85Sbeck 	if ((after = X509_get_notAfter(ctx->ssl_peer_cert)) == NULL)
142f00a4e85Sbeck 		goto err;
143029ab7abStb 	if (!ASN1_TIME_to_tm(before, &before_tm))
144f00a4e85Sbeck 		goto err;
145029ab7abStb 	if (!ASN1_TIME_to_tm(after, &after_tm))
146f00a4e85Sbeck 		goto err;
147ac059987Sbeck 	if (!tls_convert_notafter(&after_tm, notafter))
1489fdb873dSbeck 		goto err;
149ac059987Sbeck 	if (!OPENSSL_timegm(&before_tm, notbefore))
150f00a4e85Sbeck 		goto err;
151dc559dc0Sjsing 	return (0);
152dc559dc0Sjsing 
153f00a4e85Sbeck  err:
154dc559dc0Sjsing 	return (-1);
155dc559dc0Sjsing }
156dc559dc0Sjsing 
157dc559dc0Sjsing static int
158dc559dc0Sjsing tls_get_peer_cert_info(struct tls *ctx)
159dc559dc0Sjsing {
160dc559dc0Sjsing 	if (ctx->ssl_peer_cert == NULL)
161dc559dc0Sjsing 		return (0);
162dc559dc0Sjsing 
163dc559dc0Sjsing 	if (tls_get_peer_cert_hash(ctx, &ctx->conninfo->hash) == -1)
164dc559dc0Sjsing 		goto err;
165dc559dc0Sjsing 	if (tls_get_peer_cert_subject(ctx, &ctx->conninfo->subject) == -1)
166dc559dc0Sjsing 		goto err;
167dc559dc0Sjsing 	if (tls_get_peer_cert_issuer(ctx, &ctx->conninfo->issuer) == -1)
168dc559dc0Sjsing 		goto err;
169*26433cb1Stb 	if (tls_get_peer_cert_common_name(ctx,
170*26433cb1Stb 	    &ctx->conninfo->common_name) == -1)
171*26433cb1Stb 		goto err;
172dc559dc0Sjsing 	if (tls_get_peer_cert_times(ctx, &ctx->conninfo->notbefore,
173dc559dc0Sjsing 	    &ctx->conninfo->notafter) == -1)
174dc559dc0Sjsing 		goto err;
175dc559dc0Sjsing 
176dc559dc0Sjsing 	return (0);
177dc559dc0Sjsing 
178dc559dc0Sjsing  err:
179dc559dc0Sjsing 	return (-1);
180f00a4e85Sbeck }
181f00a4e85Sbeck 
182183da8c6Sjsing static int
183183da8c6Sjsing tls_conninfo_alpn_proto(struct tls *ctx)
184183da8c6Sjsing {
185183da8c6Sjsing 	const unsigned char *p;
186183da8c6Sjsing 	unsigned int len;
187183da8c6Sjsing 
188183da8c6Sjsing 	free(ctx->conninfo->alpn);
189183da8c6Sjsing 	ctx->conninfo->alpn = NULL;
190183da8c6Sjsing 
191183da8c6Sjsing 	SSL_get0_alpn_selected(ctx->ssl_conn, &p, &len);
192183da8c6Sjsing 	if (len > 0) {
193183da8c6Sjsing 		if ((ctx->conninfo->alpn = malloc(len + 1)) == NULL)
194183da8c6Sjsing 			return (-1);
195183da8c6Sjsing 		memcpy(ctx->conninfo->alpn, p, len);
196183da8c6Sjsing 		ctx->conninfo->alpn[len] = '\0';
197183da8c6Sjsing 	}
198183da8c6Sjsing 
199183da8c6Sjsing 	return (0);
200183da8c6Sjsing }
201183da8c6Sjsing 
202c67861f7Sbeck static int
203c67861f7Sbeck tls_conninfo_cert_pem(struct tls *ctx)
204c67861f7Sbeck {
205c67861f7Sbeck 	int i, rv = -1;
206c67861f7Sbeck 	BIO *membio = NULL;
207c67861f7Sbeck 	BUF_MEM *bptr = NULL;
208c67861f7Sbeck 
209c67861f7Sbeck 	if (ctx->ssl_peer_cert == NULL)
210c67861f7Sbeck 		return 0;
211c67861f7Sbeck 	if ((membio = BIO_new(BIO_s_mem()))== NULL)
212c67861f7Sbeck 		goto err;
213c67861f7Sbeck 
214c67861f7Sbeck 	/*
215c67861f7Sbeck 	 * We have to write the peer cert out separately, because
216c67861f7Sbeck 	 * the certificate chain may or may not contain it.
217c67861f7Sbeck 	 */
218c67861f7Sbeck 	if (!PEM_write_bio_X509(membio, ctx->ssl_peer_cert))
219c67861f7Sbeck 		goto err;
220c67861f7Sbeck 	for (i = 0; i < sk_X509_num(ctx->ssl_peer_chain); i++) {
221c67861f7Sbeck 		X509 *chaincert = sk_X509_value(ctx->ssl_peer_chain, i);
222c67861f7Sbeck 		if (chaincert != ctx->ssl_peer_cert &&
223c67861f7Sbeck 		    !PEM_write_bio_X509(membio, chaincert))
224c67861f7Sbeck 			goto err;
225c67861f7Sbeck 	}
226c67861f7Sbeck 
227c67861f7Sbeck 	BIO_get_mem_ptr(membio, &bptr);
228c67861f7Sbeck 	free(ctx->conninfo->peer_cert);
229c67861f7Sbeck 	ctx->conninfo->peer_cert_len = 0;
230c67861f7Sbeck 	if ((ctx->conninfo->peer_cert = malloc(bptr->length)) == NULL)
231c67861f7Sbeck 		goto err;
232c67861f7Sbeck 	ctx->conninfo->peer_cert_len = bptr->length;
233c67861f7Sbeck 	memcpy(ctx->conninfo->peer_cert, bptr->data,
234c67861f7Sbeck 	    ctx->conninfo->peer_cert_len);
235c67861f7Sbeck 
236c67861f7Sbeck 	/* BIO_free() will kill BUF_MEM - because we have not set BIO_NOCLOSE */
237c67861f7Sbeck 	rv = 0;
238c67861f7Sbeck  err:
239c67861f7Sbeck 	BIO_free(membio);
240c67861f7Sbeck 	return rv;
241c67861f7Sbeck }
242c67861f7Sbeck 
2430dd084b9Sjsing static int
2440dd084b9Sjsing tls_conninfo_session(struct tls *ctx)
2450dd084b9Sjsing {
2460dd084b9Sjsing 	ctx->conninfo->session_resumed = SSL_session_reused(ctx->ssl_conn);
2470dd084b9Sjsing 
2480dd084b9Sjsing 	return 0;
2490dd084b9Sjsing }
2500dd084b9Sjsing 
251ab8f2ec6Sbeck int
252dc559dc0Sjsing tls_conninfo_populate(struct tls *ctx)
25317727490Sjsing {
254cbeeb52cSbeck 	const char *tmp;
25517727490Sjsing 
256dc559dc0Sjsing 	tls_conninfo_free(ctx->conninfo);
257dc559dc0Sjsing 
258dc559dc0Sjsing 	if ((ctx->conninfo = calloc(1, sizeof(struct tls_conninfo))) == NULL) {
2597a756d37Sjoshua 		tls_set_errorx(ctx, TLS_ERROR_OUT_OF_MEMORY, "out of memory");
260f00a4e85Sbeck 		goto err;
261cbeeb52cSbeck 	}
262dc559dc0Sjsing 
263dc559dc0Sjsing 	if (tls_conninfo_alpn_proto(ctx) == -1)
264cbeeb52cSbeck 		goto err;
265dc559dc0Sjsing 
266cbeeb52cSbeck 	if ((tmp = SSL_get_cipher(ctx->ssl_conn)) == NULL)
267cbeeb52cSbeck 		goto err;
268f385e3b3Sjsing 	if ((ctx->conninfo->cipher = strdup(tmp)) == NULL)
2692eb13fbaSbeck 		goto err;
270bbf181b7Sjsing 	ctx->conninfo->cipher_strength = SSL_get_cipher_bits(ctx->ssl_conn, NULL);
271dc559dc0Sjsing 
27255272e79Sjsing 	if (ctx->servername != NULL) {
27355272e79Sjsing 		if ((ctx->conninfo->servername =
27455272e79Sjsing 		    strdup(ctx->servername)) == NULL)
27555272e79Sjsing 			goto err;
27655272e79Sjsing 	}
277183da8c6Sjsing 
278dc559dc0Sjsing 	if ((tmp = SSL_get_version(ctx->ssl_conn)) == NULL)
279dc559dc0Sjsing 		goto err;
280f385e3b3Sjsing 	if ((ctx->conninfo->version = strdup(tmp)) == NULL)
281dc559dc0Sjsing 		goto err;
282dc559dc0Sjsing 
283dc559dc0Sjsing 	if (tls_get_peer_cert_info(ctx) == -1)
284dc559dc0Sjsing 		goto err;
285dc559dc0Sjsing 
286c67861f7Sbeck 	if (tls_conninfo_cert_pem(ctx) == -1)
287c67861f7Sbeck 		goto err;
288c67861f7Sbeck 
2890dd084b9Sjsing 	if (tls_conninfo_session(ctx) == -1)
2900dd084b9Sjsing 		goto err;
2910dd084b9Sjsing 
292cbeeb52cSbeck 	return (0);
293dc559dc0Sjsing 
294ab8f2ec6Sbeck  err:
295dc559dc0Sjsing 	tls_conninfo_free(ctx->conninfo);
296dc559dc0Sjsing 	ctx->conninfo = NULL;
297dc559dc0Sjsing 
298cbeeb52cSbeck 	return (-1);
299ab8f2ec6Sbeck }
300ab8f2ec6Sbeck 
301ab8f2ec6Sbeck void
302dc559dc0Sjsing tls_conninfo_free(struct tls_conninfo *conninfo)
30317727490Sjsing {
304dc559dc0Sjsing 	if (conninfo == NULL)
305dc559dc0Sjsing 		return;
306dc559dc0Sjsing 
307183da8c6Sjsing 	free(conninfo->alpn);
3082eb13fbaSbeck 	free(conninfo->cipher);
3091c402a93Sjsing 	free(conninfo->servername);
310dc559dc0Sjsing 	free(conninfo->version);
311dc559dc0Sjsing 
312*26433cb1Stb 	free(conninfo->common_name);
313dc559dc0Sjsing 	free(conninfo->hash);
314dc559dc0Sjsing 	free(conninfo->issuer);
315dc559dc0Sjsing 	free(conninfo->subject);
316dc559dc0Sjsing 
317c67861f7Sbeck 	free(conninfo->peer_cert);
318c67861f7Sbeck 
319dc559dc0Sjsing 	free(conninfo);
320ab8f2ec6Sbeck }
3212eb13fbaSbeck 
3222eb13fbaSbeck const char *
323183da8c6Sjsing tls_conn_alpn_selected(struct tls *ctx)
324183da8c6Sjsing {
325183da8c6Sjsing 	if (ctx->conninfo == NULL)
326183da8c6Sjsing 		return (NULL);
327183da8c6Sjsing 	return (ctx->conninfo->alpn);
328183da8c6Sjsing }
329183da8c6Sjsing 
330183da8c6Sjsing const char *
3312eb13fbaSbeck tls_conn_cipher(struct tls *ctx)
3322eb13fbaSbeck {
3330112cb75Sjsing 	if (ctx->conninfo == NULL)
3340112cb75Sjsing 		return (NULL);
3352eb13fbaSbeck 	return (ctx->conninfo->cipher);
3362eb13fbaSbeck }
3372eb13fbaSbeck 
338bbf181b7Sjsing int
339bbf181b7Sjsing tls_conn_cipher_strength(struct tls *ctx)
340bbf181b7Sjsing {
341bbf181b7Sjsing 	if (ctx->conninfo == NULL)
342bbf181b7Sjsing 		return (0);
343bbf181b7Sjsing 	return (ctx->conninfo->cipher_strength);
344bbf181b7Sjsing }
345bbf181b7Sjsing 
3462eb13fbaSbeck const char *
34755272e79Sjsing tls_conn_servername(struct tls *ctx)
34855272e79Sjsing {
34955272e79Sjsing 	if (ctx->conninfo == NULL)
35055272e79Sjsing 		return (NULL);
35155272e79Sjsing 	return (ctx->conninfo->servername);
35255272e79Sjsing }
35355272e79Sjsing 
3540dd084b9Sjsing int
3550dd084b9Sjsing tls_conn_session_resumed(struct tls *ctx)
3560dd084b9Sjsing {
3570dd084b9Sjsing 	if (ctx->conninfo == NULL)
3580dd084b9Sjsing 		return (0);
3590dd084b9Sjsing 	return (ctx->conninfo->session_resumed);
3600dd084b9Sjsing }
3610dd084b9Sjsing 
36255272e79Sjsing const char *
3632eb13fbaSbeck tls_conn_version(struct tls *ctx)
3642eb13fbaSbeck {
3650112cb75Sjsing 	if (ctx->conninfo == NULL)
3660112cb75Sjsing 		return (NULL);
3672eb13fbaSbeck 	return (ctx->conninfo->version);
3682eb13fbaSbeck }
369