summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortb <>2024-12-10 08:40:30 +0000
committertb <>2024-12-10 08:40:30 +0000
commitb3d93b59d26fa80123892302071d566ee8f30930 (patch)
tree2542f39bf15e49eda926e59376de19e797b35c50 /src
parentc0f2dde01da58c00510ac95afabe0df82b7374ec (diff)
downloadopenbsd-b3d93b59d26fa80123892302071d566ee8f30930.tar.gz
openbsd-b3d93b59d26fa80123892302071d566ee8f30930.tar.bz2
openbsd-b3d93b59d26fa80123892302071d566ee8f30930.zip
Provide tls_peer_cert_common_name()
There is currently no sane way of getting your hands on the common name or subject alternative name of the peer certificate from libtls. It is possible to extract it from the peer cert's PEM by hand, but that way lies madness. While the common name is close to being deprecated in the webpki, it is still the de facto standard to identify client certs. It would be nice to have a way to access the subject alternative names as well, but this is a lot more difficult to expose in a clean and sane C interface due to its multivaluedness. Initial diff from henning, with input from beck, jsing and myself henning and bluhm have plans of using this in syslogd. ok beck
Diffstat (limited to 'src')
-rw-r--r--src/lib/libtls/tls.h3
-rw-r--r--src/lib/libtls/tls_conninfo.c14
-rw-r--r--src/lib/libtls/tls_internal.h5
-rw-r--r--src/lib/libtls/tls_peer.c10
-rw-r--r--src/lib/libtls/tls_verify.c97
5 files changed, 105 insertions, 24 deletions
diff --git a/src/lib/libtls/tls.h b/src/lib/libtls/tls.h
index 6b36886dc3..5a3a6254ab 100644
--- a/src/lib/libtls/tls.h
+++ b/src/lib/libtls/tls.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls.h,v 1.67 2024/08/02 15:00:01 tb Exp $ */ 1/* $OpenBSD: tls.h,v 1.68 2024/12/10 08:40:30 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -200,6 +200,7 @@ int tls_close(struct tls *_ctx);
200int tls_peer_cert_provided(struct tls *_ctx); 200int tls_peer_cert_provided(struct tls *_ctx);
201int tls_peer_cert_contains_name(struct tls *_ctx, const char *_name); 201int tls_peer_cert_contains_name(struct tls *_ctx, const char *_name);
202 202
203const char *tls_peer_cert_common_name(struct tls *_ctx);
203const char *tls_peer_cert_hash(struct tls *_ctx); 204const char *tls_peer_cert_hash(struct tls *_ctx);
204const char *tls_peer_cert_issuer(struct tls *_ctx); 205const char *tls_peer_cert_issuer(struct tls *_ctx);
205const char *tls_peer_cert_subject(struct tls *_ctx); 206const char *tls_peer_cert_subject(struct tls *_ctx);
diff --git a/src/lib/libtls/tls_conninfo.c b/src/lib/libtls/tls_conninfo.c
index bf525170f1..8fb56c92b7 100644
--- a/src/lib/libtls/tls_conninfo.c
+++ b/src/lib/libtls/tls_conninfo.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_conninfo.c,v 1.27 2024/03/26 06:31:22 jsing Exp $ */ 1/* $OpenBSD: tls_conninfo.c,v 1.28 2024/12/10 08:40:30 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2015 Bob Beck <beck@openbsd.org> 4 * Copyright (c) 2015 Bob Beck <beck@openbsd.org>
@@ -119,6 +119,14 @@ tls_get_peer_cert_subject(struct tls *ctx, char **subject)
119} 119}
120 120
121static int 121static int
122tls_get_peer_cert_common_name(struct tls *ctx, char **common_name)
123{
124 if (ctx->ssl_peer_cert == NULL)
125 return (-1);
126 return tls_get_common_name(ctx, ctx->ssl_peer_cert, NULL, common_name);
127}
128
129static int
122tls_get_peer_cert_times(struct tls *ctx, time_t *notbefore, 130tls_get_peer_cert_times(struct tls *ctx, time_t *notbefore,
123 time_t *notafter) 131 time_t *notafter)
124{ 132{
@@ -158,6 +166,9 @@ tls_get_peer_cert_info(struct tls *ctx)
158 goto err; 166 goto err;
159 if (tls_get_peer_cert_issuer(ctx, &ctx->conninfo->issuer) == -1) 167 if (tls_get_peer_cert_issuer(ctx, &ctx->conninfo->issuer) == -1)
160 goto err; 168 goto err;
169 if (tls_get_peer_cert_common_name(ctx,
170 &ctx->conninfo->common_name) == -1)
171 goto err;
161 if (tls_get_peer_cert_times(ctx, &ctx->conninfo->notbefore, 172 if (tls_get_peer_cert_times(ctx, &ctx->conninfo->notbefore,
162 &ctx->conninfo->notafter) == -1) 173 &ctx->conninfo->notafter) == -1)
163 goto err; 174 goto err;
@@ -298,6 +309,7 @@ tls_conninfo_free(struct tls_conninfo *conninfo)
298 free(conninfo->servername); 309 free(conninfo->servername);
299 free(conninfo->version); 310 free(conninfo->version);
300 311
312 free(conninfo->common_name);
301 free(conninfo->hash); 313 free(conninfo->hash);
302 free(conninfo->issuer); 314 free(conninfo->issuer);
303 free(conninfo->subject); 315 free(conninfo->subject);
diff --git a/src/lib/libtls/tls_internal.h b/src/lib/libtls/tls_internal.h
index 5ff48ed7c9..8e566a34e0 100644
--- a/src/lib/libtls/tls_internal.h
+++ b/src/lib/libtls/tls_internal.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_internal.h,v 1.85 2024/03/26 06:24:52 joshua Exp $ */ 1/* $OpenBSD: tls_internal.h,v 1.86 2024/12/10 08:40:30 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org> 3 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
4 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 4 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
@@ -129,6 +129,7 @@ struct tls_conninfo {
129 int session_resumed; 129 int session_resumed;
130 char *version; 130 char *version;
131 131
132 char *common_name;
132 char *hash; 133 char *hash;
133 char *issuer; 134 char *issuer;
134 char *subject; 135 char *subject;
@@ -238,6 +239,8 @@ struct tls_config *tls_config_new_internal(void);
238struct tls *tls_new(void); 239struct tls *tls_new(void);
239struct tls *tls_server_conn(struct tls *ctx); 240struct tls *tls_server_conn(struct tls *ctx);
240 241
242int tls_get_common_name(struct tls *_ctx, X509 *_cert, const char *_in_name,
243 char **_out_common_name);
241int tls_check_name(struct tls *ctx, X509 *cert, const char *servername, 244int tls_check_name(struct tls *ctx, X509 *cert, const char *servername,
242 int *match); 245 int *match);
243int tls_configure_server(struct tls *ctx); 246int tls_configure_server(struct tls *ctx);
diff --git a/src/lib/libtls/tls_peer.c b/src/lib/libtls/tls_peer.c
index ec97a30838..6d63a529f2 100644
--- a/src/lib/libtls/tls_peer.c
+++ b/src/lib/libtls/tls_peer.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_peer.c,v 1.8 2017/04/10 17:11:13 jsing Exp $ */ 1/* $OpenBSD: tls_peer.c,v 1.9 2024/12/10 08:40:30 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2015 Bob Beck <beck@openbsd.org> 4 * Copyright (c) 2015 Bob Beck <beck@openbsd.org>
@@ -24,6 +24,14 @@
24#include "tls_internal.h" 24#include "tls_internal.h"
25 25
26const char * 26const char *
27tls_peer_cert_common_name(struct tls *ctx)
28{
29 if (ctx->conninfo == NULL)
30 return (NULL);
31 return (ctx->conninfo->common_name);
32}
33
34const char *
27tls_peer_cert_hash(struct tls *ctx) 35tls_peer_cert_hash(struct tls *ctx)
28{ 36{
29 if (ctx->conninfo == NULL) 37 if (ctx->conninfo == NULL)
diff --git a/src/lib/libtls/tls_verify.c b/src/lib/libtls/tls_verify.c
index 6b2a4fb82a..2935278383 100644
--- a/src/lib/libtls/tls_verify.c
+++ b/src/lib/libtls/tls_verify.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_verify.c,v 1.31 2024/11/12 22:50:06 tb Exp $ */ 1/* $OpenBSD: tls_verify.c,v 1.32 2024/12/10 08:40:30 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org> 3 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
4 * 4 *
@@ -210,19 +210,22 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
210} 210}
211 211
212static int 212static int
213tls_check_common_name(struct tls *ctx, X509 *cert, const char *name, 213tls_get_common_name_internal(X509 *cert, char **out_common_name,
214 int *cn_match) 214 unsigned int *out_tlserr, const char **out_errstr)
215{ 215{
216 unsigned char *utf8_bytes = NULL; 216 unsigned char *utf8_bytes = NULL;
217 X509_NAME *subject_name; 217 X509_NAME *subject_name;
218 char *common_name = NULL; 218 char *common_name = NULL;
219 union tls_addr addrbuf;
220 int common_name_len; 219 int common_name_len;
221 ASN1_STRING *data; 220 ASN1_STRING *data;
222 int lastpos = -1; 221 int lastpos = -1;
223 int rv = -1; 222 int rv = -1;
224 223
225 *cn_match = 0; 224 *out_tlserr = TLS_ERROR_UNKNOWN;
225 *out_errstr = "unknown";
226
227 free(*out_common_name);
228 *out_common_name = NULL;
226 229
227 subject_name = X509_get_subject_name(cert); 230 subject_name = X509_get_subject_name(cert);
228 if (subject_name == NULL) 231 if (subject_name == NULL)
@@ -244,10 +247,10 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
244 * more than one CN fed to us in the subject, treating the 247 * more than one CN fed to us in the subject, treating the
245 * certificate as hostile. 248 * certificate as hostile.
246 */ 249 */
247 tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, 250 *out_tlserr = TLS_ERROR_UNKNOWN;
248 "error verifying name '%s': " 251 *out_errstr = "error getting common name: "
249 "Certificate subject contains multiple Common Name fields, " 252 "Certificate subject contains multiple Common Name fields, "
250 "probably a malicious or malformed certificate", name); 253 "probably a malicious or malformed certificate";
251 goto err; 254 goto err;
252 } 255 }
253 256
@@ -257,10 +260,10 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
257 * Fail if we cannot encode the CN bytes as UTF-8. 260 * Fail if we cannot encode the CN bytes as UTF-8.
258 */ 261 */
259 if ((common_name_len = ASN1_STRING_to_UTF8(&utf8_bytes, data)) < 0) { 262 if ((common_name_len = ASN1_STRING_to_UTF8(&utf8_bytes, data)) < 0) {
260 tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, 263 *out_tlserr = TLS_ERROR_UNKNOWN;
261 "error verifying name '%s': " 264 *out_errstr = "error getting common name: "
262 "Common Name field cannot be encoded as a UTF-8 string, " 265 "Common Name field cannot be encoded as a UTF-8 string, "
263 "probably a malicious certificate", name); 266 "probably a malicious certificate";
264 goto err; 267 goto err;
265 } 268 }
266 /* 269 /*
@@ -268,30 +271,85 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
268 * must be between 1 and 64 bytes long. 271 * must be between 1 and 64 bytes long.
269 */ 272 */
270 if (common_name_len < 1 || common_name_len > 64) { 273 if (common_name_len < 1 || common_name_len > 64) {
271 tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, 274 *out_tlserr = TLS_ERROR_UNKNOWN;
272 "error verifying name '%s': " 275 *out_errstr = "error getting common name: "
273 "Common Name field has invalid length, " 276 "Common Name field has invalid length, "
274 "probably a malicious certificate", name); 277 "probably a malicious certificate";
275 goto err; 278 goto err;
276 } 279 }
277 /* 280 /*
278 * Fail if the resulting text contains a NUL byte. 281 * Fail if the resulting text contains a NUL byte.
279 */ 282 */
280 if (memchr(utf8_bytes, 0, common_name_len) != NULL) { 283 if (memchr(utf8_bytes, 0, common_name_len) != NULL) {
281 tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, 284 *out_tlserr = TLS_ERROR_UNKNOWN;
282 "error verifying name '%s': " 285 *out_errstr = "error getting common name: "
283 "NUL byte in Common Name field, " 286 "NUL byte in Common Name field, "
284 "probably a malicious certificate", name); 287 "probably a malicious certificate";
285 goto err; 288 goto err;
286 } 289 }
287 290
288 common_name = strndup(utf8_bytes, common_name_len); 291 common_name = strndup(utf8_bytes, common_name_len);
289 if (common_name == NULL) { 292 if (common_name == NULL) {
290 tls_set_error(ctx, TLS_ERROR_OUT_OF_MEMORY, 293 *out_tlserr = TLS_ERROR_OUT_OF_MEMORY;
291 "out of memory"); 294 *out_errstr = "out of memory";
295 goto err;
296 }
297
298 *out_common_name = common_name;
299 common_name = NULL;
300
301 done:
302 if (*out_common_name == NULL)
303 *out_common_name = strdup("");
304 if (*out_common_name == NULL) {
305 *out_tlserr = TLS_ERROR_OUT_OF_MEMORY;
306 *out_errstr = "out of memory";
292 goto err; 307 goto err;
293 } 308 }
294 309
310 rv = 0;
311
312 err:
313 free(utf8_bytes);
314 free(common_name);
315 return rv;
316}
317
318int
319tls_get_common_name(struct tls *ctx, X509 *cert, const char *in_name,
320 char **out_common_name)
321{
322 unsigned int errcode = TLS_ERROR_UNKNOWN;
323 const char *errstr = "unknown";
324
325 if (tls_get_common_name_internal(cert, out_common_name, &errcode,
326 &errstr) == -1) {
327 const char *name = in_name;
328 const char *space = " ";
329
330 if (name == NULL)
331 name = space = "";
332
333 tls_set_errorx(ctx, errcode, "%s%s%s", name, space, errstr);
334 return -1;
335 }
336
337 return 0;
338}
339
340static int
341tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
342 int *cn_match)
343{
344 char *common_name = NULL;
345 union tls_addr addrbuf;
346 int rv = -1;
347
348 if (tls_get_common_name(ctx, cert, name, &common_name) == -1)
349 goto err;
350 if (strlen(common_name) == 0)
351 goto done;
352
295 /* 353 /*
296 * We don't want to attempt wildcard matching against IP addresses, 354 * We don't want to attempt wildcard matching against IP addresses,
297 * so perform a simple comparison here. 355 * so perform a simple comparison here.
@@ -310,7 +368,6 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
310 rv = 0; 368 rv = 0;
311 369
312 err: 370 err:
313 free(utf8_bytes);
314 free(common_name); 371 free(common_name);
315 return rv; 372 return rv;
316} 373}