summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/libtls/tls_verify.c59
-rw-r--r--src/regress/lib/libtls/verify/verifytest.c6
2 files changed, 51 insertions, 14 deletions
diff --git a/src/lib/libtls/tls_verify.c b/src/lib/libtls/tls_verify.c
index 0cb86f686d..420e278c99 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.23 2023/05/11 07:35:27 tb Exp $ */ 1/* $OpenBSD: tls_verify.c,v 1.24 2023/05/28 09:02:01 beck 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 *
@@ -205,10 +205,13 @@ static int
205tls_check_common_name(struct tls *ctx, X509 *cert, const char *name, 205tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
206 int *cn_match) 206 int *cn_match)
207{ 207{
208 unsigned char *utf8_bytes = NULL;
208 X509_NAME *subject_name; 209 X509_NAME *subject_name;
209 char *common_name = NULL; 210 char *common_name = NULL;
210 union tls_addr addrbuf; 211 union tls_addr addrbuf;
211 int common_name_len; 212 int common_name_len;
213 ASN1_STRING *data;
214 int lastpos = -1;
212 int rv = -1; 215 int rv = -1;
213 216
214 *cn_match = 0; 217 *cn_match = 0;
@@ -217,29 +220,60 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
217 if (subject_name == NULL) 220 if (subject_name == NULL)
218 goto done; 221 goto done;
219 222
220 common_name_len = X509_NAME_get_text_by_NID(subject_name, 223 lastpos = X509_NAME_get_index_by_NID(subject_name,
221 NID_commonName, NULL, 0); 224 NID_commonName, lastpos);
222 if (common_name_len < 0) 225 if (lastpos == -1)
223 goto done; 226 goto done;
227 if (X509_NAME_get_index_by_NID(subject_name, NID_commonName, lastpos)
228 != -1) {
229 /*
230 * Having multiple CN's is possible, and even happened back in
231 * the glory days of mullets and Hammer pants. In anything like
232 * a modern TLS cert, CN is as close to deprecated as it gets,
233 * and having more than one is bad. We therefore fail if we have
234 * more than one CN fed to us in the subject, treating the
235 * certificate as hostile.
236 */
237 tls_set_errorx(ctx, "error verifying name '%s': "
238 "Certificate subject contains mutiple Common Name fields, "
239 "probably a malicious or malformed certificate", name);
240 goto err;
241 }
224 242
225 common_name = calloc(common_name_len + 1, 1); 243 data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject_name,
226 if (common_name == NULL) { 244 lastpos));
227 tls_set_error(ctx, "out of memory"); 245 /*
246 * Fail if we cannot encode as UTF-8, or if the UTF-8 encoding of the
247 * string contains a 0 byte. We treat any certificate with such data
248 * in the CN as hostile and fail.
249 */
250 if ((common_name_len = ASN1_STRING_to_UTF8(&utf8_bytes, data)) < 0) {
251 tls_set_errorx(ctx, "error verifying name '%s': "
252 "Common Name field cannot be encoded as a UTF-8 string, "
253 "probably a malicious certificate", name);
228 goto err; 254 goto err;
229 } 255 }
230 256
231 X509_NAME_get_text_by_NID(subject_name, NID_commonName, common_name, 257 if (common_name_len < 1 || common_name_len > 64) {
232 common_name_len + 1); 258 tls_set_errorx(ctx, "error verifying name '%s': "
259 "Common Name field has invalid length, "
260 "probably a malicious certificate", name);
261 goto err;
262 }
233 263
234 /* NUL bytes in CN? */ 264 if (memchr(utf8_bytes, 0, common_name_len) != NULL) {
235 if (common_name_len < 0 ||
236 (size_t)common_name_len != strlen(common_name)) {
237 tls_set_errorx(ctx, "error verifying name '%s': " 265 tls_set_errorx(ctx, "error verifying name '%s': "
238 "NUL byte in Common Name field, " 266 "NUL byte in Common Name field, "
239 "probably a malicious certificate", name); 267 "probably a malicious certificate", name);
240 goto err; 268 goto err;
241 } 269 }
242 270
271 common_name = strndup(utf8_bytes, common_name_len);
272 if (common_name == NULL) {
273 tls_set_error(ctx, "out of memory");
274 goto err;
275 }
276
243 /* 277 /*
244 * We don't want to attempt wildcard matching against IP addresses, 278 * We don't want to attempt wildcard matching against IP addresses,
245 * so perform a simple comparison here. 279 * so perform a simple comparison here.
@@ -258,6 +292,7 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
258 rv = 0; 292 rv = 0;
259 293
260 err: 294 err:
295 free(utf8_bytes);
261 free(common_name); 296 free(common_name);
262 return rv; 297 return rv;
263} 298}
diff --git a/src/regress/lib/libtls/verify/verifytest.c b/src/regress/lib/libtls/verify/verifytest.c
index b41b62fcfb..57aa992149 100644
--- a/src/regress/lib/libtls/verify/verifytest.c
+++ b/src/regress/lib/libtls/verify/verifytest.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: verifytest.c,v 1.7 2017/04/30 03:53:31 jsing Exp $ */ 1/* $OpenBSD: verifytest.c,v 1.8 2023/05/28 09:02:01 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -40,6 +40,7 @@ struct verify_test {
40 const char name[128]; 40 const char name[128];
41 int want_return; 41 int want_return;
42 int want_match; 42 int want_match;
43 int name_type;
43}; 44};
44 45
45struct verify_test verify_tests[] = { 46struct verify_test verify_tests[] = {
@@ -474,7 +475,8 @@ do_verify_test(int test_no, struct verify_test *vt)
474 if ((name = X509_NAME_new()) == NULL) 475 if ((name = X509_NAME_new()) == NULL)
475 errx(1, "failed to malloc X509_NAME"); 476 errx(1, "failed to malloc X509_NAME");
476 if (X509_NAME_add_entry_by_NID(name, NID_commonName, 477 if (X509_NAME_add_entry_by_NID(name, NID_commonName,
477 MBSTRING_ASC, (unsigned char *)vt->common_name, 478 vt->name_type ? vt->name_type : MBSTRING_ASC,
479 (unsigned char *)vt->common_name,
478 vt->common_name_len, -1, 0) == 0) 480 vt->common_name_len, -1, 0) == 0)
479 errx(1, "failed to add name entry"); 481 errx(1, "failed to add name entry");
480 if (X509_set_subject_name(cert, name) == 0) 482 if (X509_set_subject_name(cert, name) == 0)