1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: tls_conninfo.c,v 1.22 2021/01/05 15:57:38 tb Exp $ */
2f5b1c8a1SJohn Marino /*
3f5b1c8a1SJohn Marino  * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
4f5b1c8a1SJohn Marino  * Copyright (c) 2015 Bob Beck <beck@openbsd.org>
5f5b1c8a1SJohn Marino  *
6f5b1c8a1SJohn Marino  * Permission to use, copy, modify, and distribute this software for any
7f5b1c8a1SJohn Marino  * purpose with or without fee is hereby granted, provided that the above
8f5b1c8a1SJohn Marino  * copyright notice and this permission notice appear in all copies.
9f5b1c8a1SJohn Marino  *
10f5b1c8a1SJohn Marino  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f5b1c8a1SJohn Marino  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f5b1c8a1SJohn Marino  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f5b1c8a1SJohn Marino  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f5b1c8a1SJohn Marino  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15f5b1c8a1SJohn Marino  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16f5b1c8a1SJohn Marino  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f5b1c8a1SJohn Marino  */
18f5b1c8a1SJohn Marino 
19f5b1c8a1SJohn Marino #include <stdio.h>
20f5b1c8a1SJohn Marino 
21f5b1c8a1SJohn Marino #include <openssl/x509.h>
22f5b1c8a1SJohn Marino 
23f5b1c8a1SJohn Marino #include <tls.h>
24f5b1c8a1SJohn Marino #include "tls_internal.h"
25f5b1c8a1SJohn Marino 
2672c33676SMaxim Ag int ASN1_time_tm_clamp_notafter(struct tm *tm);
2772c33676SMaxim Ag 
2872c33676SMaxim Ag int
tls_hex_string(const unsigned char * in,size_t inlen,char ** out,size_t * outlen)29f5b1c8a1SJohn Marino tls_hex_string(const unsigned char *in, size_t inlen, char **out,
30f5b1c8a1SJohn Marino     size_t *outlen)
31f5b1c8a1SJohn Marino {
32f5b1c8a1SJohn Marino 	static const char hex[] = "0123456789abcdef";
33f5b1c8a1SJohn Marino 	size_t i, len;
34f5b1c8a1SJohn Marino 	char *p;
35f5b1c8a1SJohn Marino 
36f5b1c8a1SJohn Marino 	if (outlen != NULL)
37f5b1c8a1SJohn Marino 		*outlen = 0;
38f5b1c8a1SJohn Marino 
39f5b1c8a1SJohn Marino 	if (inlen >= SIZE_MAX)
40f5b1c8a1SJohn Marino 		return (-1);
41f5b1c8a1SJohn Marino 	if ((*out = reallocarray(NULL, inlen + 1, 2)) == NULL)
42f5b1c8a1SJohn Marino 		return (-1);
43f5b1c8a1SJohn Marino 
44f5b1c8a1SJohn Marino 	p = *out;
45f5b1c8a1SJohn Marino 	len = 0;
46f5b1c8a1SJohn Marino 	for (i = 0; i < inlen; i++) {
47f5b1c8a1SJohn Marino 		p[len++] = hex[(in[i] >> 4) & 0x0f];
48f5b1c8a1SJohn Marino 		p[len++] = hex[in[i] & 0x0f];
49f5b1c8a1SJohn Marino 	}
50f5b1c8a1SJohn Marino 	p[len++] = 0;
51f5b1c8a1SJohn Marino 
52f5b1c8a1SJohn Marino 	if (outlen != NULL)
53f5b1c8a1SJohn Marino 		*outlen = len;
54f5b1c8a1SJohn Marino 
55f5b1c8a1SJohn Marino 	return (0);
56f5b1c8a1SJohn Marino }
57f5b1c8a1SJohn Marino 
58f5b1c8a1SJohn Marino static int
tls_get_peer_cert_hash(struct tls * ctx,char ** hash)59f5b1c8a1SJohn Marino tls_get_peer_cert_hash(struct tls *ctx, char **hash)
60f5b1c8a1SJohn Marino {
61f5b1c8a1SJohn Marino 	*hash = NULL;
62f5b1c8a1SJohn Marino 	if (ctx->ssl_peer_cert == NULL)
63f5b1c8a1SJohn Marino 		return (0);
64f5b1c8a1SJohn Marino 
6572c33676SMaxim Ag 	if (tls_cert_hash(ctx->ssl_peer_cert, hash) == -1) {
6672c33676SMaxim Ag 		tls_set_errorx(ctx, "unable to compute peer certificate hash - out of memory");
67f5b1c8a1SJohn Marino 		*hash = NULL;
6872c33676SMaxim Ag 		return -1;
69f5b1c8a1SJohn Marino 	}
7072c33676SMaxim Ag 	return 0;
71f5b1c8a1SJohn Marino }
72f5b1c8a1SJohn Marino 
73f5b1c8a1SJohn Marino static int
tls_get_peer_cert_issuer(struct tls * ctx,char ** issuer)74f5b1c8a1SJohn Marino tls_get_peer_cert_issuer(struct tls *ctx,  char **issuer)
75f5b1c8a1SJohn Marino {
76f5b1c8a1SJohn Marino 	X509_NAME *name = NULL;
77f5b1c8a1SJohn Marino 
78f5b1c8a1SJohn Marino 	*issuer = NULL;
79f5b1c8a1SJohn Marino 	if (ctx->ssl_peer_cert == NULL)
80f5b1c8a1SJohn Marino 		return (-1);
81f5b1c8a1SJohn Marino 	if ((name = X509_get_issuer_name(ctx->ssl_peer_cert)) == NULL)
82f5b1c8a1SJohn Marino 		return (-1);
83f5b1c8a1SJohn Marino 	*issuer = X509_NAME_oneline(name, 0, 0);
84f5b1c8a1SJohn Marino 	if (*issuer == NULL)
85f5b1c8a1SJohn Marino 		return (-1);
86f5b1c8a1SJohn Marino 	return (0);
87f5b1c8a1SJohn Marino }
88f5b1c8a1SJohn Marino 
89f5b1c8a1SJohn Marino static int
tls_get_peer_cert_subject(struct tls * ctx,char ** subject)90f5b1c8a1SJohn Marino tls_get_peer_cert_subject(struct tls *ctx, char **subject)
91f5b1c8a1SJohn Marino {
92f5b1c8a1SJohn Marino 	X509_NAME *name = NULL;
93f5b1c8a1SJohn Marino 
94f5b1c8a1SJohn Marino 	*subject = NULL;
95f5b1c8a1SJohn Marino 	if (ctx->ssl_peer_cert == NULL)
96f5b1c8a1SJohn Marino 		return (-1);
97f5b1c8a1SJohn Marino 	if ((name = X509_get_subject_name(ctx->ssl_peer_cert)) == NULL)
98f5b1c8a1SJohn Marino 		return (-1);
99f5b1c8a1SJohn Marino 	*subject = X509_NAME_oneline(name, 0, 0);
100f5b1c8a1SJohn Marino 	if (*subject == NULL)
101f5b1c8a1SJohn Marino 		return (-1);
102f5b1c8a1SJohn Marino 	return (0);
103f5b1c8a1SJohn Marino }
104f5b1c8a1SJohn Marino 
105f5b1c8a1SJohn Marino static int
tls_get_peer_cert_times(struct tls * ctx,time_t * notbefore,time_t * notafter)10672c33676SMaxim Ag tls_get_peer_cert_times(struct tls *ctx, time_t *notbefore,
10772c33676SMaxim Ag     time_t *notafter)
108f5b1c8a1SJohn Marino {
109f5b1c8a1SJohn Marino 	struct tm before_tm, after_tm;
110f5b1c8a1SJohn Marino 	ASN1_TIME *before, *after;
11172c33676SMaxim Ag 
11272c33676SMaxim Ag 	if (ctx->ssl_peer_cert == NULL)
11372c33676SMaxim Ag 		return (-1);
114f5b1c8a1SJohn Marino 
115f5b1c8a1SJohn Marino 	if ((before = X509_get_notBefore(ctx->ssl_peer_cert)) == NULL)
116f5b1c8a1SJohn Marino 		goto err;
117f5b1c8a1SJohn Marino 	if ((after = X509_get_notAfter(ctx->ssl_peer_cert)) == NULL)
118f5b1c8a1SJohn Marino 		goto err;
11972c33676SMaxim Ag 	if (ASN1_time_parse(before->data, before->length, &before_tm, 0) == -1)
120f5b1c8a1SJohn Marino 		goto err;
12172c33676SMaxim Ag 	if (ASN1_time_parse(after->data, after->length, &after_tm, 0) == -1)
12272c33676SMaxim Ag 		goto err;
12372c33676SMaxim Ag 	if (!ASN1_time_tm_clamp_notafter(&after_tm))
124f5b1c8a1SJohn Marino 		goto err;
125f5b1c8a1SJohn Marino 	if ((*notbefore = timegm(&before_tm)) == -1)
126f5b1c8a1SJohn Marino 		goto err;
127f5b1c8a1SJohn Marino 	if ((*notafter = timegm(&after_tm)) == -1)
128f5b1c8a1SJohn Marino 		goto err;
12972c33676SMaxim Ag 
13072c33676SMaxim Ag 	return (0);
13172c33676SMaxim Ag 
132f5b1c8a1SJohn Marino  err:
13372c33676SMaxim Ag 	return (-1);
134f5b1c8a1SJohn Marino }
135f5b1c8a1SJohn Marino 
13672c33676SMaxim Ag static int
tls_get_peer_cert_info(struct tls * ctx)13772c33676SMaxim Ag tls_get_peer_cert_info(struct tls *ctx)
13872c33676SMaxim Ag {
13972c33676SMaxim Ag 	if (ctx->ssl_peer_cert == NULL)
14072c33676SMaxim Ag 		return (0);
14172c33676SMaxim Ag 
142f5b1c8a1SJohn Marino 	if (tls_get_peer_cert_hash(ctx, &ctx->conninfo->hash) == -1)
143f5b1c8a1SJohn Marino 		goto err;
14472c33676SMaxim Ag 	if (tls_get_peer_cert_subject(ctx, &ctx->conninfo->subject) == -1)
145f5b1c8a1SJohn Marino 		goto err;
146f5b1c8a1SJohn Marino 	if (tls_get_peer_cert_issuer(ctx, &ctx->conninfo->issuer) == -1)
147f5b1c8a1SJohn Marino 		goto err;
148f5b1c8a1SJohn Marino 	if (tls_get_peer_cert_times(ctx, &ctx->conninfo->notbefore,
149f5b1c8a1SJohn Marino 	    &ctx->conninfo->notafter) == -1)
150f5b1c8a1SJohn Marino 		goto err;
15172c33676SMaxim Ag 
15272c33676SMaxim Ag 	return (0);
15372c33676SMaxim Ag 
15472c33676SMaxim Ag  err:
15572c33676SMaxim Ag 	return (-1);
156f5b1c8a1SJohn Marino }
15772c33676SMaxim Ag 
15872c33676SMaxim Ag static int
tls_conninfo_alpn_proto(struct tls * ctx)15972c33676SMaxim Ag tls_conninfo_alpn_proto(struct tls *ctx)
16072c33676SMaxim Ag {
16172c33676SMaxim Ag 	const unsigned char *p;
16272c33676SMaxim Ag 	unsigned int len;
16372c33676SMaxim Ag 
16472c33676SMaxim Ag 	free(ctx->conninfo->alpn);
16572c33676SMaxim Ag 	ctx->conninfo->alpn = NULL;
16672c33676SMaxim Ag 
16772c33676SMaxim Ag 	SSL_get0_alpn_selected(ctx->ssl_conn, &p, &len);
16872c33676SMaxim Ag 	if (len > 0) {
16972c33676SMaxim Ag 		if ((ctx->conninfo->alpn = malloc(len + 1)) == NULL)
17072c33676SMaxim Ag 			return (-1);
17172c33676SMaxim Ag 		memcpy(ctx->conninfo->alpn, p, len);
17272c33676SMaxim Ag 		ctx->conninfo->alpn[len] = '\0';
17372c33676SMaxim Ag 	}
17472c33676SMaxim Ag 
17572c33676SMaxim Ag 	return (0);
17672c33676SMaxim Ag }
17772c33676SMaxim Ag 
17872c33676SMaxim Ag static int
tls_conninfo_cert_pem(struct tls * ctx)17972c33676SMaxim Ag tls_conninfo_cert_pem(struct tls *ctx)
18072c33676SMaxim Ag {
18172c33676SMaxim Ag 	int i, rv = -1;
18272c33676SMaxim Ag 	BIO *membio = NULL;
18372c33676SMaxim Ag 	BUF_MEM *bptr = NULL;
18472c33676SMaxim Ag 
18572c33676SMaxim Ag 	if (ctx->ssl_peer_cert == NULL)
18672c33676SMaxim Ag 		return 0;
18772c33676SMaxim Ag 	if ((membio = BIO_new(BIO_s_mem()))== NULL)
188f5b1c8a1SJohn Marino 		goto err;
18972c33676SMaxim Ag 
19072c33676SMaxim Ag 	/*
19172c33676SMaxim Ag 	 * We have to write the peer cert out separately, because
19272c33676SMaxim Ag 	 * the certificate chain may or may not contain it.
19372c33676SMaxim Ag 	 */
19472c33676SMaxim Ag 	if (!PEM_write_bio_X509(membio, ctx->ssl_peer_cert))
195f5b1c8a1SJohn Marino 		goto err;
19672c33676SMaxim Ag 	for (i = 0; i < sk_X509_num(ctx->ssl_peer_chain); i++) {
19772c33676SMaxim Ag 		X509 *chaincert = sk_X509_value(ctx->ssl_peer_chain, i);
19872c33676SMaxim Ag 		if (chaincert != ctx->ssl_peer_cert &&
19972c33676SMaxim Ag 		    !PEM_write_bio_X509(membio, chaincert))
20072c33676SMaxim Ag 			goto err;
20172c33676SMaxim Ag 	}
20272c33676SMaxim Ag 
20372c33676SMaxim Ag 	BIO_get_mem_ptr(membio, &bptr);
20472c33676SMaxim Ag 	free(ctx->conninfo->peer_cert);
20572c33676SMaxim Ag 	ctx->conninfo->peer_cert_len = 0;
20672c33676SMaxim Ag 	if ((ctx->conninfo->peer_cert = malloc(bptr->length)) == NULL)
20772c33676SMaxim Ag 		goto err;
20872c33676SMaxim Ag 	ctx->conninfo->peer_cert_len = bptr->length;
20972c33676SMaxim Ag 	memcpy(ctx->conninfo->peer_cert, bptr->data,
21072c33676SMaxim Ag 	    ctx->conninfo->peer_cert_len);
21172c33676SMaxim Ag 
21272c33676SMaxim Ag 	/* BIO_free() will kill BUF_MEM - because we have not set BIO_NOCLOSE */
21372c33676SMaxim Ag 	rv = 0;
21472c33676SMaxim Ag  err:
21572c33676SMaxim Ag 	BIO_free(membio);
21672c33676SMaxim Ag 	return rv;
21772c33676SMaxim Ag }
21872c33676SMaxim Ag 
21972c33676SMaxim Ag static int
tls_conninfo_session(struct tls * ctx)22072c33676SMaxim Ag tls_conninfo_session(struct tls *ctx)
22172c33676SMaxim Ag {
22272c33676SMaxim Ag 	ctx->conninfo->session_resumed = SSL_session_reused(ctx->ssl_conn);
22372c33676SMaxim Ag 
22472c33676SMaxim Ag 	return 0;
22572c33676SMaxim Ag }
22672c33676SMaxim Ag 
22772c33676SMaxim Ag int
tls_conninfo_populate(struct tls * ctx)22872c33676SMaxim Ag tls_conninfo_populate(struct tls *ctx)
22972c33676SMaxim Ag {
23072c33676SMaxim Ag 	const char *tmp;
23172c33676SMaxim Ag 
23272c33676SMaxim Ag 	tls_conninfo_free(ctx->conninfo);
23372c33676SMaxim Ag 
23472c33676SMaxim Ag 	if ((ctx->conninfo = calloc(1, sizeof(struct tls_conninfo))) == NULL) {
23572c33676SMaxim Ag 		tls_set_errorx(ctx, "out of memory");
23672c33676SMaxim Ag 		goto err;
23772c33676SMaxim Ag 	}
23872c33676SMaxim Ag 
23972c33676SMaxim Ag 	if (tls_conninfo_alpn_proto(ctx) == -1)
24072c33676SMaxim Ag 		goto err;
24172c33676SMaxim Ag 
242f5b1c8a1SJohn Marino 	if ((tmp = SSL_get_cipher(ctx->ssl_conn)) == NULL)
243f5b1c8a1SJohn Marino 		goto err;
24472c33676SMaxim Ag 	if ((ctx->conninfo->cipher = strdup(tmp)) == NULL)
245f5b1c8a1SJohn Marino 		goto err;
246cca6fc52SDaniel Fojt 	ctx->conninfo->cipher_strength = SSL_get_cipher_bits(ctx->ssl_conn, NULL);
24772c33676SMaxim Ag 
24872c33676SMaxim Ag 	if (ctx->servername != NULL) {
24972c33676SMaxim Ag 		if ((ctx->conninfo->servername =
25072c33676SMaxim Ag 		    strdup(ctx->servername)) == NULL)
25172c33676SMaxim Ag 			goto err;
25272c33676SMaxim Ag 	}
25372c33676SMaxim Ag 
25472c33676SMaxim Ag 	if ((tmp = SSL_get_version(ctx->ssl_conn)) == NULL)
25572c33676SMaxim Ag 		goto err;
25672c33676SMaxim Ag 	if ((ctx->conninfo->version = strdup(tmp)) == NULL)
25772c33676SMaxim Ag 		goto err;
25872c33676SMaxim Ag 
25972c33676SMaxim Ag 	if (tls_get_peer_cert_info(ctx) == -1)
26072c33676SMaxim Ag 		goto err;
26172c33676SMaxim Ag 
26272c33676SMaxim Ag 	if (tls_conninfo_cert_pem(ctx) == -1)
26372c33676SMaxim Ag 		goto err;
26472c33676SMaxim Ag 
26572c33676SMaxim Ag 	if (tls_conninfo_session(ctx) == -1)
26672c33676SMaxim Ag 		goto err;
26772c33676SMaxim Ag 
268f5b1c8a1SJohn Marino 	return (0);
26972c33676SMaxim Ag 
270f5b1c8a1SJohn Marino  err:
27172c33676SMaxim Ag 	tls_conninfo_free(ctx->conninfo);
27272c33676SMaxim Ag 	ctx->conninfo = NULL;
27372c33676SMaxim Ag 
274f5b1c8a1SJohn Marino 	return (-1);
275f5b1c8a1SJohn Marino }
276f5b1c8a1SJohn Marino 
277f5b1c8a1SJohn Marino void
tls_conninfo_free(struct tls_conninfo * conninfo)27872c33676SMaxim Ag tls_conninfo_free(struct tls_conninfo *conninfo)
27972c33676SMaxim Ag {
28072c33676SMaxim Ag 	if (conninfo == NULL)
28172c33676SMaxim Ag 		return;
28272c33676SMaxim Ag 
28372c33676SMaxim Ag 	free(conninfo->alpn);
284f5b1c8a1SJohn Marino 	free(conninfo->cipher);
28572c33676SMaxim Ag 	free(conninfo->servername);
28672c33676SMaxim Ag 	free(conninfo->version);
28772c33676SMaxim Ag 
28872c33676SMaxim Ag 	free(conninfo->hash);
28972c33676SMaxim Ag 	free(conninfo->issuer);
29072c33676SMaxim Ag 	free(conninfo->subject);
29172c33676SMaxim Ag 
29272c33676SMaxim Ag 	free(conninfo->peer_cert);
29372c33676SMaxim Ag 
29472c33676SMaxim Ag 	free(conninfo);
295f5b1c8a1SJohn Marino }
29672c33676SMaxim Ag 
29772c33676SMaxim Ag const char *
tls_conn_alpn_selected(struct tls * ctx)29872c33676SMaxim Ag tls_conn_alpn_selected(struct tls *ctx)
29972c33676SMaxim Ag {
30072c33676SMaxim Ag 	if (ctx->conninfo == NULL)
30172c33676SMaxim Ag 		return (NULL);
30272c33676SMaxim Ag 	return (ctx->conninfo->alpn);
303f5b1c8a1SJohn Marino }
304f5b1c8a1SJohn Marino 
305f5b1c8a1SJohn Marino const char *
tls_conn_cipher(struct tls * ctx)306f5b1c8a1SJohn Marino tls_conn_cipher(struct tls *ctx)
307f5b1c8a1SJohn Marino {
308f5b1c8a1SJohn Marino 	if (ctx->conninfo == NULL)
309f5b1c8a1SJohn Marino 		return (NULL);
310f5b1c8a1SJohn Marino 	return (ctx->conninfo->cipher);
311f5b1c8a1SJohn Marino }
312f5b1c8a1SJohn Marino 
313cca6fc52SDaniel Fojt int
tls_conn_cipher_strength(struct tls * ctx)314cca6fc52SDaniel Fojt tls_conn_cipher_strength(struct tls *ctx)
315cca6fc52SDaniel Fojt {
316cca6fc52SDaniel Fojt 	if (ctx->conninfo == NULL)
317cca6fc52SDaniel Fojt 		return (0);
318cca6fc52SDaniel Fojt 	return (ctx->conninfo->cipher_strength);
319cca6fc52SDaniel Fojt }
320cca6fc52SDaniel Fojt 
321f5b1c8a1SJohn Marino const char *
tls_conn_servername(struct tls * ctx)32272c33676SMaxim Ag tls_conn_servername(struct tls *ctx)
32372c33676SMaxim Ag {
32472c33676SMaxim Ag 	if (ctx->conninfo == NULL)
32572c33676SMaxim Ag 		return (NULL);
32672c33676SMaxim Ag 	return (ctx->conninfo->servername);
32772c33676SMaxim Ag }
32872c33676SMaxim Ag 
32972c33676SMaxim Ag int
tls_conn_session_resumed(struct tls * ctx)33072c33676SMaxim Ag tls_conn_session_resumed(struct tls *ctx)
33172c33676SMaxim Ag {
33272c33676SMaxim Ag 	if (ctx->conninfo == NULL)
33372c33676SMaxim Ag 		return (0);
33472c33676SMaxim Ag 	return (ctx->conninfo->session_resumed);
33572c33676SMaxim Ag }
33672c33676SMaxim Ag 
33772c33676SMaxim Ag const char *
tls_conn_version(struct tls * ctx)338f5b1c8a1SJohn Marino tls_conn_version(struct tls *ctx)
339f5b1c8a1SJohn Marino {
340f5b1c8a1SJohn Marino 	if (ctx->conninfo == NULL)
341f5b1c8a1SJohn Marino 		return (NULL);
342f5b1c8a1SJohn Marino 	return (ctx->conninfo->version);
343f5b1c8a1SJohn Marino }
344