Skip to content

Commit 995e123

Browse files
Support allowing specific unknown critical extensions (#2377)
As of today, AWS-LC returns an error as part of verification if there are any critical extensions present in the certificate being validated. There have been asks to set a custom OID on the issued certificates to ensure that additional validation is performed by customers after or during the handshake. The intention is to prevent accidental mis-use of these certificates without that extra validation. To support this, we've decided to add two new APIs for this use case. 1. `X509_STORE_CTX_add_custom_crit_oid` adds an oid as an `ASN1_OBJECT` to the list of "known" critical extension OIDs in `ctx`. Typical OpenSSL/AWS-LC behavior returns an error if there are any unknown critical extensions present within the certificates being validated. This function lets users specify custom OIDs of any critical extensions that are within the certificates being validated, that they wish to allow. The callback mechanism enabled with `X509_STORE_CTX_set_verify_crit_oids` must be set for this feature to enabled. 2. `X509_STORE_CTX_set_verify_crit_oids` enables the `X509_STORE_CTX_verify_crit_oids_cb` with `X509_STORE_CTX`. Consumers should be performing additional validation against the custom extension oids after or during the handshake. This callback forces users to validate their custom OIDs when processing unknown custom critical extensions. The `X509_STORE_CTX_verify_crit_oids_cb` callback function gives the user the current certificate being validated as `x509` and a stack of `ASN1_OBJECT`s representing unknown critical extension OIDs that were found in `x509` and match those previously registered via`|X509_STORE_CTX_add_custom_crit_oid` as `oids`. This should not effect any existing consumers of `X509_verify_cert`. Any existence of an unknown critical extension will still cause the entire verification to be aborted. Only consumers that have enabled the callback and set specific OIDs with `ASN1_OBJECT` can circumvent the check and trigger the verification to pass. ### Testing: Test certs were generated by the team asking for this feature. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.
1 parent 9aaeb74 commit 995e123

File tree

4 files changed

+348
-4
lines changed

4 files changed

+348
-4
lines changed

crypto/x509/internal.h

+5
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,8 @@ struct x509_store_ctx_st {
344344
X509_STORE_CTX_verify_cb verify_cb; // error callback
345345
X509_STORE_CTX_get_crl_fn get_crl; // retrieve CRL
346346
X509_STORE_CTX_check_crl_fn check_crl; // Check CRL validity
347+
X509_STORE_CTX_verify_crit_oids_cb
348+
verify_custom_crit_oids; // Check custom critical oids
347349

348350
// The following is built up
349351

@@ -359,6 +361,9 @@ struct x509_store_ctx_st {
359361

360362
int current_crl_score; // score of current CRL
361363

364+
// Stack of allowed custom critical extension oids.
365+
STACK_OF(ASN1_OBJECT) *custom_crit_oids;
366+
362367
CRYPTO_EX_DATA ex_data;
363368
} /* X509_STORE_CTX */;
364369

crypto/x509/x509_test.cc

+199
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,67 @@ j2kCAwG+LLpGNmNwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBw5lmgITTEvXIj+8ls
6262
-----END CERTIFICATE-----
6363
)";
6464

65+
static const char kX509CustomExtensionsCA[] = R"(
66+
-----BEGIN CERTIFICATE-----
67+
MIIBxzCCAW2gAwIBAgIFAQAAAAAwCgYIKoZIzj0EAwIwJjEPMA0GA1UECgwGQW1h
68+
em9uMRMwEQYDVQQpDAo0Mjk0OTY3Mjk2MCIYDzIwMjUwMzI5MjA0OTE5WhgPOTk5
69+
OTEyMzEyMzU5NTlaMCYxDzANBgNVBAoMBkFtYXpvbjETMBEGA1UEKQwKNDI5NDk2
70+
NzI5NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABL3eDQzFx4cherBJdIQsxMzZ
71+
rCtzXBTB3f/rRMLrtjxpk2/6h3ZbE4t8MmDbwVepAKYQgT1bjPUFn+edG2U8kRej
72+
gYMwgYAwEgYDVR0TAQH/BAgwBgEB/wIBADBLBgNVHSMERDBCgBTMNuas7QD5hDXY
73+
KS7k0WDN6ckMFqEqpCgwJjEPMA0GA1UECgwGQW1hem9uMRMwEQYDVQQpDAo0Mjk0
74+
OTY3Mjk2MB0GA1UdDgQWBBTMNuas7QD5hDXYKS7k0WDN6ckMFjAKBggqhkjOPQQD
75+
AgNIADBFAiB3MJLK86+JyyoBr2s1Ugjvc7gWAHSk9OgXfyfsVmBV9gIhAPIUiYo8
76+
Jx+IbRyNj2WfeCbn8v3fob0wkGsKf1TSVcZ8
77+
-----END CERTIFICATE-----
78+
)";
79+
80+
static const char kX509CustomExtensionsCert[] = R"(
81+
-----BEGIN CERTIFICATE-----
82+
MIIB6zCCAZGgAwIBAgIFAQAAAAAwCgYIKoZIzj0EAwIwJjEPMA0GA1UECgwGQW1h
83+
em9uMRMwEQYDVQQpDAo0Mjk0OTY3Mjk2MCIYDzIwMjUwMzI5MjA0OTE5WhgPOTk5
84+
OTEyMzEyMzU5NTlaMBExDzANBgNVBAoMBkFtYXpvbjBZMBMGByqGSM49AgEGCCqG
85+
SM49AwEHA0IABNbNswB+jmoICPKu567Odfq83s9P0N82kFYnyANgmztgHqoK7yIX
86+
0meBn5N9Y4m3wAmvokYeK7dU1oRSM397unmjgbwwgbkwDAYDVR0TAQH/BAIwADAO
87+
BgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwFQYHK4E7gcR0
88+
BQEB/wQHcHJlc2VudDBLBgNVHSMERDBCgBTMNuas7QD5hDXYKS7k0WDN6ckMFqEq
89+
pCgwJjEPMA0GA1UECgwGQW1hem9uMRMwEQYDVQQpDAo0Mjk0OTY3Mjk2MB0GA1Ud
90+
DgQWBBRiexFm2K7Ou2dx4+c0LjQOsuqHJjAKBggqhkjOPQQDAgNIADBFAiAxH63Q
91+
eK26A9QPOkqi+5Hvrptpb9HRstSC6emJdaEB1QIhAKyhyLBPrG85QDoXrFcVZUA2
92+
+StWnDVDGtgWM6tPz4Uw
93+
-----END CERTIFICATE-----
94+
)";
95+
96+
static const char kX509MultipleCustomExtensionsCA[] = R"(
97+
-----BEGIN CERTIFICATE-----
98+
MIIByDCCAW2gAwIBAgIFAQAAAAAwCgYIKoZIzj0EAwIwJjEPMA0GA1UECgwGQW1h
99+
em9uMRMwEQYDVQQpDAo0Mjk0OTY3Mjk2MCIYDzIwMjUwMzMwMjExMzA1WhgPOTk5
100+
OTEyMzEyMzU5NTlaMCYxDzANBgNVBAoMBkFtYXpvbjETMBEGA1UEKQwKNDI5NDk2
101+
NzI5NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABMhC2xZcc7UouUMo1xPMiq8E
102+
Z7DdWJq0I9nPunowEwidaif/YU6tjAPVFPmcRIhRYvZH6HWyNc0gztcfgAxa7tej
103+
gYMwgYAwEgYDVR0TAQH/BAgwBgEB/wIBADBLBgNVHSMERDBCgBRMh4uFf12IUZ1m
104+
v3WCstI0aqCBdKEqpCgwJjEPMA0GA1UECgwGQW1hem9uMRMwEQYDVQQpDAo0Mjk0
105+
OTY3Mjk2MB0GA1UdDgQWBBRMh4uFf12IUZ1mv3WCstI0aqCBdDAKBggqhkjOPQQD
106+
AgNJADBGAiEAyZK6Elt1iqVV1Rys4G8HmIE7/hRW3rbQWiNPd4FnANACIQCgbgki
107+
hQaJgNo+8hOTEOQZsRSaIbu+F2afe6ncp996RQ==
108+
-----END CERTIFICATE-----
109+
)";
110+
111+
static const char kX509MultipleCustomExtensionsCert[] = R"(
112+
-----BEGIN CERTIFICATE-----
113+
MIICAjCCAaigAwIBAgIFAQAAAAAwCgYIKoZIzj0EAwIwJjEPMA0GA1UECgwGQW1h
114+
em9uMRMwEQYDVQQpDAo0Mjk0OTY3Mjk2MCIYDzIwMjUwMzMwMjExMzA1WhgPOTk5
115+
OTEyMzEyMzU5NTlaMBExDzANBgNVBAoMBkFtYXpvbjBZMBMGByqGSM49AgEGCCqG
116+
SM49AwEHA0IABPVuvcRmJ8fqyZferbqGWP8Kd1yHHX+4gcglS5WV9Zt7T957fhNY
117+
QpimdCfV+KEJji8IwBc7vOk+1Db3ulQ0dZejgdMwgdAwDAYDVR0TAQH/BAIwADAO
118+
BgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwFQYHK4E7gcR0
119+
BQEB/wQHcHJlc2VudDAVBgcrgTuBxHQGAQH/BAdwcmVzZW50MEsGA1UdIwREMEKA
120+
FEyHi4V/XYhRnWa/dYKy0jRqoIF0oSqkKDAmMQ8wDQYDVQQKDAZBbWF6b24xEzAR
121+
BgNVBCkMCjQyOTQ5NjcyOTYwHQYDVR0OBBYEFGt+Hy7qdE2lFnnjYPGqeVvJ4uPf
122+
MAoGCCqGSM49BAMCA0gAMEUCIQC4aXyPOO6asCwoG1pGGmODmAEMA2tAXXNp67Oo
123+
hDO90wIgETGPNCQIHlvUXAfDmZdUPh+PKkv6paVhWMTXrsh19LQ=
124+
-----END CERTIFICATE-----
125+
)";
65126

66127
std::string GetTestData(const char *path);
67128

@@ -8208,3 +8269,141 @@ TEST(X509Test, Trust) {
82088269
{intermediate.normal.get()}, {},
82098270
/*flags=*/0, set_server_trust));
82108271
}
8272+
8273+
// A brief validation against the |oids| expected to be done by the consumer.
8274+
// This example simulates the consumer checking that the certificate has the
8275+
// correct number of unknown extensions and there aren't any duplicates.
8276+
static int verify_crit_oids_callback(X509_STORE_CTX *ctx, X509 *x509,
8277+
STACK_OF(ASN1_OBJECT) *oids) {
8278+
if (oids == nullptr) {
8279+
return 0; // Fail if no OIDs provided
8280+
}
8281+
size_t known_oid_count = sk_ASN1_OBJECT_num(oids);
8282+
size_t unknown_ext_count = 0;
8283+
int last_pos = X509_get_ext_by_critical(x509, 1, -1);
8284+
while (last_pos >= 0) {
8285+
const X509_EXTENSION *ext = X509_get_ext(x509, last_pos);
8286+
if (!X509_supported_extension(ext)) {
8287+
unknown_ext_count++;
8288+
}
8289+
last_pos = X509_get_ext_by_critical(x509, 1, last_pos);
8290+
}
8291+
return known_oid_count == unknown_ext_count;
8292+
}
8293+
8294+
// Helper function to set up the basic verification context
8295+
static void SetupVerificationContext(
8296+
X509_STORE_CTX *ctx, const std::vector<ASN1_OBJECT *> &custom_oids = {},
8297+
bool set_callback = false) {
8298+
X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(ctx);
8299+
X509_VERIFY_PARAM_set_time_posix(param, 1745884800); // Apr 28, 2025
8300+
8301+
for (const auto &oid : custom_oids) {
8302+
ASSERT_TRUE(X509_STORE_CTX_add_custom_crit_oid(ctx, oid));
8303+
}
8304+
8305+
if (set_callback) {
8306+
X509_STORE_CTX_set_verify_crit_oids(ctx, verify_crit_oids_callback);
8307+
}
8308+
}
8309+
8310+
TEST(X509Test, X509CustomExtensions) {
8311+
bssl::UniquePtr<X509> cert(CertFromPEM(kX509CustomExtensionsCert));
8312+
ASSERT_TRUE(cert);
8313+
bssl::UniquePtr<X509> ca(CertFromPEM(kX509CustomExtensionsCA));
8314+
ASSERT_TRUE(ca);
8315+
8316+
// Check that the cert has been marked as |EXFLAG_CRITICAL|.
8317+
EXPECT_TRUE(X509_get_extension_flags(cert.get()) & EXFLAG_CRITICAL);
8318+
8319+
bssl::UniquePtr<ASN1_OBJECT> custom_oid(OBJ_txt2obj("1.3.187.25204.5", 1));
8320+
ASSERT_TRUE(custom_oid);
8321+
8322+
// A typical call to |X509_verify_cert| without any set up would fail due to
8323+
// the unknown critical extensions.
8324+
auto typical_setup = [&](X509_STORE_CTX *ctx) {
8325+
SetupVerificationContext(ctx, {}, false);
8326+
};
8327+
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
8328+
Verify(cert.get(), {ca.get()}, {}, {},
8329+
/*flags=*/0, typical_setup));
8330+
8331+
// Unknown critical certificate extensions aren't enabled without the
8332+
// callback.
8333+
auto set_custom_ext_with_no_callback = [&](X509_STORE_CTX *ctx) {
8334+
SetupVerificationContext(ctx, {custom_oid.get()}, false);
8335+
};
8336+
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
8337+
Verify(cert.get(), {ca.get()}, {}, {},
8338+
/*flags=*/0, set_custom_ext_with_no_callback));
8339+
8340+
// Unknown critical certificate extensions aren't enabled, when only the
8341+
// callback is enabled, but no custom oids are set.
8342+
auto set_no_custom_ext_with_callback = [&](X509_STORE_CTX *ctx) {
8343+
SetupVerificationContext(ctx, {}, true);
8344+
};
8345+
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
8346+
Verify(cert.get(), {ca.get()}, {}, {},
8347+
/*flags=*/0, set_no_custom_ext_with_callback));
8348+
8349+
// This correctly sets up |ctx| with a custom critical extension and the
8350+
// |verify_crit_oids| callback.
8351+
auto set_custom_ext_with_callback = [&](X509_STORE_CTX *ctx) {
8352+
SetupVerificationContext(ctx, {custom_oid.get()}, true);
8353+
};
8354+
EXPECT_EQ(X509_V_OK,
8355+
Verify(cert.get(), {ca.get()}, {}, {}, /*flags=*/0,
8356+
set_custom_ext_with_callback));
8357+
// Check that |EXFLAG_CRITICAL| has been removed after validation.
8358+
EXPECT_FALSE(X509_get_extension_flags(cert.get()) & EXFLAG_CRITICAL);
8359+
}
8360+
8361+
TEST(X509Test, X509MultipleCustomExtensions) {
8362+
bssl::UniquePtr<X509> cert(CertFromPEM(kX509MultipleCustomExtensionsCert));
8363+
ASSERT_TRUE(cert);
8364+
bssl::UniquePtr<X509> ca(CertFromPEM(kX509MultipleCustomExtensionsCA));
8365+
ASSERT_TRUE(ca);
8366+
8367+
// Check that the cert has been marked as |EXFLAG_CRITICAL|.
8368+
EXPECT_TRUE(X509_get_extension_flags(cert.get()) & EXFLAG_CRITICAL);
8369+
8370+
bssl::UniquePtr<ASN1_OBJECT> custom_oid(OBJ_txt2obj("1.3.187.25204.5", 1));
8371+
ASSERT_TRUE(custom_oid);
8372+
bssl::UniquePtr<ASN1_OBJECT> custom_oid2(OBJ_txt2obj("1.3.187.25204.6", 1));
8373+
ASSERT_TRUE(custom_oid2);
8374+
8375+
// The result should be |X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION| since only
8376+
// one custom critical extension was set. Both extensions are needed since the
8377+
// cert contains two unknown extensions.
8378+
auto set_single_custom_ext = [&](X509_STORE_CTX *ctx) {
8379+
SetupVerificationContext(ctx, {custom_oid.get()}, true);
8380+
};
8381+
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
8382+
Verify(cert.get(), {ca.get()}, {}, {},
8383+
/*flags=*/0, set_single_custom_ext));
8384+
auto set_other_custom_ext = [&](X509_STORE_CTX *ctx) {
8385+
SetupVerificationContext(ctx, {custom_oid2.get()}, true);
8386+
};
8387+
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
8388+
Verify(cert.get(), {ca.get()}, {}, {},
8389+
/*flags=*/0, set_other_custom_ext));
8390+
8391+
// Verification should not pass if all custom critical extensions are set, but
8392+
// the |verify_crit_oids| callback is not configured.
8393+
auto only_custom_exts_set = [&](X509_STORE_CTX *ctx) {
8394+
SetupVerificationContext(ctx, {custom_oid.get(), custom_oid2.get()}, false);
8395+
};
8396+
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
8397+
Verify(cert.get(), {ca.get()}, {}, {},
8398+
/*flags=*/0, only_custom_exts_set));
8399+
8400+
// Verification should only pass if all custom critical extensions are set, and
8401+
// the |verify_crit_oids| callback is configured.
8402+
auto set_custom_exts_with_callback = [&](X509_STORE_CTX *ctx) {
8403+
SetupVerificationContext(ctx, {custom_oid.get(), custom_oid2.get()}, true);
8404+
};
8405+
EXPECT_EQ(X509_V_OK, Verify(cert.get(), {ca.get()}, {}, {},
8406+
/*flags=*/0, set_custom_exts_with_callback));
8407+
// Check that |EXFLAG_CRITICAL| has been removed after validation.
8408+
EXPECT_FALSE(X509_get_extension_flags(cert.get()) & EXFLAG_CRITICAL);
8409+
}

crypto/x509/x509_vfy.c

+112-4
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x);
122122
static int internal_verify(X509_STORE_CTX *ctx);
123123

124124
static int null_callback(int ok, X509_STORE_CTX *e) { return ok; }
125+
static int null_verify_custom_crit_oids_callback(X509_STORE_CTX *ctx,
126+
X509 *x509,
127+
STACK_OF(ASN1_OBJECT) *oids) {
128+
// This returns 0 by default, so that the callback must be configured by the
129+
// user when enabling the custom critical extensions feature.
130+
return 0;
131+
}
125132

126133
// cert_self_signed checks if |x| is self-signed. If |x| is valid, it returns
127134
// one and sets |*out_is_self_signed| to the result. If |x| is invalid, it
@@ -519,7 +526,7 @@ static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x) {
519526
issuer = sk_X509_value(sk, i);
520527
if (x509_check_issued_with_callback(ctx, x, issuer)) {
521528
candidate = issuer;
522-
if (x509_check_cert_time(ctx, candidate, /*suppress_error*/1)) {
529+
if (x509_check_cert_time(ctx, candidate, /*suppress_error*/ 1)) {
523530
break;
524531
}
525532
}
@@ -561,6 +568,71 @@ static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) {
561568
return X509_STORE_CTX_get1_issuer(issuer, ctx, x);
562569
}
563570

571+
static int check_custom_critical_extensions(X509_STORE_CTX *ctx, X509 *x) {
572+
if (ctx->custom_crit_oids == NULL) {
573+
// Fail if custom critical extensions are enabled, but none were set.
574+
return 0;
575+
}
576+
size_t known_oid_count = sk_ASN1_OBJECT_num(ctx->custom_crit_oids);
577+
if (known_oid_count == 0) {
578+
return 0;
579+
}
580+
581+
// Allocate |found_exts| to pass to the callback.
582+
STACK_OF(ASN1_OBJECT) *found_exts = sk_ASN1_OBJECT_new_null();
583+
if (found_exts == NULL) {
584+
return 0;
585+
}
586+
587+
// Iterate through all critical extensions of |x| and validate against the
588+
// ones that aren't recognized by |X509_supported_extension|.
589+
int last_pos = X509_get_ext_by_critical(x, 1, -1);
590+
while (last_pos >= 0) {
591+
const X509_EXTENSION *ext = X509_get_ext(x, last_pos);
592+
if (!X509_supported_extension(ext)) {
593+
int found = 0;
594+
595+
// Iterate through all set |custom_crit_oids|.
596+
for (size_t i = 0; i < known_oid_count; i++) {
597+
const ASN1_OBJECT *known_ext =
598+
sk_ASN1_OBJECT_value(ctx->custom_crit_oids, i);
599+
if (OBJ_cmp(ext->object, known_ext) == 0) {
600+
// |sk_ASN1_OBJECT_value| returns a direct pointer.
601+
ASN1_OBJECT *dup_obj = OBJ_dup(known_ext);
602+
if (dup_obj == NULL || !sk_ASN1_OBJECT_push(found_exts, dup_obj)) {
603+
ASN1_OBJECT_free(dup_obj);
604+
sk_ASN1_OBJECT_pop_free(found_exts, ASN1_OBJECT_free);
605+
return 0;
606+
}
607+
found = 1;
608+
break;
609+
}
610+
}
611+
612+
if (!found) {
613+
// If any critical extension isn't in our known list, return early.
614+
sk_ASN1_OBJECT_pop_free(found_exts, ASN1_OBJECT_free);
615+
return 0;
616+
}
617+
}
618+
last_pos = X509_get_ext_by_critical(x, 1, last_pos);
619+
}
620+
621+
// If we get here, all unknown critical extensions in |x| were
622+
// properly handled and we pass the ones that were found to the caller.
623+
if (!ctx->verify_custom_crit_oids(ctx, x, found_exts)) {
624+
sk_ASN1_OBJECT_pop_free(found_exts, ASN1_OBJECT_free);
625+
return 0;
626+
}
627+
628+
// Remove the |EXFLAG_CRITICAL| flag from |x|, now that all unknown
629+
// critical extensions have been handled.
630+
x->ex_flags &= ~EXFLAG_CRITICAL;
631+
632+
sk_ASN1_OBJECT_pop_free(found_exts, ASN1_OBJECT_free);
633+
return 1;
634+
}
635+
564636
// Check a certificate chains extensions for consistency with the supplied
565637
// purpose
566638

@@ -571,8 +643,14 @@ static int check_chain_extensions(X509_STORE_CTX *ctx) {
571643
// Check all untrusted certificates
572644
for (int i = 0; i < ctx->last_untrusted; i++) {
573645
X509 *x = sk_X509_value(ctx->chain, i);
574-
if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) &&
575-
(x->ex_flags & EXFLAG_CRITICAL)) {
646+
if ( // OpenSSL's historic check for unknown critical extensions.
647+
// |EXFLAG_CRITICAL| indicates an unsupported critical extension was
648+
// found in |x| during the initial parsing of the certificate.
649+
(!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) &&
650+
(x->ex_flags & EXFLAG_CRITICAL)) &&
651+
// AWS-LC specific logic for enabling custom unknown critical
652+
// extensions.
653+
!check_custom_critical_extensions(ctx, x)) {
576654
ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
577655
ctx->error_depth = i;
578656
ctx->current_cert = x;
@@ -1439,7 +1517,7 @@ static int internal_verify(X509_STORE_CTX *ctx) {
14391517
}
14401518

14411519
check_cert:
1442-
ok = x509_check_cert_time(ctx, xs, /*suppress_error*/0);
1520+
ok = x509_check_cert_time(ctx, xs, /*suppress_error*/ 0);
14431521
if (!ok) {
14441522
goto end;
14451523
}
@@ -1686,6 +1764,8 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
16861764
ctx->check_crl = check_crl;
16871765
}
16881766

1767+
ctx->verify_custom_crit_oids = null_verify_custom_crit_oids_callback;
1768+
16891769
return 1;
16901770

16911771
err:
@@ -1714,6 +1794,7 @@ void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx) {
17141794
CRYPTO_free_ex_data(&g_ex_data_class, ctx, &(ctx->ex_data));
17151795
X509_VERIFY_PARAM_free(ctx->param);
17161796
sk_X509_pop_free(ctx->chain, X509_free);
1797+
sk_ASN1_OBJECT_pop_free(ctx->custom_crit_oids, ASN1_OBJECT_free);
17171798
OPENSSL_memset(ctx, 0, sizeof(X509_STORE_CTX));
17181799
}
17191800

@@ -1762,3 +1843,30 @@ void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param) {
17621843
}
17631844
ctx->param = param;
17641845
}
1846+
1847+
int X509_STORE_CTX_add_custom_crit_oid(X509_STORE_CTX *ctx, ASN1_OBJECT *oid) {
1848+
GUARD_PTR(ctx);
1849+
GUARD_PTR(oid);
1850+
1851+
ASN1_OBJECT *oid_dup = OBJ_dup(oid);
1852+
if (oid_dup == NULL) {
1853+
return 0;
1854+
}
1855+
if (ctx->custom_crit_oids == NULL) {
1856+
ctx->custom_crit_oids = sk_ASN1_OBJECT_new_null();
1857+
if (ctx->custom_crit_oids == NULL) {
1858+
return 0;
1859+
}
1860+
}
1861+
1862+
if (!sk_ASN1_OBJECT_push(ctx->custom_crit_oids, oid_dup)) {
1863+
return 0;
1864+
}
1865+
return 1;
1866+
}
1867+
1868+
void X509_STORE_CTX_set_verify_crit_oids(
1869+
X509_STORE_CTX *ctx,
1870+
X509_STORE_CTX_verify_crit_oids_cb verify_custom_crit_oids) {
1871+
ctx->verify_custom_crit_oids = verify_custom_crit_oids;
1872+
}

0 commit comments

Comments
 (0)