1 /* $OpenBSD: tls_conninfo.c,v 1.24 2023/11/13 10:51:49 tb Exp $ */
3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2015 Bob Beck <beck@openbsd.org>
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.
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.
24 #include <openssl/x509.h>
27 #include "tls_internal.h"
29 int ASN1_time_tm_clamp_notafter(struct tm *tm);
32 tls_hex_string(const unsigned char *in, size_t inlen, char **out,
35 static const char hex[] = "0123456789abcdef";
42 if (inlen >= SIZE_MAX)
44 if ((*out = reallocarray(NULL, inlen + 1, 2)) == NULL)
49 for (i = 0; i < inlen; i++) {
50 p[len++] = hex[(in[i] >> 4) & 0x0f];
51 p[len++] = hex[in[i] & 0x0f];
62 tls_get_peer_cert_hash(struct tls *ctx, char **hash)
65 if (ctx->ssl_peer_cert == NULL)
68 if (tls_cert_hash(ctx->ssl_peer_cert, hash) == -1) {
69 tls_set_errorx(ctx, "unable to compute peer certificate hash - out of memory");
77 tls_get_peer_cert_issuer(struct tls *ctx, char **issuer)
79 X509_NAME *name = NULL;
82 if (ctx->ssl_peer_cert == NULL)
84 if ((name = X509_get_issuer_name(ctx->ssl_peer_cert)) == NULL)
86 *issuer = X509_NAME_oneline(name, 0, 0);
93 tls_get_peer_cert_subject(struct tls *ctx, char **subject)
95 X509_NAME *name = NULL;
98 if (ctx->ssl_peer_cert == NULL)
100 if ((name = X509_get_subject_name(ctx->ssl_peer_cert)) == NULL)
102 *subject = X509_NAME_oneline(name, 0, 0);
103 if (*subject == NULL)
109 tls_get_peer_cert_times(struct tls *ctx, time_t *notbefore,
112 struct tm before_tm, after_tm;
113 ASN1_TIME *before, *after;
115 if (ctx->ssl_peer_cert == NULL)
118 if ((before = X509_get_notBefore(ctx->ssl_peer_cert)) == NULL)
120 if ((after = X509_get_notAfter(ctx->ssl_peer_cert)) == NULL)
122 if (!ASN1_TIME_to_tm(before, &before_tm))
124 if (!ASN1_TIME_to_tm(after, &after_tm))
126 if (!ASN1_time_tm_clamp_notafter(&after_tm))
128 if ((*notbefore = timegm(&before_tm)) == -1)
130 if ((*notafter = timegm(&after_tm)) == -1)
140 tls_get_peer_cert_info(struct tls *ctx)
142 if (ctx->ssl_peer_cert == NULL)
145 if (tls_get_peer_cert_hash(ctx, &ctx->conninfo->hash) == -1)
147 if (tls_get_peer_cert_subject(ctx, &ctx->conninfo->subject) == -1)
149 if (tls_get_peer_cert_issuer(ctx, &ctx->conninfo->issuer) == -1)
151 if (tls_get_peer_cert_times(ctx, &ctx->conninfo->notbefore,
152 &ctx->conninfo->notafter) == -1)
162 tls_conninfo_alpn_proto(struct tls *ctx)
164 const unsigned char *p;
167 free(ctx->conninfo->alpn);
168 ctx->conninfo->alpn = NULL;
170 SSL_get0_alpn_selected(ctx->ssl_conn, &p, &len);
172 if ((ctx->conninfo->alpn = malloc(len + 1)) == NULL)
174 memcpy(ctx->conninfo->alpn, p, len);
175 ctx->conninfo->alpn[len] = '\0';
182 tls_conninfo_cert_pem(struct tls *ctx)
186 BUF_MEM *bptr = NULL;
188 if (ctx->ssl_peer_cert == NULL)
190 if ((membio = BIO_new(BIO_s_mem()))== NULL)
194 * We have to write the peer cert out separately, because
195 * the certificate chain may or may not contain it.
197 if (!PEM_write_bio_X509(membio, ctx->ssl_peer_cert))
199 for (i = 0; i < sk_X509_num(ctx->ssl_peer_chain); i++) {
200 X509 *chaincert = sk_X509_value(ctx->ssl_peer_chain, i);
201 if (chaincert != ctx->ssl_peer_cert &&
202 !PEM_write_bio_X509(membio, chaincert))
206 BIO_get_mem_ptr(membio, &bptr);
207 free(ctx->conninfo->peer_cert);
208 ctx->conninfo->peer_cert_len = 0;
209 if ((ctx->conninfo->peer_cert = malloc(bptr->length)) == NULL)
211 ctx->conninfo->peer_cert_len = bptr->length;
212 memcpy(ctx->conninfo->peer_cert, bptr->data,
213 ctx->conninfo->peer_cert_len);
215 /* BIO_free() will kill BUF_MEM - because we have not set BIO_NOCLOSE */
223 tls_conninfo_session(struct tls *ctx)
225 ctx->conninfo->session_resumed = SSL_session_reused(ctx->ssl_conn);
231 tls_conninfo_populate(struct tls *ctx)
235 tls_conninfo_free(ctx->conninfo);
237 if ((ctx->conninfo = calloc(1, sizeof(struct tls_conninfo))) == NULL) {
238 tls_set_errorx(ctx, "out of memory");
242 if (tls_conninfo_alpn_proto(ctx) == -1)
245 if ((tmp = SSL_get_cipher(ctx->ssl_conn)) == NULL)
247 if ((ctx->conninfo->cipher = strdup(tmp)) == NULL)
249 ctx->conninfo->cipher_strength = SSL_get_cipher_bits(ctx->ssl_conn, NULL);
251 if (ctx->servername != NULL) {
252 if ((ctx->conninfo->servername =
253 strdup(ctx->servername)) == NULL)
257 if ((tmp = SSL_get_version(ctx->ssl_conn)) == NULL)
259 if ((ctx->conninfo->version = strdup(tmp)) == NULL)
262 if (tls_get_peer_cert_info(ctx) == -1)
265 if (tls_conninfo_cert_pem(ctx) == -1)
268 if (tls_conninfo_session(ctx) == -1)
274 tls_conninfo_free(ctx->conninfo);
275 ctx->conninfo = NULL;
281 tls_conninfo_free(struct tls_conninfo *conninfo)
283 if (conninfo == NULL)
286 free(conninfo->alpn);
287 free(conninfo->cipher);
288 free(conninfo->servername);
289 free(conninfo->version);
291 free(conninfo->hash);
292 free(conninfo->issuer);
293 free(conninfo->subject);
295 free(conninfo->peer_cert);
301 tls_conn_alpn_selected(struct tls *ctx)
303 if (ctx->conninfo == NULL)
305 return (ctx->conninfo->alpn);
309 tls_conn_cipher(struct tls *ctx)
311 if (ctx->conninfo == NULL)
313 return (ctx->conninfo->cipher);
317 tls_conn_cipher_strength(struct tls *ctx)
319 if (ctx->conninfo == NULL)
321 return (ctx->conninfo->cipher_strength);
325 tls_conn_servername(struct tls *ctx)
327 if (ctx->conninfo == NULL)
329 return (ctx->conninfo->servername);
333 tls_conn_session_resumed(struct tls *ctx)
335 if (ctx->conninfo == NULL)
337 return (ctx->conninfo->session_resumed);
341 tls_conn_version(struct tls *ctx)
343 if (ctx->conninfo == NULL)
345 return (ctx->conninfo->version);