Document and test X509_PURPOSE and X509_TRUST machinery
The trust and purpose is all a bit tied up together, as is the meaning
of the certificates in an X509_STORE at all. (It's hard to discuss
whether a "trusted certificate" is actually a trust anchor without a
description of trust settings to reference.)
Cut the Gordian Knot by documenting all that first. Later CLs will move
other symbols into the sections established here. Also as the behavior
is a little complex, add some tests to cover some of this machinery.
Bug: 426
Change-Id: Idde8bc4e588de92ebabf6ecf640b62a2a6803688
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/65207
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/crypto/x509/v3_purp.c b/crypto/x509/v3_purp.c
index a382592..265e874 100644
--- a/crypto/x509/v3_purp.c
+++ b/crypto/x509/v3_purp.c
@@ -432,6 +432,10 @@
return 0;
}
if (ca) {
+ // TODO(davidben): Move the various |check_ca| calls out of the
+ // |check_purpose| callbacks. Those checks are purpose-independent. They are
+ // also redundant when called from |X509_verify_cert|, though
+ // not when |X509_check_purpose| is called directly.
return check_ca(x);
}
// We need to do digital signatures or key agreement
@@ -473,8 +477,7 @@
static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
int ca) {
- int ret;
- ret = check_purpose_ssl_server(xp, x, ca);
+ int ret = check_purpose_ssl_server(xp, x, ca);
if (!ret || ca) {
return ret;
}
@@ -507,8 +510,7 @@
static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
int ca) {
- int ret;
- ret = purpose_smime(x, ca);
+ int ret = purpose_smime(x, ca);
if (!ret || ca) {
return ret;
}
@@ -520,8 +522,7 @@
static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
int ca) {
- int ret;
- ret = purpose_smime(x, ca);
+ int ret = purpose_smime(x, ca);
if (!ret || ca) {
return ret;
}
@@ -555,8 +556,6 @@
static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
int ca) {
- int i_ext;
-
// If ca is true we must return if this is a valid CA certificate.
if (ca) {
return check_ca(x);
@@ -580,9 +579,9 @@
}
// Extended Key Usage MUST be critical
- i_ext = X509_get_ext_by_NID((X509 *)x, NID_ext_key_usage, -1);
+ int i_ext = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
if (i_ext >= 0) {
- const X509_EXTENSION *ext = X509_get_ext((X509 *)x, i_ext);
+ const X509_EXTENSION *ext = X509_get_ext(x, i_ext);
if (!X509_EXTENSION_get_critical(ext)) {
return 0;
}
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index 08fea33..3493806 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -1725,6 +1725,46 @@
return cert;
}
+static bool AddExtendedKeyUsage(X509 *x509, const std::vector<int> &eku_nids) {
+ bssl::UniquePtr<STACK_OF(ASN1_OBJECT)> objs(sk_ASN1_OBJECT_new_null());
+ if (objs == nullptr) {
+ return false;
+ }
+ for (int nid : eku_nids) {
+ if (!sk_ASN1_OBJECT_push(objs.get(), OBJ_nid2obj(nid))) {
+ return false;
+ }
+ }
+ return X509_add1_ext_i2d(x509, NID_ext_key_usage, objs.get(), /*crit=*/1,
+ /*flags=*/0);
+}
+
+enum class KeyUsage : int {
+ kDigitalSignature = 0,
+ kNonRepudiation = 1,
+ kKeyEncipherment = 2,
+ kDataEncipherment = 3,
+ kKeyAgreement = 4,
+ kKeyCertSign = 5,
+ kCRLSign = 6,
+ kEncipherOnly = 7,
+ kDecipherOnly = 8,
+};
+
+static bool AddKeyUsage(X509 *x509, const std::vector<KeyUsage> usages) {
+ bssl::UniquePtr<ASN1_BIT_STRING> str(ASN1_BIT_STRING_new());
+ if (str == nullptr) {
+ return false;
+ }
+ for (KeyUsage usage : usages) {
+ if (!ASN1_BIT_STRING_set_bit(str.get(), static_cast<int>(usage), 1)) {
+ return false;
+ }
+ }
+ return X509_add1_ext_i2d(x509, NID_key_usage, str.get(), /*crit=*/1,
+ /*flags=*/0);
+}
+
TEST(X509Test, NameConstraints) {
bssl::UniquePtr<EVP_PKEY> key = PrivateKeyFromPEM(kP256Key);
ASSERT_TRUE(key);
@@ -2780,6 +2820,15 @@
// basicConstraints.
EXPECT_EQ(X509_V_ERR_INVALID_CA,
Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, 0));
+
+ // |X509_check_purpose| with |X509_PURPOSE_ANY| and purpose -1 do not check
+ // basicConstraints, but other purpose types do. (This is redundant with the
+ // actual basicConstraints check, but |X509_check_purpose| is public API.)
+ EXPECT_TRUE(X509_check_purpose(intermediate.get(), -1, /*ca=*/1));
+ EXPECT_TRUE(
+ X509_check_purpose(intermediate.get(), X509_PURPOSE_ANY, /*ca=*/1));
+ EXPECT_FALSE(X509_check_purpose(intermediate.get(), X509_PURPOSE_SSL_SERVER,
+ /*ca=*/1));
}
TEST(X509Test, NoBasicConstraintsNetscapeCA) {
@@ -7309,3 +7358,360 @@
key2.reset(X509_PUBKEY_get(pub));
EXPECT_FALSE(key2);
}
+
+// Tests some unusual behavior in |X509_STORE_CTX_set_purpose| and
+// |X509_STORE_CTX_set_trust|.
+TEST(X509Test, ContextTrustAndPurpose) {
+ bssl::UniquePtr<X509_STORE> store(X509_STORE_new());
+ ASSERT_TRUE(store);
+ bssl::UniquePtr<X509> leaf(CertFromPEM(kLeafPEM));
+ ASSERT_TRUE(leaf);
+
+ bssl::UniquePtr<X509_STORE_CTX> ctx(X509_STORE_CTX_new());
+ ASSERT_TRUE(ctx);
+ ASSERT_TRUE(X509_STORE_CTX_init(ctx.get(), store.get(), leaf.get(), nullptr));
+
+ // Initially, neither parameter is set.
+ EXPECT_EQ(ctx->param->purpose, 0);
+ EXPECT_EQ(ctx->param->trust, 0);
+
+ // Invalid purpose and trust types fail.
+ EXPECT_FALSE(X509_STORE_CTX_set_purpose(ctx.get(), 999));
+ EXPECT_FALSE(X509_STORE_CTX_set_trust(ctx.get(), 999));
+
+ // It is not possible to set |X509_PURPOSE_ANY| with this API, because there
+ // is no corresponding trust.
+ EXPECT_FALSE(X509_STORE_CTX_set_purpose(ctx.get(), X509_PURPOSE_ANY));
+
+ // Setting a purpose also sets the corresponding trust.
+ ASSERT_TRUE(X509_STORE_CTX_set_purpose(ctx.get(), X509_PURPOSE_SSL_SERVER));
+ EXPECT_EQ(ctx->param->purpose, X509_PURPOSE_SSL_SERVER);
+ EXPECT_EQ(ctx->param->trust, X509_TRUST_SSL_SERVER);
+
+ // Once set, the functions silently do nothing.
+ ASSERT_TRUE(X509_STORE_CTX_set_purpose(ctx.get(), X509_PURPOSE_SSL_CLIENT));
+ ASSERT_TRUE(X509_STORE_CTX_set_trust(ctx.get(), X509_TRUST_SSL_CLIENT));
+ EXPECT_EQ(ctx->param->purpose, X509_PURPOSE_SSL_SERVER);
+ EXPECT_EQ(ctx->param->trust, X509_TRUST_SSL_SERVER);
+
+ // Start over.
+ ctx.reset(X509_STORE_CTX_new());
+ ASSERT_TRUE(ctx);
+ ASSERT_TRUE(X509_STORE_CTX_init(ctx.get(), store.get(), leaf.get(), nullptr));
+ EXPECT_EQ(ctx->param->purpose, 0);
+ EXPECT_EQ(ctx->param->trust, 0);
+
+ // Setting trust leaves purpose unset.
+ ASSERT_TRUE(X509_STORE_CTX_set_trust(ctx.get(), X509_TRUST_SSL_SERVER));
+ EXPECT_EQ(ctx->param->purpose, 0);
+ EXPECT_EQ(ctx->param->trust, X509_TRUST_SSL_SERVER);
+
+ // If trust is set, but not purpose, |X509_STORE_CTX_set_purpose| only sets
+ // purpose.
+ ASSERT_TRUE(X509_STORE_CTX_set_purpose(ctx.get(), X509_PURPOSE_SSL_CLIENT));
+ EXPECT_EQ(ctx->param->purpose, X509_PURPOSE_SSL_CLIENT);
+ EXPECT_EQ(ctx->param->trust, X509_TRUST_SSL_SERVER);
+
+ // Start over.
+ ctx.reset(X509_STORE_CTX_new());
+ ASSERT_TRUE(ctx);
+ ASSERT_TRUE(X509_STORE_CTX_init(ctx.get(), store.get(), leaf.get(), nullptr));
+ EXPECT_EQ(ctx->param->purpose, 0);
+ EXPECT_EQ(ctx->param->trust, 0);
+
+ // If purpose is set, but not trust, |X509_STORE_CTX_set_purpose| only sets
+ // trust.
+ ASSERT_TRUE(X509_VERIFY_PARAM_set_purpose(
+ X509_STORE_CTX_get0_param(ctx.get()), X509_PURPOSE_SSL_CLIENT));
+ EXPECT_EQ(ctx->param->purpose, X509_PURPOSE_SSL_CLIENT);
+ EXPECT_EQ(ctx->param->trust, 0);
+
+ ASSERT_TRUE(X509_STORE_CTX_set_purpose(ctx.get(), X509_PURPOSE_SSL_SERVER));
+ EXPECT_EQ(ctx->param->purpose, X509_PURPOSE_SSL_CLIENT);
+ EXPECT_EQ(ctx->param->trust, X509_TRUST_SSL_SERVER);
+}
+
+TEST(X509Test, Purpose) {
+ bssl::UniquePtr<EVP_PKEY> key = PrivateKeyFromPEM(kP256Key);
+ ASSERT_TRUE(key);
+
+ struct {
+ int purpose;
+ int eku_nid;
+ std::vector<KeyUsage> key_usages;
+ } kTests[] = {
+ {X509_PURPOSE_SSL_CLIENT,
+ NID_client_auth,
+ {KeyUsage::kDigitalSignature, KeyUsage::kKeyAgreement}},
+ {X509_PURPOSE_SSL_SERVER,
+ NID_server_auth,
+ {KeyUsage::kDigitalSignature, KeyUsage::kKeyAgreement,
+ KeyUsage::kKeyEncipherment}},
+ {X509_PURPOSE_NS_SSL_SERVER,
+ NID_server_auth,
+ {KeyUsage::kKeyEncipherment}},
+ {X509_PURPOSE_SMIME_SIGN,
+ NID_email_protect,
+ {KeyUsage::kDigitalSignature, KeyUsage::kNonRepudiation}},
+ {X509_PURPOSE_SMIME_ENCRYPT,
+ NID_email_protect,
+ {KeyUsage::kKeyEncipherment}},
+ {X509_PURPOSE_CRL_SIGN, NID_undef, {KeyUsage::kCRLSign}},
+ };
+ for (const auto &t : kTests) {
+ SCOPED_TRACE(t.purpose);
+
+ auto configure_callback = [&](X509_STORE_CTX *ctx) {
+ X509_STORE_CTX_set_purpose(ctx, t.purpose);
+ };
+
+ // An unconstrained cert chain is valid.
+ bssl::UniquePtr<X509> root =
+ MakeTestCert("Root", "Root", key.get(), /*is_ca=*/true);
+ ASSERT_TRUE(root);
+ ASSERT_TRUE(X509_sign(root.get(), key.get(), EVP_sha256()));
+
+ bssl::UniquePtr<X509> intermediate =
+ MakeTestCert("Root", "Intermediate", key.get(), /*is_ca=*/true);
+ ASSERT_TRUE(intermediate);
+ ASSERT_TRUE(X509_sign(intermediate.get(), key.get(), EVP_sha256()));
+
+ bssl::UniquePtr<X509> leaf =
+ MakeTestCert("Intermediate", "Leaf", key.get(), /*is_ca=*/false);
+ ASSERT_TRUE(leaf);
+ ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
+
+ EXPECT_EQ(X509_V_OK, Verify(leaf.get(), {root.get()}, {intermediate.get()},
+ {}, 0, configure_callback));
+
+ // A leaf and intermediate with compatible constraints is valid.
+ intermediate =
+ MakeTestCert("Root", "Intermediate", key.get(), /*is_ca=*/true);
+ ASSERT_TRUE(intermediate);
+ ASSERT_TRUE(AddKeyUsage(intermediate.get(), {KeyUsage::kKeyCertSign}));
+ if (t.eku_nid != NID_undef) {
+ ASSERT_TRUE(AddExtendedKeyUsage(intermediate.get(), {t.eku_nid}));
+ }
+ ASSERT_TRUE(X509_sign(intermediate.get(), key.get(), EVP_sha256()));
+
+ leaf = MakeTestCert("Intermediate", "Leaf", key.get(), /*is_ca=*/false);
+ ASSERT_TRUE(leaf);
+ if (t.eku_nid != NID_undef) {
+ ASSERT_TRUE(AddExtendedKeyUsage(leaf.get(), {t.eku_nid}));
+ }
+ ASSERT_TRUE(AddKeyUsage(leaf.get(), t.key_usages));
+ ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
+
+ EXPECT_EQ(X509_V_OK, Verify(leaf.get(), {root.get()}, {intermediate.get()},
+ {}, 0, configure_callback));
+
+ // Each key usage asserted individually is valid.
+ for (KeyUsage usage : t.key_usages) {
+ SCOPED_TRACE(static_cast<int>(usage));
+ leaf = MakeTestCert("Intermediate", "Leaf", key.get(), /*is_ca=*/false);
+ ASSERT_TRUE(leaf);
+ if (t.eku_nid != NID_undef) {
+ ASSERT_TRUE(AddExtendedKeyUsage(leaf.get(), {t.eku_nid}));
+ }
+ ASSERT_TRUE(AddKeyUsage(leaf.get(), {usage}));
+ ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
+ EXPECT_EQ(X509_V_OK,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, 0,
+ configure_callback));
+ }
+
+ // A leaf with the wrong EKU is invalid.
+ if (t.eku_nid != NID_undef) {
+ leaf = MakeTestCert("Intermediate", "Leaf", key.get(), /*is_ca=*/false);
+ ASSERT_TRUE(leaf);
+ ASSERT_TRUE(AddExtendedKeyUsage(leaf.get(), {NID_rsaEncryption}));
+ ASSERT_TRUE(AddKeyUsage(leaf.get(), t.key_usages));
+ ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
+ EXPECT_EQ(X509_V_ERR_INVALID_PURPOSE,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, 0,
+ configure_callback));
+ }
+
+ // A leaf without any of the requested key usages is invalid.
+ std::vector<KeyUsage> usages;
+ for (int i = 0; i < 10; i++) {
+ auto k = static_cast<KeyUsage>(i);
+ if (std::find(t.key_usages.begin(), t.key_usages.end(), k) ==
+ t.key_usages.end()) {
+ usages.push_back(k);
+ }
+ }
+ leaf = MakeTestCert("Intermediate", "Leaf", key.get(), /*is_ca=*/false);
+ ASSERT_TRUE(leaf);
+ if (t.eku_nid != NID_undef) {
+ ASSERT_TRUE(AddExtendedKeyUsage(leaf.get(), {t.eku_nid}));
+ }
+ ASSERT_TRUE(AddKeyUsage(leaf.get(), usages));
+ ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
+ EXPECT_EQ(X509_V_ERR_INVALID_PURPOSE,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, 0,
+ configure_callback));
+
+ // Extra EKUs and key usages are fine.
+ usages.clear();
+ for (int i = 0; i < 10; i++) {
+ usages.push_back(static_cast<KeyUsage>(i));
+ }
+ leaf = MakeTestCert("Intermediate", "Leaf", key.get(), /*is_ca=*/false);
+ ASSERT_TRUE(leaf);
+ if (t.eku_nid != NID_undef) {
+ ASSERT_TRUE(
+ AddExtendedKeyUsage(leaf.get(), {t.eku_nid, NID_rsaEncryption}));
+ }
+ ASSERT_TRUE(AddKeyUsage(leaf.get(), usages));
+ ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
+ EXPECT_EQ(X509_V_OK, Verify(leaf.get(), {root.get()}, {intermediate.get()},
+ {}, 0, configure_callback));
+
+ // anyExtendedKeyUsage is not allowed in place of a concrete EKU.
+ if (t.eku_nid != NID_undef) {
+ leaf = MakeTestCert("Intermediate", "Leaf", key.get(), /*is_ca=*/false);
+ ASSERT_TRUE(leaf);
+ ASSERT_TRUE(AddExtendedKeyUsage(leaf.get(), {NID_anyExtendedKeyUsage}));
+ ASSERT_TRUE(AddKeyUsage(leaf.get(), t.key_usages));
+ ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
+ EXPECT_EQ(X509_V_ERR_INVALID_PURPOSE,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, 0,
+ configure_callback));
+ }
+
+ // Restore |leaf| to a valid option.
+ leaf = MakeTestCert("Intermediate", "Leaf", key.get(), /*is_ca=*/false);
+ ASSERT_TRUE(leaf);
+ ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
+
+ // The intermediate must have the keyCertSign bit. This bit is checked in
+ // multiple places. The first place that fails is in looking for candidate
+ // issuers.
+ intermediate =
+ MakeTestCert("Root", "Intermediate", key.get(), /*is_ca=*/true);
+ ASSERT_TRUE(intermediate);
+ ASSERT_TRUE(AddKeyUsage(intermediate.get(), {KeyUsage::kDigitalSignature}));
+ if (t.eku_nid != NID_undef) {
+ ASSERT_TRUE(AddExtendedKeyUsage(intermediate.get(), {t.eku_nid}));
+ }
+ ASSERT_TRUE(X509_sign(intermediate.get(), key.get(), EVP_sha256()));
+ EXPECT_EQ(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, 0,
+ configure_callback));
+
+ // The intermediate must have the EKU asserted.
+ if (t.eku_nid != NID_undef) {
+ intermediate =
+ MakeTestCert("Root", "Intermediate", key.get(), /*is_ca=*/true);
+ ASSERT_TRUE(intermediate);
+ ASSERT_TRUE(AddKeyUsage(intermediate.get(), {KeyUsage::kKeyCertSign}));
+ ASSERT_TRUE(AddExtendedKeyUsage(intermediate.get(), {NID_rsaEncryption}));
+ ASSERT_TRUE(X509_sign(intermediate.get(), key.get(), EVP_sha256()));
+ EXPECT_EQ(X509_V_ERR_INVALID_PURPOSE,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, 0,
+ configure_callback));
+ }
+ }
+}
+
+TEST(X509Test, Trust) {
+ struct Certs {
+ bssl::UniquePtr<X509> normal;
+ bssl::UniquePtr<X509> trusted_server, distrusted_server;
+ bssl::UniquePtr<X509> trusted_any, distrusted_any;
+ };
+ auto certs_from_pem = [](const char *pem) -> Certs {
+ Certs certs;
+ certs.normal = CertFromPEM(pem);
+ certs.trusted_server = CertFromPEM(pem);
+ certs.distrusted_server = CertFromPEM(pem);
+ certs.trusted_any = CertFromPEM(pem);
+ certs.distrusted_any = CertFromPEM(pem);
+ if (certs.normal == nullptr || certs.trusted_server == nullptr ||
+ certs.distrusted_server == nullptr || certs.trusted_any == nullptr ||
+ certs.distrusted_any == nullptr ||
+ !X509_add1_trust_object(certs.trusted_server.get(),
+ OBJ_nid2obj(NID_server_auth)) ||
+ !X509_add1_reject_object(certs.distrusted_server.get(),
+ OBJ_nid2obj(NID_server_auth)) ||
+ !X509_add1_trust_object(certs.trusted_any.get(),
+ OBJ_nid2obj(NID_anyExtendedKeyUsage)) ||
+ !X509_add1_reject_object(certs.distrusted_any.get(),
+ OBJ_nid2obj(NID_anyExtendedKeyUsage))) {
+ return Certs{};
+ }
+ return certs;
+ };
+
+ Certs root = certs_from_pem(kRootCAPEM);
+ Certs intermediate = certs_from_pem(kIntermediatePEM);
+ Certs leaf = certs_from_pem(kLeafPEM);
+ ASSERT_TRUE(root.normal);
+ ASSERT_TRUE(intermediate.normal);
+ ASSERT_TRUE(leaf.normal);
+
+ // By default, trust is determined by a combination of self-signedness and
+ // NID_anyExtendedKeyUsage.
+ EXPECT_EQ(X509_V_OK, Verify(leaf.normal.get(), {root.normal.get()},
+ {intermediate.normal.get()}, {}));
+ EXPECT_EQ(X509_V_OK, Verify(leaf.normal.get(), {root.trusted_any.get()},
+ {intermediate.normal.get()}, {}));
+ EXPECT_EQ(X509_V_ERR_CERT_REJECTED,
+ Verify(leaf.normal.get(), {root.distrusted_any.get()},
+ {intermediate.normal.get()}, {}));
+
+ // Intermediate certificates are not self-signed, so must have an
+ // NID_anyExtendedKeyUsage trust setting.
+ EXPECT_EQ(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
+ Verify(leaf.normal.get(), {intermediate.normal.get()}, {}, {}));
+ EXPECT_EQ(X509_V_OK, Verify(leaf.normal.get(),
+ {intermediate.trusted_any.get()}, {}, {}));
+ EXPECT_EQ(
+ X509_V_ERR_CERT_REJECTED,
+ Verify(leaf.normal.get(), {intermediate.distrusted_any.get()}, {}, {}));
+
+ // If a certificate has trust settings, but only for a different OID, the
+ // self-signed rule still takes effect.
+ EXPECT_EQ(X509_V_OK, Verify(leaf.normal.get(), {root.trusted_server.get()},
+ {intermediate.normal.get()}, {}));
+ EXPECT_EQ(X509_V_OK, Verify(leaf.normal.get(), {root.distrusted_server.get()},
+ {intermediate.normal.get()}, {}));
+ EXPECT_EQ(
+ X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
+ Verify(leaf.normal.get(), {intermediate.trusted_server.get()}, {}, {}));
+
+ // |X509_TRUST_SSL_SERVER| should instead look at self-signedness and
+ // |NID_server_auth|.
+ auto set_server_trust = [](X509_STORE_CTX *ctx) {
+ X509_STORE_CTX_set_trust(ctx, X509_TRUST_SSL_SERVER);
+ };
+ EXPECT_EQ(X509_V_OK, Verify(leaf.normal.get(), {root.normal.get()},
+ {intermediate.normal.get()}, {}, /*flags=*/0,
+ set_server_trust));
+ EXPECT_EQ(X509_V_OK, Verify(leaf.normal.get(), {root.trusted_server.get()},
+ {intermediate.normal.get()}, {}, /*flags=*/0,
+ set_server_trust));
+ EXPECT_EQ(
+ X509_V_ERR_CERT_REJECTED,
+ Verify(leaf.normal.get(), {root.distrusted_server.get()},
+ {intermediate.normal.get()}, {}, /*flags=*/0, set_server_trust));
+
+ EXPECT_EQ(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
+ Verify(leaf.normal.get(), {intermediate.normal.get()}, {}, {},
+ /*flags=*/0, set_server_trust));
+ EXPECT_EQ(X509_V_OK, Verify(leaf.normal.get(),
+ {intermediate.trusted_server.get()}, {}, {},
+ /*flags=*/0, set_server_trust));
+ EXPECT_EQ(X509_V_ERR_CERT_REJECTED,
+ Verify(leaf.normal.get(), {intermediate.distrusted_server.get()},
+ {}, {}, /*flags=*/0, set_server_trust));
+
+ // NID_anyExtendedKeyUsage is just an unrelated OID to X509_TRUST_SSL_SERVER.
+ // Unlike the default behavior, once a certificate has explicit trust settings
+ // for any OID, the self-signed check is disabled.
+ EXPECT_EQ(
+ X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
+ Verify(leaf.normal.get(), {root.trusted_any.get()},
+ {intermediate.normal.get()}, {}, /*flags=*/0, set_server_trust));
+}
diff --git a/crypto/x509/x509_trs.c b/crypto/x509/x509_trs.c
index 38dc96b..907e492 100644
--- a/crypto/x509/x509_trs.c
+++ b/crypto/x509/x509_trs.c
@@ -85,20 +85,18 @@
NULL}};
int X509_check_trust(X509 *x, int id, int flags) {
- int idx;
if (id == -1) {
- return 1;
+ return X509_TRUST_TRUSTED;
}
// We get this as a default value
if (id == 0) {
- int rv;
- rv = obj_trust(NID_anyExtendedKeyUsage, x, 0);
+ int rv = obj_trust(NID_anyExtendedKeyUsage, x, 0);
if (rv != X509_TRUST_UNTRUSTED) {
return rv;
}
return trust_compat(NULL, x, 0);
}
- idx = X509_TRUST_get_by_id(id);
+ int idx = X509_TRUST_get_by_id(id);
if (idx == -1) {
return obj_trust(id, x, flags);
}
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index f8f152b..929d2b3 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -1658,8 +1658,7 @@
}
int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name) {
- const X509_VERIFY_PARAM *param;
- param = X509_VERIFY_PARAM_lookup(name);
+ const X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_lookup(name);
if (!param) {
return 0;
}
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 644b66c..29a4930 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -659,11 +659,15 @@
// X509_add1_trust_object configures |x509| as a valid trust anchor for |obj|.
// It returns one on success and zero on error. |obj| should be a certificate
// usage OID associated with an |X509_TRUST| object.
+//
+// See |X509_VERIFY_PARAM_set_trust| for details on how this value is evaluated.
OPENSSL_EXPORT int X509_add1_trust_object(X509 *x509, const ASN1_OBJECT *obj);
// X509_add1_reject_object configures |x509| as distrusted for |obj|. It returns
// one on success and zero on error. |obj| should be a certificate usage OID
// associated with an |X509_TRUST| object.
+//
+// See |X509_VERIFY_PARAM_set_trust| for details on how this value is evaluated.
OPENSSL_EXPORT int X509_add1_reject_object(X509 *x509, const ASN1_OBJECT *obj);
// X509_trust_clear clears the list of OIDs for which |x509| is trusted. See
@@ -2185,6 +2189,323 @@
int idx);
+// Certificate stores.
+//
+// An |X509_STORE| contains trusted certificates, CRLs, and verification
+// parameters that are shared between multiple certificate verifications.
+//
+// Certificates in an |X509_STORE| are referred to as "trusted certificates",
+// but an individual certificate verification may not necessarily treat every
+// trusted certificate as a trust anchor. See |X509_VERIFY_PARAM_set_trust| for
+// details.
+//
+// WARNING: Although a trusted certificate which fails the
+// |X509_VERIFY_PARAM_set_trust| check is functionally an untrusted
+// intermediate certificate, callers should not rely on this to configure
+// untrusted intermediates in an |X509_STORE|. The trust check is complex, so
+// this risks inadvertently treating it as a trust anchor. Instead, configure
+// untrusted intermediates with the |chain| parameter of |X509_STORE_CTX_init|.
+//
+// Certificates in |X509_STORE| may be specified in several ways:
+// - Added by |X509_STORE_add_cert|.
+// - Returned by an |X509_LOOKUP| added by |X509_STORE_add_lookup|.
+//
+// |X509_STORE|s are reference-counted and may be shared by certificate
+// verifications running concurrently on multiple threads. However, an
+// |X509_STORE|'s verification parameters may not be modified concurrently with
+// certificate verification or other operations. Unless otherwise documented,
+// functions which take const pointer may be used concurrently, while
+// functions which take a non-const pointer may not. Callers that wish to modify
+// verification parameters in a shared |X509_STORE| should instead modify
+// |X509_STORE_CTX|s individually.
+
+// X509_STORE_new returns a newly-allocated |X509_STORE|, or NULL on error.
+OPENSSL_EXPORT X509_STORE *X509_STORE_new(void);
+
+// X509_STORE_up_ref adds one to the reference count of |store| and returns one.
+// Although |store| is not const, this function's use of |store| is thread-safe.
+OPENSSL_EXPORT int X509_STORE_up_ref(X509_STORE *store);
+
+// X509_STORE_free releases memory associated with |store|.
+OPENSSL_EXPORT void X509_STORE_free(X509_STORE *store);
+
+// X509_STORE_add_cert adds |x509| to |store| as a trusted certificate. It
+// returns one on success and zero on error. This function internally increments
+// |x509|'s reference count, so the caller retains ownership of |x509|.
+//
+// Certificates configured by this function are still subject to the checks
+// described in |X509_VERIFY_PARAM_set_trust|.
+//
+// Although |store| is not const, this function's use of |store| is thread-safe.
+// However, if this function is called concurrently with |X509_verify_cert|, it
+// is a race condition whether |x509| is available for issuer lookups.
+// Moreover, the result may differ for each issuer lookup performed by a single
+// |X509_verify_cert| call.
+OPENSSL_EXPORT int X509_STORE_add_cert(X509_STORE *store, X509 *x509);
+
+// X509_STORE_add_crl adds |crl| to |store|. It returns one on success and zero
+// on error. This function internally increments |crl|'s reference count, so the
+// caller retains ownership of |crl|. CRLs added in this way are candidates for
+// CRL lookup when |X509_V_FLAG_CRL_CHECK| is set.
+//
+// Although |store| is not const, this function's use of |store| is thread-safe.
+// However, if this function is called concurrently with |X509_verify_cert|, it
+// is a race condition whether |crl| is available for CRL checks. Moreover, the
+// result may differ for each CRL check performed by a single
+// |X509_verify_cert| call.
+//
+// Note there are no supported APIs to remove CRLs from |store| once inserted.
+// To vary the set of CRLs over time, callers should either create a new
+// |X509_STORE| or configure CRLs on a per-verification basis with
+// |X509_STORE_CTX_set0_crls|.
+OPENSSL_EXPORT int X509_STORE_add_crl(X509_STORE *store, X509_CRL *crl);
+
+// X509_STORE_set_purpose configures the purpose check for |store|. See
+// |X509_VERIFY_PARAM_set_purpose| for details.
+OPENSSL_EXPORT int X509_STORE_set_purpose(X509_STORE *store, int purpose);
+
+// X509_STORE_set_trust configures the trust check for |store|. See
+// |X509_VERIFY_PARAM_set_trust| for details.
+OPENSSL_EXPORT int X509_STORE_set_trust(X509_STORE *store, int trust);
+
+// TODO(crbug.com/boringssl/426): Move the other |X509_STORE| functions here.
+
+
+// Certificate verification.
+//
+// An |X509_STORE_CTX| object represents a single certificate verification
+// operation. To verify a certificate chain, callers construct an
+// |X509_STORE_CTX|, initialize it with |X509_STORE_CTX_init|, configure extra
+// parameters, and call |X509_verify_cert|.
+
+// X509_STORE_CTX_new returns a newly-allocated, empty |X509_STORE_CTX|, or NULL
+// on error.
+OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_new(void);
+
+// X509_STORE_CTX_free releases memory associated with |ctx|.
+OPENSSL_EXPORT void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
+
+// X509_STORE_CTX_init initializes |ctx| to verify |x509|, using trusted
+// certificates and parameters in |store|. It returns one on success and zero on
+// error. |chain| is a list of untrusted intermediate certificates to use in
+// verification.
+//
+// |ctx| stores pointers to |store|, |x509|, and |chain|. Each of these objects
+// must outlive |ctx| and may not be mutated for the duration of the certificate
+// verification.
+OPENSSL_EXPORT int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
+ X509 *x509, STACK_OF(X509) *chain);
+
+// X509_verify_cert performs certifice verification with |ctx|, which must have
+// been initialized with |X509_STORE_CTX_init|. It returns one on success and
+// zero on error. On success, |X509_STORE_CTX_get0_chain| or
+// |X509_STORE_CTX_get1_chain| may be used to return the verified certificate
+// chain. On error, |X509_STORE_CTX_get_error| may be used to return additional
+// error information.
+OPENSSL_EXPORT int X509_verify_cert(X509_STORE_CTX *ctx);
+
+// X509_STORE_CTX_set0_trusted_stack configures |ctx| to trust the certificates
+// in |sk|. |sk| must remain valid for the duration of |ctx|. Calling this
+// function causes |ctx| to ignore any certificates configured in the
+// |X509_STORE|. Certificates in |sk| are still subject to the check described
+// in |X509_VERIFY_PARAM_set_trust|.
+//
+// WARNING: This function differs from most |set0| functions in that it does not
+// take ownership of its input. The caller is required to ensure the lifetimes
+// are consistent.
+OPENSSL_EXPORT void X509_STORE_CTX_set0_trusted_stack(X509_STORE_CTX *ctx,
+ STACK_OF(X509) *sk);
+
+// X509_STORE_CTX_set_default looks up the set of parameters named |name| and
+// applies those default verification parameters for |ctx|. As in
+// |X509_VERIFY_PARAM_inherit|, only unset parameters are changed. This function
+// returns one on success and zero on error.
+//
+// The supported values of |name| are:
+// - "default" is an internal value which configures some late defaults. See the
+// discussion in |X509_STORE_get0_param|.
+// - "pkcs7" configures default trust and purpose checks for PKCS#7 signatures.
+// - "smime_sign" configures trust and purpose checks for S/MIME signatures.
+// - "ssl_client" configures trust and purpose checks for TLS clients.
+// - "ssl_server" configures trust and purpose checks for TLS servers.
+//
+// TODO(crbug.com/boringssl/441): Make "default" a no-op.
+OPENSSL_EXPORT int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx,
+ const char *name);
+
+// X509_STORE_CTX_set_purpose simultaneously configures |ctx|'s purpose and
+// trust checks, if unset. It returns one on success and zero if |purpose| is
+// not a valid purpose value. |purpose| should be an |X509_PURPOSE_*| constant.
+// If so, it configures |ctx| with a purpose check of |purpose| and a trust
+// check of |purpose|'s corresponding trust value. If either the purpose or
+// trust check had already been specified for |ctx|, that corresponding
+// modification is silently dropped.
+//
+// See |X509_VERIFY_PARAM_set_purpose| and |X509_VERIFY_PARAM_set_trust| for
+// details on the purpose and trust checks, respectively.
+//
+// If |purpose| is |X509_PURPOSE_ANY|, this function returns an error because it
+// has no corresponding |X509_TRUST_*| value. It is not possible to set
+// |X509_PURPOSE_ANY| with this function, only |X509_VERIFY_PARAM_set_purpose|.
+//
+// WARNING: Unlike similarly named functions in this header, this function
+// silently does not behave the same as |X509_VERIFY_PARAM_set_purpose|. Callers
+// may use |X509_VERIFY_PARAM_set_purpose| with |X509_STORE_CTX_get0_param| to
+// avoid this difference.
+OPENSSL_EXPORT int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
+
+// X509_STORE_CTX_set_trust configures |ctx|'s trust check, if unset. It returns
+// one on success and zero if |trust| is not a valid trust value. |trust| should
+// be an |X509_TRUST_*| constant. If so, it configures |ctx| with a trust check
+// of |trust|. If the trust check had already been specified for |ctx|, it
+// silently does nothing.
+//
+// See |X509_VERIFY_PARAM_set_trust| for details on the purpose and trust check.
+//
+// WARNING: Unlike similarly named functions in this header, this function
+// does not behave the same as |X509_VERIFY_PARAM_set_trust|. Callers may use
+// |X509_VERIFY_PARAM_set_trust| with |X509_STORE_CTX_get0_param| to avoid this
+// difference.
+OPENSSL_EXPORT int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust);
+
+// TODO(crbug.com/boringssl/426): Move the other |X509_STORE_CTX| functions
+// here.
+
+
+// Verification parameters.
+//
+// An |X509_VERIFY_PARAM| contains a set of parameters for certificate
+// verification.
+
+// X509_VERIFY_PARAM_new returns a newly-allocated |X509_VERIFY_PARAM|, or NULL
+// on error.
+OPENSSL_EXPORT X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void);
+
+// X509_VERIFY_PARAM_free releases memory associated with |param|.
+OPENSSL_EXPORT void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param);
+
+// X509_PURPOSE_SSL_CLIENT validates TLS client certificates. It checks for the
+// id-kp-clientAuth EKU and one of digitalSignature or keyAgreement key usages.
+// The TLS library is expected to check for the key usage specific to the
+// negotiated TLS parameters.
+#define X509_PURPOSE_SSL_CLIENT 1
+// X509_PURPOSE_SSL_SERVER validates TLS server certificates. It checks for the
+// id-kp-clientAuth EKU and one of digitalSignature, keyAgreement, or
+// keyEncipherment key usages. The TLS library is expected to check for the key
+// usage specific to the negotiated TLS parameters.
+#define X509_PURPOSE_SSL_SERVER 2
+// X509_PURPOSE_NS_SSL_SERVER is a legacy mode. It behaves like
+// |X509_PURPOSE_SSL_SERVER|, but only accepts the keyEncipherment key usage,
+// used by SSL 2.0 and RSA key exchange. Do not use this.
+#define X509_PURPOSE_NS_SSL_SERVER 3
+// X509_PURPOSE_SMIME_SIGN validates S/MIME signing certificates. It checks for
+// the id-kp-emailProtection EKU and one of digitalSignature or nonRepudiation
+// key usages.
+#define X509_PURPOSE_SMIME_SIGN 4
+// X509_PURPOSE_SMIME_ENCRYPT validates S/MIME encryption certificates. It
+// checks for the id-kp-emailProtection EKU and keyEncipherment key usage.
+#define X509_PURPOSE_SMIME_ENCRYPT 5
+// X509_PURPOSE_CRL_SIGN validates indirect CRL signers. It checks for the
+// cRLSign key usage. BoringSSL does not support indirect CRLs and does not use
+// this mode.
+#define X509_PURPOSE_CRL_SIGN 6
+// X509_PURPOSE_ANY performs no EKU or key usage checks. Such checks are the
+// responsibility of the caller.
+#define X509_PURPOSE_ANY 7
+// X509_PURPOSE_OCSP_HELPER performs no EKU or key usage checks. It was
+// historically used in OpenSSL's OCSP implementation, which left those checks
+// to the OCSP implementation itself.
+#define X509_PURPOSE_OCSP_HELPER 8
+// X509_PURPOSE_TIMESTAMP_SIGN validates Time Stamping Authority (RFC 3161)
+// certificates. It checks for the id-kp-timeStamping EKU and one of
+// digitalSignature or nonRepudiation key usages. It additionally checks that
+// the EKU extension is critical and that no other EKUs or key usages are
+// asserted.
+#define X509_PURPOSE_TIMESTAMP_SIGN 9
+
+// X509_VERIFY_PARAM_set_purpose configures |param| to validate certificates for
+// a specified purpose. It returns one on success and zero if |purpose| is not a
+// valid purpose type. |purpose| should be one of the |X509_PURPOSE_*| values.
+//
+// This option controls checking the extended key usage (EKU) and key usage
+// extensions. These extensions specify how a certificate's public key may be
+// used and are important to avoid cross-protocol attacks, particularly in PKIs
+// that may issue certificates for multiple protocols, or for protocols that use
+// keys in multiple ways. If not configured, these security checks are the
+// caller's responsibility.
+//
+// This library applies the EKU checks to all untrusted intermediates. Although
+// not defined in RFC 5280, this matches widely-deployed practice. It also does
+// not accept anyExtendedKeyUsage.
+//
+// Many purpose values have a corresponding trust value, which is not configured
+// by this function. See |X509_VERIFY_PARAM_set_trust| for details. Callers
+// that wish to configure both should either call both functions, or use
+// |X509_STORE_CTX_set_purpose|.
+//
+// It is currently not possible to configure custom EKU OIDs or key usage bits.
+// Contact the BoringSSL maintainers if your application needs to do so. OpenSSL
+// had an |X509_PURPOSE_add| API, but it was not thread-safe and relied on
+// global mutable state, so we removed it.
+//
+// TODO(davidben): This function additionally configures checking the legacy
+// Netscape certificate type extension. Remove this.
+OPENSSL_EXPORT int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param,
+ int purpose);
+
+// X509_TRUST_COMPAT evaluates trust using only the self-signed fallback. Trust
+// and distrust OIDs are ignored.
+#define X509_TRUST_COMPAT 1
+// X509_TRUST_SSL_CLIENT evaluates trust with the |NID_client_auth| OID, for
+// validating TLS client certificates.
+#define X509_TRUST_SSL_CLIENT 2
+// X509_TRUST_SSL_SERVER evaluates trust with the |NID_server_auth| OID, for
+// validating TLS server certificates.
+#define X509_TRUST_SSL_SERVER 3
+// X509_TRUST_EMAIL evaluates trust with the |NID_email_protect| OID, for
+// validating S/MIME email certificates.
+#define X509_TRUST_EMAIL 4
+// X509_TRUST_OBJECT_SIGN evaluates trust with the |NID_code_sign| OID, for
+// validating code signing certificates.
+#define X509_TRUST_OBJECT_SIGN 5
+// X509_TRUST_TSA evaluates trust with the |NID_time_stamp| OID, for validating
+// Time Stamping Authority (RFC 3161) certificates.
+#define X509_TRUST_TSA 8
+
+// X509_VERIFY_PARAM_set_trust configures which certificates from |X509_STORE|
+// are trust anchors. It returns one on success and zero if |trust| is not a
+// valid trust value. |trust| should be one of the |X509_TRUST_*| constants.
+// This function allows applications to vary trust anchors when the same set of
+// trusted certificates is used in multiple contexts.
+//
+// Two properties determine whether a certificate is a trust anchor:
+//
+// - Whether it is trusted or distrusted for some OID, via auxiliary information
+// configured by |X509_add1_trust_object| or |X509_add1_reject_object|.
+//
+// - Whether it is "self-signed". That is, whether |X509_get_extension_flags|
+// includes |EXFLAG_SS|. The signature itself is not checked.
+//
+// When this function is called, |trust| determines the OID to check in the
+// first case. If the certificate is not explicitly trusted or distrusted for
+// any OID, it is trusted if self-signed instead.
+//
+// If unset, the default behavior is to check for the |NID_anyExtendedKeyUsage|
+// OID. If the certificate is not explicitly trusted or distrusted for this OID,
+// it is trusted if self-signed instead. Note this slightly differs from the
+// above.
+//
+// It is currently not possible to configure custom trust OIDs. Contact the
+// BoringSSL maintainers if your application needs to do so. OpenSSL had an
+// |X509_TRUST_add| API, but it was not thread-safe and relied on global mutable
+// state, so we removed it.
+OPENSSL_EXPORT int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param,
+ int trust);
+
+// TODO(crbug.com/boringssl/426): Move the other |X509_VERIFY_PARAM| functions
+// here.
+
+
// SignedPublicKeyAndChallenge structures.
//
// The SignedPublicKeyAndChallenge (SPKAC) is a legacy structure to request
@@ -3109,6 +3430,31 @@
OPENSSL_EXPORT int X509_STORE_CTX_get1_issuer(X509 **out_issuer,
X509_STORE_CTX *ctx, X509 *x509);
+// X509_check_purpose performs checks if |x509|'s basic constraints, key usage,
+// and extended key usage extensions for the specified purpose. |purpose| should
+// be one of |X509_PURPOSE_*| constants. See |X509_VERIFY_PARAM_set_purpose| for
+// details. It returns one if |x509|'s extensions are consistent with |purpose|
+// and zero otherwise. If |ca| is non-zero, |x509| is checked as a CA
+// certificate. Otherwise, it is checked as an end-entity certificate.
+//
+// If |purpose| is -1, this function performs no purpose checks, but it parses
+// some extensions in |x509| and may return zero on syntax error. Historically,
+// callers primarily used this function to trigger this parsing, but this is no
+// longer necessary. Functions acting on |X509| will internally parse as needed.
+OPENSSL_EXPORT int X509_check_purpose(X509 *x509, int purpose, int ca);
+
+#define X509_TRUST_TRUSTED 1
+#define X509_TRUST_REJECTED 2
+#define X509_TRUST_UNTRUSTED 3
+
+// X509_check_trust checks if |x509| is a valid trust anchor for trust type
+// |id|. See |X509_VERIFY_PARAM_set_trust| for details. It returns
+// |X509_TRUST_TRUSTED| if |x509| is a trust anchor, |X509_TRUST_REJECTED| if it
+// was distrusted, and |X509_TRUST_UNTRUSTED| otherwise. |id| should be one of
+// the |X509_TRUST_*| constants, or zero to indicate the default behavior.
+// |flags| should be zero and is ignored.
+OPENSSL_EXPORT int X509_check_trust(X509 *x509, int id, int flags);
+
// X.509 information.
//
@@ -3570,19 +3916,6 @@
#define X509_TRUST_DEFAULT (-1) // Only valid in purpose settings
-#define X509_TRUST_COMPAT 1
-#define X509_TRUST_SSL_CLIENT 2
-#define X509_TRUST_SSL_SERVER 3
-#define X509_TRUST_EMAIL 4
-#define X509_TRUST_OBJECT_SIGN 5
-#define X509_TRUST_TSA 8
-
-// check_trust return codes
-
-#define X509_TRUST_TRUSTED 1
-#define X509_TRUST_REJECTED 2
-#define X509_TRUST_UNTRUSTED 3
-
// X509_verify_cert_error_string returns |err| as a human-readable string, where
// |err| should be one of the |X509_V_*| values. If |err| is unknown, it returns
// a default description.
@@ -3628,15 +3961,6 @@
OPENSSL_EXPORT int X509_CRL_match(const X509_CRL *a, const X509_CRL *b);
-// X509_verify_cert performs certifice verification with |ctx|, which must have
-// been initialized with |X509_STORE_CTX_init|. It returns one on success and
-// zero on error. On success, |X509_STORE_CTX_get0_chain| or
-// |X509_STORE_CTX_get1_chain| may be used to return the verified certificate
-// chain. On error, |X509_STORE_CTX_get_error| may be used to return additional
-// error information.
-OPENSSL_EXPORT int X509_verify_cert(X509_STORE_CTX *ctx);
-
-OPENSSL_EXPORT int X509_check_trust(X509 *x, int id, int flags);
OPENSSL_EXPORT int X509_TRUST_get_count(void);
OPENSSL_EXPORT const X509_TRUST *X509_TRUST_get0(int idx);
OPENSSL_EXPORT int X509_TRUST_get_by_id(int id);
@@ -3845,15 +4169,6 @@
// a certificate.
OPENSSL_EXPORT X509 *X509_OBJECT_get0_X509(const X509_OBJECT *obj);
-// X509_STORE_new returns a newly-allocated |X509_STORE|, or NULL on error.
-OPENSSL_EXPORT X509_STORE *X509_STORE_new(void);
-
-// X509_STORE_up_ref adds one to the reference count of |store| and returns one.
-OPENSSL_EXPORT int X509_STORE_up_ref(X509_STORE *store);
-
-// X509_STORE_free releases memory associated with |store|.
-OPENSSL_EXPORT void X509_STORE_free(X509_STORE *store);
-
OPENSSL_EXPORT STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *st);
OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *st,
X509_NAME *nm);
@@ -3868,9 +4183,6 @@
// the |X509_STORE|. See discussion in |X509_STORE_get0_param|.
OPENSSL_EXPORT int X509_STORE_set_flags(X509_STORE *store, unsigned long flags);
-OPENSSL_EXPORT int X509_STORE_set_purpose(X509_STORE *store, int purpose);
-OPENSSL_EXPORT int X509_STORE_set_trust(X509_STORE *store, int trust);
-
// |X509_STORE_set1_param| copies verification parameters from |param| as in
// |X509_VERIFY_PARAM_set1|. It returns one on success and zero on error.
OPENSSL_EXPORT int X509_STORE_set1_param(X509_STORE *store,
@@ -3896,35 +4208,6 @@
// |X509_V_FLAG_TRUSTED_FIRST| is mostly a workaround for poor path-building.
OPENSSL_EXPORT X509_VERIFY_PARAM *X509_STORE_get0_param(X509_STORE *store);
-// X509_STORE_CTX_new returns a newly-allocated, empty |X509_STORE_CTX|, or NULL
-// on error.
-OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_new(void);
-
-// X509_STORE_CTX_free releases memory associated with |ctx|.
-OPENSSL_EXPORT void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
-
-// X509_STORE_CTX_init initializes |ctx| to verify |x509|, using trusted
-// certificates and parameters in |store|. It returns one on success and zero on
-// error. |chain| is a list of untrusted intermediate certificates to use in
-// verification.
-//
-// |ctx| stores pointers to |store|, |x509|, and |chain|. Each of these objects
-// must outlive |ctx| and may not be mutated for the duration of the certificate
-// verification.
-OPENSSL_EXPORT int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
- X509 *x509, STACK_OF(X509) *chain);
-
-// X509_STORE_CTX_set0_trusted_stack configures |ctx| to trust the certificates
-// in |sk|. |sk| must remain valid for the duration of |ctx|. Calling this
-// function causes |ctx| to ignore any certificates configured in the
-// |X509_STORE|.
-//
-// WARNING: This function differs from most |set0| functions in that it does not
-// take ownership of its input. The caller is required to ensure the lifetimes
-// are consistent.
-OPENSSL_EXPORT void X509_STORE_CTX_set0_trusted_stack(X509_STORE_CTX *ctx,
- STACK_OF(X509) *sk);
-
// X509_STORE_CTX_get0_store returns the |X509_STORE| that |ctx| uses.
OPENSSL_EXPORT X509_STORE *X509_STORE_CTX_get0_store(const X509_STORE_CTX *ctx);
@@ -3938,9 +4221,6 @@
OPENSSL_EXPORT const X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void);
OPENSSL_EXPORT const X509_LOOKUP_METHOD *X509_LOOKUP_file(void);
-OPENSSL_EXPORT int X509_STORE_add_cert(X509_STORE *ctx, X509 *x);
-OPENSSL_EXPORT int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x);
-
OPENSSL_EXPORT int X509_STORE_CTX_get_by_subject(X509_STORE_CTX *vs, int type,
X509_NAME *name,
X509_OBJECT *ret);
@@ -4008,8 +4288,9 @@
const X509_STORE_CTX *ctx);
OPENSSL_EXPORT void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c,
STACK_OF(X509_CRL) *sk);
-OPENSSL_EXPORT int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
-OPENSSL_EXPORT int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust);
+
+// X509_STORE_CTX_purpose_inherit is an internal implementation detail that will
+// shortly be removed.
OPENSSL_EXPORT int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx,
int def_purpose, int purpose,
int trust);
@@ -4052,22 +4333,6 @@
OPENSSL_EXPORT void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx,
X509_VERIFY_PARAM *param);
-// X509_STORE_CTX_set_default looks up the set of parameters named |name| and
-// applies those default verification parameters for |ctx|. As in
-// |X509_VERIFY_PARAM_inherit|, only unset parameters are changed. This function
-// returns one on success and zero on error.
-OPENSSL_EXPORT int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx,
- const char *name);
-
-// X509_VERIFY_PARAM functions
-
-// X509_VERIFY_PARAM_new returns a newly-allocated |X509_VERIFY_PARAM|, or NULL
-// on error.
-OPENSSL_EXPORT X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void);
-
-// X509_VERIFY_PARAM_free releases memory associated with |param|.
-OPENSSL_EXPORT void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param);
-
// X509_VERIFY_PARAM_inherit applies |from| as the default values for |to|. That
// is, for each parameter that is unset in |to|, it copies the value in |from|.
// This function returns one on success and zero on error.
@@ -4096,11 +4361,6 @@
OPENSSL_EXPORT unsigned long X509_VERIFY_PARAM_get_flags(
const X509_VERIFY_PARAM *param);
-OPENSSL_EXPORT int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param,
- int purpose);
-OPENSSL_EXPORT int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param,
- int trust);
-
// X509_VERIFY_PARAM_set_depth configures |param| to limit certificate chains to
// |depth| intermediate certificates. This count excludes both the target
// certificate and the trust anchor (root certificate).
@@ -4375,16 +4635,6 @@
void *usr_data;
} X509_PURPOSE;
-#define X509_PURPOSE_SSL_CLIENT 1
-#define X509_PURPOSE_SSL_SERVER 2
-#define X509_PURPOSE_NS_SSL_SERVER 3
-#define X509_PURPOSE_SMIME_SIGN 4
-#define X509_PURPOSE_SMIME_ENCRYPT 5
-#define X509_PURPOSE_CRL_SIGN 6
-#define X509_PURPOSE_ANY 7
-#define X509_PURPOSE_OCSP_HELPER 8
-#define X509_PURPOSE_TIMESTAMP_SIGN 9
-
DEFINE_STACK_OF(X509_PURPOSE)
DECLARE_ASN1_FUNCTIONS_const(BASIC_CONSTRAINTS)
@@ -4586,8 +4836,6 @@
OPENSSL_EXPORT int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid,
void *value, int crit, unsigned long flags);
-OPENSSL_EXPORT int X509_check_purpose(X509 *x, int id, int ca);
-
OPENSSL_EXPORT int X509_PURPOSE_set(int *p, int purpose);
OPENSSL_EXPORT int X509_PURPOSE_get_count(void);