diff options
Diffstat (limited to '')
| -rw-r--r-- | src/lib/libtls/tls_verify.c | 59 |
1 files changed, 47 insertions, 12 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 | |||
| 205 | tls_check_common_name(struct tls *ctx, X509 *cert, const char *name, | 205 | tls_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 | } |
