Skip to content

Support allowing specific unknown critical extensions #2377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crypto/x509/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ struct x509_store_ctx_st {
X509_STORE_CTX_verify_cb verify_cb; // error callback
X509_STORE_CTX_get_crl_fn get_crl; // retrieve CRL
X509_STORE_CTX_check_crl_fn check_crl; // Check CRL validity
X509_STORE_CTX_verify_crit_oids_cb
verify_custom_crit_oids; // Check custom critical oids

// The following is built up

Expand All @@ -359,6 +361,9 @@ struct x509_store_ctx_st {

int current_crl_score; // score of current CRL

// Stack of allowed custom critical extension oids.
STACK_OF(ASN1_OBJECT) *custom_crit_oids;

CRYPTO_EX_DATA ex_data;
} /* X509_STORE_CTX */;

Expand Down
199 changes: 199 additions & 0 deletions crypto/x509/x509_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,67 @@ j2kCAwG+LLpGNmNwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBw5lmgITTEvXIj+8ls
-----END CERTIFICATE-----
)";

static const char kX509CustomExtensionsCA[] = R"(
-----BEGIN CERTIFICATE-----
MIIBxzCCAW2gAwIBAgIFAQAAAAAwCgYIKoZIzj0EAwIwJjEPMA0GA1UECgwGQW1h
em9uMRMwEQYDVQQpDAo0Mjk0OTY3Mjk2MCIYDzIwMjUwMzI5MjA0OTE5WhgPOTk5
OTEyMzEyMzU5NTlaMCYxDzANBgNVBAoMBkFtYXpvbjETMBEGA1UEKQwKNDI5NDk2
NzI5NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABL3eDQzFx4cherBJdIQsxMzZ
rCtzXBTB3f/rRMLrtjxpk2/6h3ZbE4t8MmDbwVepAKYQgT1bjPUFn+edG2U8kRej
gYMwgYAwEgYDVR0TAQH/BAgwBgEB/wIBADBLBgNVHSMERDBCgBTMNuas7QD5hDXY
KS7k0WDN6ckMFqEqpCgwJjEPMA0GA1UECgwGQW1hem9uMRMwEQYDVQQpDAo0Mjk0
OTY3Mjk2MB0GA1UdDgQWBBTMNuas7QD5hDXYKS7k0WDN6ckMFjAKBggqhkjOPQQD
AgNIADBFAiB3MJLK86+JyyoBr2s1Ugjvc7gWAHSk9OgXfyfsVmBV9gIhAPIUiYo8
Jx+IbRyNj2WfeCbn8v3fob0wkGsKf1TSVcZ8
-----END CERTIFICATE-----
)";

static const char kX509CustomExtensionsCert[] = R"(
-----BEGIN CERTIFICATE-----
MIIB6zCCAZGgAwIBAgIFAQAAAAAwCgYIKoZIzj0EAwIwJjEPMA0GA1UECgwGQW1h
em9uMRMwEQYDVQQpDAo0Mjk0OTY3Mjk2MCIYDzIwMjUwMzI5MjA0OTE5WhgPOTk5
OTEyMzEyMzU5NTlaMBExDzANBgNVBAoMBkFtYXpvbjBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABNbNswB+jmoICPKu567Odfq83s9P0N82kFYnyANgmztgHqoK7yIX
0meBn5N9Y4m3wAmvokYeK7dU1oRSM397unmjgbwwgbkwDAYDVR0TAQH/BAIwADAO
BgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwFQYHK4E7gcR0
BQEB/wQHcHJlc2VudDBLBgNVHSMERDBCgBTMNuas7QD5hDXYKS7k0WDN6ckMFqEq
pCgwJjEPMA0GA1UECgwGQW1hem9uMRMwEQYDVQQpDAo0Mjk0OTY3Mjk2MB0GA1Ud
DgQWBBRiexFm2K7Ou2dx4+c0LjQOsuqHJjAKBggqhkjOPQQDAgNIADBFAiAxH63Q
eK26A9QPOkqi+5Hvrptpb9HRstSC6emJdaEB1QIhAKyhyLBPrG85QDoXrFcVZUA2
+StWnDVDGtgWM6tPz4Uw
-----END CERTIFICATE-----
)";

static const char kX509MultipleCustomExtensionsCA[] = R"(
-----BEGIN CERTIFICATE-----
MIIByDCCAW2gAwIBAgIFAQAAAAAwCgYIKoZIzj0EAwIwJjEPMA0GA1UECgwGQW1h
em9uMRMwEQYDVQQpDAo0Mjk0OTY3Mjk2MCIYDzIwMjUwMzMwMjExMzA1WhgPOTk5
OTEyMzEyMzU5NTlaMCYxDzANBgNVBAoMBkFtYXpvbjETMBEGA1UEKQwKNDI5NDk2
NzI5NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABMhC2xZcc7UouUMo1xPMiq8E
Z7DdWJq0I9nPunowEwidaif/YU6tjAPVFPmcRIhRYvZH6HWyNc0gztcfgAxa7tej
gYMwgYAwEgYDVR0TAQH/BAgwBgEB/wIBADBLBgNVHSMERDBCgBRMh4uFf12IUZ1m
v3WCstI0aqCBdKEqpCgwJjEPMA0GA1UECgwGQW1hem9uMRMwEQYDVQQpDAo0Mjk0
OTY3Mjk2MB0GA1UdDgQWBBRMh4uFf12IUZ1mv3WCstI0aqCBdDAKBggqhkjOPQQD
AgNJADBGAiEAyZK6Elt1iqVV1Rys4G8HmIE7/hRW3rbQWiNPd4FnANACIQCgbgki
hQaJgNo+8hOTEOQZsRSaIbu+F2afe6ncp996RQ==
-----END CERTIFICATE-----
)";

static const char kX509MultipleCustomExtensionsCert[] = R"(
-----BEGIN CERTIFICATE-----
MIICAjCCAaigAwIBAgIFAQAAAAAwCgYIKoZIzj0EAwIwJjEPMA0GA1UECgwGQW1h
em9uMRMwEQYDVQQpDAo0Mjk0OTY3Mjk2MCIYDzIwMjUwMzMwMjExMzA1WhgPOTk5
OTEyMzEyMzU5NTlaMBExDzANBgNVBAoMBkFtYXpvbjBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABPVuvcRmJ8fqyZferbqGWP8Kd1yHHX+4gcglS5WV9Zt7T957fhNY
QpimdCfV+KEJji8IwBc7vOk+1Db3ulQ0dZejgdMwgdAwDAYDVR0TAQH/BAIwADAO
BgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwFQYHK4E7gcR0
BQEB/wQHcHJlc2VudDAVBgcrgTuBxHQGAQH/BAdwcmVzZW50MEsGA1UdIwREMEKA
FEyHi4V/XYhRnWa/dYKy0jRqoIF0oSqkKDAmMQ8wDQYDVQQKDAZBbWF6b24xEzAR
BgNVBCkMCjQyOTQ5NjcyOTYwHQYDVR0OBBYEFGt+Hy7qdE2lFnnjYPGqeVvJ4uPf
MAoGCCqGSM49BAMCA0gAMEUCIQC4aXyPOO6asCwoG1pGGmODmAEMA2tAXXNp67Oo
hDO90wIgETGPNCQIHlvUXAfDmZdUPh+PKkv6paVhWMTXrsh19LQ=
-----END CERTIFICATE-----
)";

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

Expand Down Expand Up @@ -8208,3 +8269,141 @@ TEST(X509Test, Trust) {
{intermediate.normal.get()}, {},
/*flags=*/0, set_server_trust));
}

// A brief validation against the |oids| expected to be done by the consumer.
// This example simulates the consumer checking that the certificate has the
// correct number of unknown extensions and there aren't any duplicates.
static int verify_crit_oids_callback(X509_STORE_CTX *ctx, X509 *x509,
STACK_OF(ASN1_OBJECT) *oids) {
if (oids == nullptr) {
return 0; // Fail if no OIDs provided
}
size_t known_oid_count = sk_ASN1_OBJECT_num(oids);
size_t unknown_ext_count = 0;
int last_pos = X509_get_ext_by_critical(x509, 1, -1);
while (last_pos >= 0) {
const X509_EXTENSION *ext = X509_get_ext(x509, last_pos);
if (!X509_supported_extension(ext)) {
unknown_ext_count++;
}
last_pos = X509_get_ext_by_critical(x509, 1, last_pos);
}
return known_oid_count == unknown_ext_count;
}

// Helper function to set up the basic verification context
static void SetupVerificationContext(
X509_STORE_CTX *ctx, const std::vector<ASN1_OBJECT *> &custom_oids = {},
bool set_callback = false) {
X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(ctx);
X509_VERIFY_PARAM_set_time_posix(param, 1745884800); // Apr 28, 2025

for (const auto &oid : custom_oids) {
ASSERT_TRUE(X509_STORE_CTX_add_custom_crit_oid(ctx, oid));
}

if (set_callback) {
X509_STORE_CTX_set_verify_crit_oids(ctx, verify_crit_oids_callback);
}
}

TEST(X509Test, X509CustomExtensions) {
bssl::UniquePtr<X509> cert(CertFromPEM(kX509CustomExtensionsCert));
ASSERT_TRUE(cert);
bssl::UniquePtr<X509> ca(CertFromPEM(kX509CustomExtensionsCA));
ASSERT_TRUE(ca);

// Check that the cert has been marked as |EXFLAG_CRITICAL|.
EXPECT_TRUE(X509_get_extension_flags(cert.get()) & EXFLAG_CRITICAL);

bssl::UniquePtr<ASN1_OBJECT> custom_oid(OBJ_txt2obj("1.3.187.25204.5", 1));
ASSERT_TRUE(custom_oid);

// A typical call to |X509_verify_cert| without any set up would fail due to
// the unknown critical extensions.
auto typical_setup = [&](X509_STORE_CTX *ctx) {
SetupVerificationContext(ctx, {}, false);
};
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
Verify(cert.get(), {ca.get()}, {}, {},
/*flags=*/0, typical_setup));

// Unknown critical certificate extensions aren't enabled without the
// callback.
auto set_custom_ext_with_no_callback = [&](X509_STORE_CTX *ctx) {
SetupVerificationContext(ctx, {custom_oid.get()}, false);
};
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
Verify(cert.get(), {ca.get()}, {}, {},
/*flags=*/0, set_custom_ext_with_no_callback));

// Unknown critical certificate extensions aren't enabled, when only the
// callback is enabled, but no custom oids are set.
auto set_no_custom_ext_with_callback = [&](X509_STORE_CTX *ctx) {
SetupVerificationContext(ctx, {}, true);
};
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
Verify(cert.get(), {ca.get()}, {}, {},
/*flags=*/0, set_no_custom_ext_with_callback));

// This correctly sets up |ctx| with a custom critical extension and the
// |verify_crit_oids| callback.
auto set_custom_ext_with_callback = [&](X509_STORE_CTX *ctx) {
SetupVerificationContext(ctx, {custom_oid.get()}, true);
};
EXPECT_EQ(X509_V_OK,
Verify(cert.get(), {ca.get()}, {}, {}, /*flags=*/0,
set_custom_ext_with_callback));
// Check that |EXFLAG_CRITICAL| has been removed after validation.
EXPECT_FALSE(X509_get_extension_flags(cert.get()) & EXFLAG_CRITICAL);
}

TEST(X509Test, X509MultipleCustomExtensions) {
bssl::UniquePtr<X509> cert(CertFromPEM(kX509MultipleCustomExtensionsCert));
ASSERT_TRUE(cert);
bssl::UniquePtr<X509> ca(CertFromPEM(kX509MultipleCustomExtensionsCA));
ASSERT_TRUE(ca);

// Check that the cert has been marked as |EXFLAG_CRITICAL|.
EXPECT_TRUE(X509_get_extension_flags(cert.get()) & EXFLAG_CRITICAL);

bssl::UniquePtr<ASN1_OBJECT> custom_oid(OBJ_txt2obj("1.3.187.25204.5", 1));
ASSERT_TRUE(custom_oid);
bssl::UniquePtr<ASN1_OBJECT> custom_oid2(OBJ_txt2obj("1.3.187.25204.6", 1));
ASSERT_TRUE(custom_oid2);

// The result should be |X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION| since only
// one custom critical extension was set. Both extensions are needed since the
// cert contains two unknown extensions.
auto set_single_custom_ext = [&](X509_STORE_CTX *ctx) {
SetupVerificationContext(ctx, {custom_oid.get()}, true);
};
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
Verify(cert.get(), {ca.get()}, {}, {},
/*flags=*/0, set_single_custom_ext));
auto set_other_custom_ext = [&](X509_STORE_CTX *ctx) {
SetupVerificationContext(ctx, {custom_oid2.get()}, true);
};
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
Verify(cert.get(), {ca.get()}, {}, {},
/*flags=*/0, set_other_custom_ext));

// Verification should not pass if all custom critical extensions are set, but
// the |verify_crit_oids| callback is not configured.
auto only_custom_exts_set = [&](X509_STORE_CTX *ctx) {
SetupVerificationContext(ctx, {custom_oid.get(), custom_oid2.get()}, false);
};
EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
Verify(cert.get(), {ca.get()}, {}, {},
/*flags=*/0, only_custom_exts_set));

// Verification should only pass if all custom critical extensions are set, and
// the |verify_crit_oids| callback is configured.
auto set_custom_exts_with_callback = [&](X509_STORE_CTX *ctx) {
SetupVerificationContext(ctx, {custom_oid.get(), custom_oid2.get()}, true);
};
EXPECT_EQ(X509_V_OK, Verify(cert.get(), {ca.get()}, {}, {},
/*flags=*/0, set_custom_exts_with_callback));
// Check that |EXFLAG_CRITICAL| has been removed after validation.
EXPECT_FALSE(X509_get_extension_flags(cert.get()) & EXFLAG_CRITICAL);
}
116 changes: 112 additions & 4 deletions crypto/x509/x509_vfy.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x);
static int internal_verify(X509_STORE_CTX *ctx);

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

// cert_self_signed checks if |x| is self-signed. If |x| is valid, it returns
// one and sets |*out_is_self_signed| to the result. If |x| is invalid, it
Expand Down Expand Up @@ -519,7 +526,7 @@ static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x) {
issuer = sk_X509_value(sk, i);
if (x509_check_issued_with_callback(ctx, x, issuer)) {
candidate = issuer;
if (x509_check_cert_time(ctx, candidate, /*suppress_error*/1)) {
if (x509_check_cert_time(ctx, candidate, /*suppress_error*/ 1)) {
break;
}
}
Expand Down Expand Up @@ -561,6 +568,71 @@ static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) {
return X509_STORE_CTX_get1_issuer(issuer, ctx, x);
}

static int check_custom_critical_extensions(X509_STORE_CTX *ctx, X509 *x) {
if (ctx->custom_crit_oids == NULL) {
// Fail if custom critical extensions are enabled, but none were set.
return 0;
}
size_t known_oid_count = sk_ASN1_OBJECT_num(ctx->custom_crit_oids);
if (known_oid_count == 0) {
return 0;
}

// Allocate |found_exts| to pass to the callback.
STACK_OF(ASN1_OBJECT) *found_exts = sk_ASN1_OBJECT_new_null();
if (found_exts == NULL) {
return 0;
}

// Iterate through all critical extensions of |x| and validate against the
// ones that aren't recognized by |X509_supported_extension|.
int last_pos = X509_get_ext_by_critical(x, 1, -1);
while (last_pos >= 0) {
const X509_EXTENSION *ext = X509_get_ext(x, last_pos);
if (!X509_supported_extension(ext)) {
int found = 0;

// Iterate through all set |custom_crit_oids|.
for (size_t i = 0; i < known_oid_count; i++) {
const ASN1_OBJECT *known_ext =
sk_ASN1_OBJECT_value(ctx->custom_crit_oids, i);
if (OBJ_cmp(ext->object, known_ext) == 0) {
// |sk_ASN1_OBJECT_value| returns a direct pointer.
ASN1_OBJECT *dup_obj = OBJ_dup(known_ext);
if (dup_obj == NULL || !sk_ASN1_OBJECT_push(found_exts, dup_obj)) {
ASN1_OBJECT_free(dup_obj);
sk_ASN1_OBJECT_pop_free(found_exts, ASN1_OBJECT_free);
return 0;
}
found = 1;
break;
}
}

if (!found) {
// If any critical extension isn't in our known list, return early.
sk_ASN1_OBJECT_pop_free(found_exts, ASN1_OBJECT_free);
return 0;
}
}
last_pos = X509_get_ext_by_critical(x, 1, last_pos);
}

// If we get here, all unknown critical extensions in |x| were
// properly handled and we pass the ones that were found to the caller.
if (!ctx->verify_custom_crit_oids(ctx, x, found_exts)) {
sk_ASN1_OBJECT_pop_free(found_exts, ASN1_OBJECT_free);
return 0;
}

// Remove the |EXFLAG_CRITICAL| flag from |x|, now that all unknown
// critical extensions have been handled.
x->ex_flags &= ~EXFLAG_CRITICAL;

sk_ASN1_OBJECT_pop_free(found_exts, ASN1_OBJECT_free);
return 1;
}

// Check a certificate chains extensions for consistency with the supplied
// purpose

Expand All @@ -571,8 +643,14 @@ static int check_chain_extensions(X509_STORE_CTX *ctx) {
// Check all untrusted certificates
for (int i = 0; i < ctx->last_untrusted; i++) {
X509 *x = sk_X509_value(ctx->chain, i);
if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) &&
(x->ex_flags & EXFLAG_CRITICAL)) {
if ( // OpenSSL's historic check for unknown critical extensions.
// |EXFLAG_CRITICAL| indicates an unsupported critical extension was
// found in |x| during the initial parsing of the certificate.
(!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) &&
(x->ex_flags & EXFLAG_CRITICAL)) &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should clear this EXFLAG_CRITICAL flag off after this if case. It's kind of a misnomer of a name but the purpose of the flag indicates that there is unknown critical extension unhandled. If we don't exit out here at this point we should remove it cause that implies no extensions are unknown at that point on the certificate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also add a comment here about this maybe, I was also confused at first. I read the if condition as "if IGNORE_CRITICAL is not set, and EXFLAG_CRITICAL is set (which to me implied any critical extensions, not just unhandled ones), AND either check_custom_known_critical_extension or ctx->verify_crit_oids fails", we are in an error state.

Since check_custom_known_critical_extension fails immediately if ctx->custom_crit_oids is NULL, if EXFLAG_CRITICAL were to mean any critical ext and not just unhandled ones, this if condition would be erroneous.

Just to confirm for my own clarity, at this point in code, are we expecting that any "known" critical oids have already been parsed/validated. So if EXFLAG_CRITICAL is still set here, we know that it's only possible because the customer has set custom oids and can therefore fail otherwise?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a bit hesitant to do so, mainly because the state of EXFLAG_CRITICAL is maintained along with the x certificate. If that state is cleared, there is now an implication that critical extension is supported and the certificate can be accepted. I was initially afraid of the user not being aware that there were typically unknown critical extensions present in the cert. But if they're already running X509_verify_cert with this feature, I guess it would make sense that that state is cleared later on.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EXFLAG_CRITICAL simply indicates an unsupported critical extension, so a critical extension that is already supported wouldn't trigger this. This flag is added during the initial parsing of the certificate.

check_custom_known_critical_extension is supposed to fail under the circumstance you mentioned. Typical OpenSSL/AWS-LC behavior is to fail when an unsupported critical extension is found (hence the flag). The user has to set up ctx->custom_crit_oids with all their "known" unsupported critical extensions they wish to work around here.

At this point in the code, we only know if there are unknown critical extensions present with the EXFLAG_CRITICAL flag. We could remove the flag after the first validation against this has succeeded, but I'd prefer to do the custom OID validation regardless of whether the flag has been set.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for those details, that clears up a lot for me! It would be great if we can add a comment here explaining EXFLAG_CRITICAL/what we are checking to improve readability in this func :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, I think it's valuable. Will do :).

// AWS-LC specific logic for enabling custom unknown critical
// extensions.
!check_custom_critical_extensions(ctx, x)) {
ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
ctx->error_depth = i;
ctx->current_cert = x;
Expand Down Expand Up @@ -1439,7 +1517,7 @@ static int internal_verify(X509_STORE_CTX *ctx) {
}

check_cert:
ok = x509_check_cert_time(ctx, xs, /*suppress_error*/0);
ok = x509_check_cert_time(ctx, xs, /*suppress_error*/ 0);
if (!ok) {
goto end;
}
Expand Down Expand Up @@ -1686,6 +1764,8 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
ctx->check_crl = check_crl;
}

ctx->verify_custom_crit_oids = null_verify_custom_crit_oids_callback;

return 1;

err:
Expand Down Expand Up @@ -1714,6 +1794,7 @@ void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx) {
CRYPTO_free_ex_data(&g_ex_data_class, ctx, &(ctx->ex_data));
X509_VERIFY_PARAM_free(ctx->param);
sk_X509_pop_free(ctx->chain, X509_free);
sk_ASN1_OBJECT_pop_free(ctx->custom_crit_oids, ASN1_OBJECT_free);
OPENSSL_memset(ctx, 0, sizeof(X509_STORE_CTX));
}

Expand Down Expand Up @@ -1762,3 +1843,30 @@ void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param) {
}
ctx->param = param;
}

int X509_STORE_CTX_add_custom_crit_oid(X509_STORE_CTX *ctx, ASN1_OBJECT *oid) {
GUARD_PTR(ctx);
GUARD_PTR(oid);

ASN1_OBJECT *oid_dup = OBJ_dup(oid);
if (oid_dup == NULL) {
return 0;
}
if (ctx->custom_crit_oids == NULL) {
ctx->custom_crit_oids = sk_ASN1_OBJECT_new_null();
if (ctx->custom_crit_oids == NULL) {
return 0;
}
}

if (!sk_ASN1_OBJECT_push(ctx->custom_crit_oids, oid_dup)) {
return 0;
}
return 1;
}

void X509_STORE_CTX_set_verify_crit_oids(
X509_STORE_CTX *ctx,
X509_STORE_CTX_verify_crit_oids_cb verify_custom_crit_oids) {
ctx->verify_custom_crit_oids = verify_custom_crit_oids;
}
Loading
Loading