Skip to content

Commit 1e41dad

Browse files
committed
Extend X509 cert checks and error reporting in v3_{purp,crld}.c and x509_{set,vfy}.c
add various checks for malformedness to static check_chain_extensions() in x509_vfc.c improve error reporting of X509v3_cache_extensions() in v3_purp.c add error reporting to x509_init_sig_info() in x509_set.c improve static setup_dp() and related functions in v3_purp.c and v3_crld.c add test case for non-conforming cert from https://tools.ietf.org/html/rfc8410#section-10.2 Reviewed-by: Kurt Roeckx <[email protected]> Reviewed-by: Tomas Mraz <[email protected]> (Merged from #12478)
1 parent b0a4cbe commit 1e41dad

File tree

16 files changed

+398
-178
lines changed

16 files changed

+398
-178
lines changed

crypto/err/openssl.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3487,6 +3487,7 @@ X509V3_R_BN_TO_ASN1_INTEGER_ERROR:101:bn to asn1 integer error
34873487
X509V3_R_DIRNAME_ERROR:149:dirname error
34883488
X509V3_R_DISTPOINT_ALREADY_SET:160:distpoint already set
34893489
X509V3_R_DUPLICATE_ZONE_ID:133:duplicate zone id
3490+
X509V3_R_EMPTY_KEY_USAGE:169:empty key usage
34903491
X509V3_R_ERROR_CONVERTING_ZONE:131:error converting zone
34913492
X509V3_R_ERROR_CREATING_EXTENSION:144:error creating extension
34923493
X509V3_R_ERROR_IN_EXTENSION:128:error in extension
@@ -3501,6 +3502,7 @@ X509V3_R_INCORRECT_POLICY_SYNTAX_TAG:152:incorrect policy syntax tag
35013502
X509V3_R_INVALID_ASNUMBER:162:invalid asnumber
35023503
X509V3_R_INVALID_ASRANGE:163:invalid asrange
35033504
X509V3_R_INVALID_BOOLEAN_STRING:104:invalid boolean string
3505+
X509V3_R_INVALID_CERTIFICATE:158:invalid certificate
35043506
X509V3_R_INVALID_EMPTY_NAME:108:invalid empty name
35053507
X509V3_R_INVALID_EXTENSION_STRING:105:invalid extension string
35063508
X509V3_R_INVALID_INHERITANCE:165:invalid inheritance
@@ -3522,6 +3524,7 @@ X509V3_R_INVALID_SYNTAX:143:invalid syntax
35223524
X509V3_R_ISSUER_DECODE_ERROR:126:issuer decode error
35233525
X509V3_R_MISSING_VALUE:124:missing value
35243526
X509V3_R_NEED_ORGANIZATION_AND_NUMBERS:142:need organization and numbers
3527+
X509V3_R_NEGATIVE_PATHLEN:168:negative pathlen
35253528
X509V3_R_NO_CONFIG_DATABASE:136:no config database
35263529
X509V3_R_NO_ISSUER_CERTIFICATE:121:no issuer certificate
35273530
X509V3_R_NO_ISSUER_DETAILS:127:no issuer details
@@ -3557,9 +3560,12 @@ X509_R_CERTIFICATE_VERIFICATION_FAILED:139:certificate verification failed
35573560
X509_R_CERT_ALREADY_IN_HASH_TABLE:101:cert already in hash table
35583561
X509_R_CRL_ALREADY_DELTA:127:crl already delta
35593562
X509_R_CRL_VERIFY_FAILURE:131:crl verify failure
3563+
X509_R_ERROR_GETTING_MD_BY_NID:141:error getting md by nid
3564+
X509_R_ERROR_USING_SIGINF_SET:142:error using siginf set
35603565
X509_R_IDP_MISMATCH:128:idp mismatch
35613566
X509_R_INVALID_ATTRIBUTES:138:invalid attributes
35623567
X509_R_INVALID_DIRECTORY:113:invalid directory
3568+
X509_R_INVALID_DISTPOINT:143:invalid distpoint
35633569
X509_R_INVALID_FIELD_NAME:119:invalid field name
35643570
X509_R_INVALID_TRUST:123:invalid trust
35653571
X509_R_ISSUER_MISMATCH:129:issuer mismatch
@@ -3583,6 +3589,7 @@ X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY:108:unable to get certs public key
35833589
X509_R_UNKNOWN_KEY_TYPE:117:unknown key type
35843590
X509_R_UNKNOWN_NID:109:unknown nid
35853591
X509_R_UNKNOWN_PURPOSE_ID:121:unknown purpose id
3592+
X509_R_UNKNOWN_SIGID_ALGS:144:unknown sigid algs
35863593
X509_R_UNKNOWN_TRUST_ID:120:unknown trust id
35873594
X509_R_UNSUPPORTED_ALGORITHM:111:unsupported algorithm
35883595
X509_R_WRONG_LOOKUP_TYPE:112:wrong lookup type

crypto/x509/v3_crld.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -485,30 +485,31 @@ static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out,
485485
return 1;
486486
}
487487

488+
/* Append any nameRelativeToCRLIssuer in dpn to iname, set in dpn->dpname */
488489
int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, const X509_NAME *iname)
489490
{
490491
int i;
491492
STACK_OF(X509_NAME_ENTRY) *frag;
492493
X509_NAME_ENTRY *ne;
493-
if (!dpn || (dpn->type != 1))
494+
495+
if (dpn == NULL || dpn->type != 1)
494496
return 1;
495497
frag = dpn->name.relativename;
498+
X509_NAME_free(dpn->dpname); /* just in case it was already set */
496499
dpn->dpname = X509_NAME_dup(iname);
497-
if (!dpn->dpname)
500+
if (dpn->dpname == NULL)
498501
return 0;
499502
for (i = 0; i < sk_X509_NAME_ENTRY_num(frag); i++) {
500503
ne = sk_X509_NAME_ENTRY_value(frag, i);
501-
if (!X509_NAME_add_entry(dpn->dpname, ne, -1, i ? 0 : 1)) {
502-
X509_NAME_free(dpn->dpname);
503-
dpn->dpname = NULL;
504-
return 0;
505-
}
504+
if (!X509_NAME_add_entry(dpn->dpname, ne, -1, i ? 0 : 1))
505+
goto err;
506506
}
507507
/* generate cached encoding of name */
508-
if (i2d_X509_NAME(dpn->dpname, NULL) < 0) {
509-
X509_NAME_free(dpn->dpname);
510-
dpn->dpname = NULL;
511-
return 0;
512-
}
513-
return 1;
508+
if (i2d_X509_NAME(dpn->dpname, NULL) >= 0)
509+
return 1;
510+
511+
err:
512+
X509_NAME_free(dpn->dpname);
513+
dpn->dpname = NULL;
514+
return 0;
514515
}

crypto/x509/v3_purp.c

Lines changed: 71 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -305,44 +305,62 @@ int X509_supported_extension(X509_EXTENSION *ex)
305305
return 0;
306306
}
307307

308-
static int setup_dp(X509 *x, DIST_POINT *dp)
308+
/* return 1 on success, 0 if x is invalid, -1 on (internal) error */
309+
static int setup_dp(const X509 *x, DIST_POINT *dp)
309310
{
310311
const X509_NAME *iname = NULL;
311312
int i;
312313

313-
if (dp->reasons) {
314+
if (dp->distpoint == NULL && sk_GENERAL_NAME_num(dp->CRLissuer) <= 0) {
315+
X509err(0, X509_R_INVALID_DISTPOINT);
316+
return 0;
317+
}
318+
if (dp->reasons != NULL) {
314319
if (dp->reasons->length > 0)
315320
dp->dp_reasons = dp->reasons->data[0];
316321
if (dp->reasons->length > 1)
317322
dp->dp_reasons |= (dp->reasons->data[1] << 8);
318323
dp->dp_reasons &= CRLDP_ALL_REASONS;
319-
} else
324+
} else {
320325
dp->dp_reasons = CRLDP_ALL_REASONS;
321-
if (!dp->distpoint || (dp->distpoint->type != 1))
326+
}
327+
if (dp->distpoint == NULL || dp->distpoint->type != 1)
322328
return 1;
329+
330+
/* handle name fragment given by nameRelativeToCRLIssuer */
331+
/*
332+
* Note that the below way of determining iname is not really compliant
333+
* with https://tools.ietf.org/html/rfc5280#section-4.2.1.13
334+
* According to it, sk_GENERAL_NAME_num(dp->CRLissuer) MUST be <= 1
335+
* and any CRLissuer could be of type different to GEN_DIRNAME.
336+
*/
323337
for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) {
324338
GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
339+
325340
if (gen->type == GEN_DIRNAME) {
326341
iname = gen->d.directoryName;
327342
break;
328343
}
329344
}
330-
if (!iname)
345+
if (iname == NULL)
331346
iname = X509_get_issuer_name(x);
332-
333-
return DIST_POINT_set_dpname(dp->distpoint, iname);
347+
return DIST_POINT_set_dpname(dp->distpoint, iname) ? 1 : -1;
334348
}
335349

350+
/* return 1 on success, 0 if x is invalid, -1 on (internal) error */
336351
static int setup_crldp(X509 *x)
337352
{
338353
int i;
339354

340355
x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &i, NULL);
341356
if (x->crldp == NULL && i != -1)
342357
return 0;
358+
343359
for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) {
344-
if (!setup_dp(x, sk_DIST_POINT_value(x->crldp, i)))
345-
return 0;
360+
int res = setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
361+
362+
if (res < 1)
363+
return res;
346364
}
347365
return 1;
348366
}
@@ -373,6 +391,7 @@ static int check_sig_alg_match(const EVP_PKEY *pkey, const X509 *subject)
373391
/*
374392
* Cache info on various X.509v3 extensions and further derived information,
375393
* e.g., if cert 'x' is self-issued, in x->ex_flags and other internal fields.
394+
* X509_SIG_INFO_VALID is set in x->flags if x->siginf was filled successfully.
376395
* Set EXFLAG_INVALID and return 0 in case the certificate is invalid.
377396
*/
378397
int x509v3_cache_extensions(X509 *x)
@@ -384,6 +403,7 @@ int x509v3_cache_extensions(X509 *x)
384403
EXTENDED_KEY_USAGE *extusage;
385404
X509_EXTENSION *ex;
386405
int i;
406+
int res;
387407

388408
#ifdef tsan_ld_acq
389409
/* fast lock-free check, see end of the function for details. */
@@ -398,30 +418,34 @@ int x509v3_cache_extensions(X509 *x)
398418
}
399419
ERR_set_mark();
400420

421+
/* Cache the SHA1 digest of the cert */
401422
if (!X509_digest(x, EVP_sha1(), x->sha1_hash, NULL))
402-
x->ex_flags |= EXFLAG_INVALID;
423+
/*
424+
* Note that the cert is marked invalid also on internal malloc failure
425+
* or on failure of EVP_MD_fetch(), potentially called by X509_digest().
426+
*/
427+
x->ex_flags |= EXFLAG_INVALID;
403428

404429
/* V1 should mean no extensions ... */
405430
if (X509_get_version(x) == 0)
406431
x->ex_flags |= EXFLAG_V1;
407432

408433
/* Handle basic constraints */
434+
x->ex_pathlen = -1;
409435
if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &i, NULL)) != NULL) {
410436
if (bs->ca)
411437
x->ex_flags |= EXFLAG_CA;
412438
if (bs->pathlen != NULL) {
439+
/*
440+
* the error case !bs->ca is checked by check_chain_extensions()
441+
* in case ctx->param->flags & X509_V_FLAG_X509_STRICT
442+
*/
413443
if (bs->pathlen->type == V_ASN1_NEG_INTEGER) {
444+
X509err(0, X509V3_R_NEGATIVE_PATHLEN);
414445
x->ex_flags |= EXFLAG_INVALID;
415-
x->ex_pathlen = 0;
416446
} else {
417447
x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
418-
if (!bs->ca && x->ex_pathlen != 0) {
419-
x->ex_flags |= EXFLAG_INVALID;
420-
x->ex_pathlen = 0;
421-
}
422448
}
423-
} else {
424-
x->ex_pathlen = -1;
425449
}
426450
BASIC_CONSTRAINTS_free(bs);
427451
x->ex_flags |= EXFLAG_BCONS;
@@ -436,17 +460,17 @@ int x509v3_cache_extensions(X509 *x)
436460
|| X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) {
437461
x->ex_flags |= EXFLAG_INVALID;
438462
}
439-
if (pci->pcPathLengthConstraint) {
463+
if (pci->pcPathLengthConstraint != NULL)
440464
x->ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint);
441-
} else
465+
else
442466
x->ex_pcpathlen = -1;
443467
PROXY_CERT_INFO_EXTENSION_free(pci);
444468
x->ex_flags |= EXFLAG_PROXY;
445469
} else if (i != -1) {
446470
x->ex_flags |= EXFLAG_INVALID;
447471
}
448472

449-
/* Handle (basic and extended) key usage */
473+
/* Handle basic key usage */
450474
if ((usage = X509_get_ext_d2i(x, NID_key_usage, &i, NULL)) != NULL) {
451475
x->ex_kusage = 0;
452476
if (usage->length > 0) {
@@ -456,9 +480,16 @@ int x509v3_cache_extensions(X509 *x)
456480
}
457481
x->ex_flags |= EXFLAG_KUSAGE;
458482
ASN1_BIT_STRING_free(usage);
483+
/* Check for empty key usage according to RFC 5280 section 4.2.1.3 */
484+
if (x->ex_kusage == 0) {
485+
X509err(0, X509V3_R_EMPTY_KEY_USAGE);
486+
x->ex_flags |= EXFLAG_INVALID;
487+
}
459488
} else if (i != -1) {
460489
x->ex_flags |= EXFLAG_INVALID;
461490
}
491+
492+
/* Handle extended key usage */
462493
x->ex_xkusage = 0;
463494
if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, &i, NULL)) != NULL) {
464495
x->ex_flags |= EXFLAG_XKUSAGE;
@@ -493,6 +524,7 @@ int x509v3_cache_extensions(X509 *x)
493524
x->ex_xkusage |= XKU_ANYEKU;
494525
break;
495526
default:
527+
/* ignore unknown extended key usage */
496528
break;
497529
}
498530
}
@@ -517,6 +549,7 @@ int x509v3_cache_extensions(X509 *x)
517549
x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, &i, NULL);
518550
if (x->skid == NULL && i != -1)
519551
x->ex_flags |= EXFLAG_INVALID;
552+
520553
x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &i, NULL);
521554
if (x->akid == NULL && i != -1)
522555
x->ex_flags |= EXFLAG_INVALID;
@@ -538,8 +571,13 @@ int x509v3_cache_extensions(X509 *x)
538571
x->nc = X509_get_ext_d2i(x, NID_name_constraints, &i, NULL);
539572
if (x->nc == NULL && i != -1)
540573
x->ex_flags |= EXFLAG_INVALID;
541-
if (!setup_crldp(x))
574+
575+
/* Handle CRL distribution point entries */
576+
res = setup_crldp(x);
577+
if (res == 0)
542578
x->ex_flags |= EXFLAG_INVALID;
579+
else if (res < 0)
580+
goto err;
543581

544582
#ifndef OPENSSL_NO_RFC3779
545583
x->rfc3779_addr = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &i, NULL);
@@ -551,8 +589,7 @@ int x509v3_cache_extensions(X509 *x)
551589
#endif
552590
for (i = 0; i < X509_get_ext_count(x); i++) {
553591
ex = X509_get_ext(x, i);
554-
if (OBJ_obj2nid(X509_EXTENSION_get_object(ex))
555-
== NID_freshest_crl)
592+
if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == NID_freshest_crl)
556593
x->ex_flags |= EXFLAG_FRESHEST;
557594
if (!X509_EXTENSION_get_critical(ex))
558595
continue;
@@ -562,7 +599,8 @@ int x509v3_cache_extensions(X509 *x)
562599
}
563600
}
564601

565-
x509_init_sig_info(x);
602+
/* Set x->siginf, ignoring errors due to unsupported algos */
603+
(void)x509_init_sig_info(x);
566604

567605
x->ex_flags |= EXFLAG_SET; /* indicate that cert has been processed */
568606
#ifdef tsan_st_rel
@@ -574,9 +612,16 @@ int x509v3_cache_extensions(X509 *x)
574612
*/
575613
#endif
576614
ERR_pop_to_mark();
577-
CRYPTO_THREAD_unlock(x->lock);
615+
if ((x->ex_flags & EXFLAG_INVALID) == 0) {
616+
CRYPTO_THREAD_unlock(x->lock);
617+
return 1;
618+
}
619+
X509err(0, X509V3_R_INVALID_CERTIFICATE);
578620

579-
return (x->ex_flags & EXFLAG_INVALID) == 0;
621+
err:
622+
x->ex_flags |= EXFLAG_SET; /* indicate that cert has been processed */
623+
CRYPTO_THREAD_unlock(x->lock);
624+
return 0;
580625
}
581626

582627
/*-

crypto/x509/v3err.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ static const ERR_STRING_DATA X509V3_str_reasons[] = {
2424
"distpoint already set"},
2525
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DUPLICATE_ZONE_ID),
2626
"duplicate zone id"},
27+
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EMPTY_KEY_USAGE), "empty key usage"},
2728
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_CONVERTING_ZONE),
2829
"error converting zone"},
2930
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_CREATING_EXTENSION),
@@ -51,6 +52,8 @@ static const ERR_STRING_DATA X509V3_str_reasons[] = {
5152
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_ASRANGE), "invalid asrange"},
5253
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_BOOLEAN_STRING),
5354
"invalid boolean string"},
55+
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_CERTIFICATE),
56+
"invalid certificate"},
5457
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_EXTENSION_STRING),
5558
"invalid extension string"},
5659
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_INHERITANCE),
@@ -84,6 +87,8 @@ static const ERR_STRING_DATA X509V3_str_reasons[] = {
8487
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_MISSING_VALUE), "missing value"},
8588
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS),
8689
"need organization and numbers"},
90+
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NEGATIVE_PATHLEN),
91+
"negative pathlen"},
8792
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_CONFIG_DATABASE),
8893
"no config database"},
8994
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_ISSUER_CERTIFICATE),

crypto/x509/x509_err.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,15 @@ static const ERR_STRING_DATA X509_str_reasons[] = {
2727
{ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_ALREADY_DELTA), "crl already delta"},
2828
{ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_VERIFY_FAILURE),
2929
"crl verify failure"},
30+
{ERR_PACK(ERR_LIB_X509, 0, X509_R_ERROR_GETTING_MD_BY_NID),
31+
"error getting md by nid"},
32+
{ERR_PACK(ERR_LIB_X509, 0, X509_R_ERROR_USING_SIGINF_SET),
33+
"error using siginf set"},
3034
{ERR_PACK(ERR_LIB_X509, 0, X509_R_IDP_MISMATCH), "idp mismatch"},
3135
{ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_ATTRIBUTES),
3236
"invalid attributes"},
3337
{ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_DIRECTORY), "invalid directory"},
38+
{ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_DISTPOINT), "invalid distpoint"},
3439
{ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_FIELD_NAME),
3540
"invalid field name"},
3641
{ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_TRUST), "invalid trust"},
@@ -66,6 +71,8 @@ static const ERR_STRING_DATA X509_str_reasons[] = {
6671
{ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_NID), "unknown nid"},
6772
{ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_PURPOSE_ID),
6873
"unknown purpose id"},
74+
{ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_SIGID_ALGS),
75+
"unknown sigid algs"},
6976
{ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_TRUST_ID), "unknown trust id"},
7077
{ERR_PACK(ERR_LIB_X509, 0, X509_R_UNSUPPORTED_ALGORITHM),
7178
"unsupported algorithm"},

0 commit comments

Comments
 (0)