diff options
Diffstat (limited to 'src/lib/libtls/tls_verify.c')
-rw-r--r-- | src/lib/libtls/tls_verify.c | 97 |
1 files changed, 77 insertions, 20 deletions
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 | ||
212 | static int | 212 | static int |
213 | tls_check_common_name(struct tls *ctx, X509 *cert, const char *name, | 213 | tls_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 | |||
318 | int | ||
319 | tls_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 | |||
340 | static int | ||
341 | tls_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 | } |