diff options
author | Ben Laurie <ben@openssl.org> | 2012-12-14 12:53:53 +0000 |
---|---|---|
committer | Ben Laurie <ben@openssl.org> | 2012-12-14 12:53:53 +0000 |
commit | d65b8b2162f33ac0d53dace588a0847ed827626c (patch) | |
tree | 7fc5f91d14728ccb6934605677bd537b847e6998 | |
parent | 5dca1e338c068931a1cdcb76d8db303a3d3dce25 (diff) |
Backport OCSP fixes.
75 files changed, 2095 insertions, 41 deletions
@@ -4,6 +4,16 @@ Changes between 1.0.1 and 1.0.2 [xx XXX xxxx] + *) Fix OCSP checking. + [Rob Stradling <rob.stradling@comodo.com> and Ben Laurie] + + *) Backport support for partial chain verification: if an intermediate + certificate is explicitly trusted (using -addtrust option to x509 + utility for example) the verification is sucessful even if the chain + is not complete. + The OCSP checking fix depends on this backport. + [Steve Henson and Rob Stradling <rob.stradling@comodo.com>] + *) Add -trusted_first option which attempts to find certificates in the trusted store even if an untrusted chain is also supplied. [Steve Henson] diff --git a/apps/ocsp.c b/apps/ocsp.c index 01847dfad7..ce9bfa52d6 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c @@ -866,6 +866,8 @@ int MAIN(int argc, char **argv) goto end; } + ret = 0; + if (!noverify) { if (req && ((i = OCSP_check_nonce(req, bs)) <= 0)) @@ -875,17 +877,17 @@ int MAIN(int argc, char **argv) else { BIO_printf(bio_err, "Nonce Verify error\n"); + ret = 1; goto end; } } i = OCSP_basic_verify(bs, verify_other, store, verify_flags); - if (i < 0) i = OCSP_basic_verify(bs, NULL, store, 0); - if(i <= 0) { BIO_printf(bio_err, "Response Verify Failure\n"); ERR_print_errors(bio_err); + ret = 1; } else BIO_printf(bio_err, "Response verify OK\n"); @@ -893,9 +895,7 @@ int MAIN(int argc, char **argv) } if (!print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage)) - goto end; - - ret = 0; + ret = 1; end: ERR_print_errors(bio_err); diff --git a/crypto/ocsp/ocsp_vfy.c b/crypto/ocsp/ocsp_vfy.c index 8a5e788d96..214b4020fe 100644 --- a/crypto/ocsp/ocsp_vfy.c +++ b/crypto/ocsp/ocsp_vfy.c @@ -77,8 +77,10 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, { X509 *signer, *x; STACK_OF(X509) *chain = NULL; + STACK_OF(X509) *tmpchain = NULL; + X509_STORE *tmpstore = NULL; X509_STORE_CTX ctx; - int i, ret = 0; + int i, ret; ret = ocsp_find_signer(&signer, bs, certs, st, flags); if (!ret) { @@ -86,7 +88,7 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, goto end; } if ((ret == 2) && (flags & OCSP_TRUSTOTHER)) - flags |= OCSP_NOVERIFY; + chain = certs; if (!(flags & OCSP_NOSIGS)) { EVP_PKEY *skey; @@ -102,6 +104,60 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, if (!(flags & OCSP_NOVERIFY)) { int init_res; + + /* If we trust the signer, we don't need to build a chain. + * (If the signer is a root certificate, X509_verify_cert() + * would fail anyway!) + */ + if (chain == certs) goto verified_chain; + + /* If we trust some "other" certificates, mark them as + * explicitly trusted (because some of them might be + * Intermediate CA Certificates), put them in a store and + * attempt to build a trusted chain. + */ + if ((flags & OCSP_TRUSTOTHER) && (certs != NULL)) + { + ASN1_OBJECT *objtmp = OBJ_nid2obj(NID_OCSP_sign); + tmpstore = X509_STORE_new(); + if (!tmpstore) + { + ret = -1; + OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, ERR_R_MALLOC_FAILURE); + goto end; + } + for (i = 0; i < sk_X509_num(certs); i++) + { + X509 *xother = sk_X509_value(certs, i); + X509_add1_trust_object(xother, objtmp); + if (!X509_STORE_add_cert(tmpstore, xother)) + { + ret = -1; + goto end; + } + } + + init_res = X509_STORE_CTX_init(&ctx, tmpstore, signer, NULL); + if (!init_res) + { + ret = -1; + OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,ERR_R_X509_LIB); + goto end; + } + X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER); + ret = X509_verify_cert(&ctx); + if (ret == 1) + { + chain = tmpchain = X509_STORE_CTX_get1_chain(&ctx); + X509_STORE_CTX_cleanup(&ctx); + goto verified_chain; + } + X509_STORE_CTX_cleanup(&ctx); + } + + /* Attempt to build a chain up to a Root Certificate in the + * trust store provided by the caller. + */ if(flags & OCSP_NOCHAIN) init_res = X509_STORE_CTX_init(&ctx, st, signer, NULL); else @@ -115,16 +171,18 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER); ret = X509_verify_cert(&ctx); - chain = X509_STORE_CTX_get1_chain(&ctx); + chain = tmpchain = X509_STORE_CTX_get1_chain(&ctx); X509_STORE_CTX_cleanup(&ctx); - if (ret <= 0) + if (ret <= 0) { i = X509_STORE_CTX_get_error(&ctx); OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,OCSP_R_CERTIFICATE_VERIFY_ERROR); ERR_add_error_data(2, "Verify error:", X509_verify_cert_error_string(i)); - goto end; - } + goto end; + } + + verified_chain: if(flags & OCSP_NOCHECKS) { ret = 1; @@ -155,7 +213,8 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, end: - if(chain) sk_X509_pop_free(chain, X509_free); + if(tmpchain) sk_X509_pop_free(tmpchain, X509_free); + if(tmpstore) X509_STORE_free(tmpstore); return ret; } diff --git a/crypto/x509/x509_trs.c b/crypto/x509/x509_trs.c index a6cb9c8b1b..3d7e06815c 100644 --- a/crypto/x509/x509_trs.c +++ b/crypto/x509/x509_trs.c @@ -114,6 +114,15 @@ int X509_check_trust(X509 *x, int id, int flags) X509_TRUST *pt; int idx; if(id == -1) return 1; + /* We get this as a default value */ + if (id == 0) + { + int rv; + 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); if(idx == -1) return default_trust(id, x, flags); pt = X509_TRUST_get0(idx); diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 99cf5be3fc..c7aa575920 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -323,8 +323,13 @@ int X509_verify_cert(X509_STORE_CTX *ctx) /* we now have our chain, lets check it... */ - /* Is last certificate looked up self signed? */ - if (!ctx->check_issued(ctx,x,x)) + i = check_trust(ctx); + + /* If explicitly rejected error */ + if (i == X509_TRUST_REJECTED) + goto end; + /* If not explicitly trusted then indicate error */ + if (i != X509_TRUST_TRUSTED) { if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss)) { @@ -362,12 +367,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx) if (!ok) goto end; - /* The chain extensions are OK: check trust */ - - if (param->trust > 0) ok = check_trust(ctx); - - if (!ok) goto end; - /* We may as well copy down any DSA parameters that are required */ X509_get_pubkey_parameters(NULL,ctx->chain); @@ -658,28 +657,35 @@ static int check_name_constraints(X509_STORE_CTX *ctx) static int check_trust(X509_STORE_CTX *ctx) { -#ifdef OPENSSL_NO_CHAIN_VERIFY - return 1; -#else int i, ok; - X509 *x; + X509 *x = NULL; int (*cb)(int xok,X509_STORE_CTX *xctx); cb=ctx->verify_cb; -/* For now just check the last certificate in the chain */ - i = sk_X509_num(ctx->chain) - 1; - x = sk_X509_value(ctx->chain, i); - ok = X509_check_trust(x, ctx->param->trust, 0); - if (ok == X509_TRUST_TRUSTED) - return 1; - ctx->error_depth = i; - ctx->current_cert = x; - if (ok == X509_TRUST_REJECTED) - ctx->error = X509_V_ERR_CERT_REJECTED; - else - ctx->error = X509_V_ERR_CERT_UNTRUSTED; - ok = cb(0, ctx); - return ok; -#endif + /* Check all trusted certificates in chain */ + for (i = ctx->last_untrusted; i < sk_X509_num(ctx->chain); i++) + { + x = sk_X509_value(ctx->chain, i); + ok = X509_check_trust(x, ctx->param->trust, 0); + /* If explicitly trusted return trusted */ + if (ok == X509_TRUST_TRUSTED) + return X509_TRUST_TRUSTED; + /* If explicitly rejected notify callback and reject if + * not overridden. + */ + if (ok == X509_TRUST_REJECTED) + { + ctx->error_depth = i; + ctx->current_cert = x; + ctx->error = X509_V_ERR_CERT_REJECTED; + ok = cb(0, ctx); + if (!ok) + return X509_TRUST_REJECTED; + } + } + /* If no trusted certs in chain at all return untrusted and + * allow standard (no issuer cert) etc errors to be indicated. + */ + return X509_TRUST_UNTRUSTED; } static int check_revocation(X509_STORE_CTX *ctx) diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c index 2cc75eecaa..b1eeaf9cf1 100644 --- a/crypto/x509v3/v3_purp.c +++ b/crypto/x509v3/v3_purp.c @@ -87,7 +87,7 @@ static X509_PURPOSE xstandard[] = { {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL}, {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, "CRL signing", "crlsign", NULL}, {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any", NULL}, - {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, "OCSP helper", "ocsphelper", NULL}, + {X509_PURPOSE_OCSP_HELPER, X509_TRUST_OCSP_SIGN, 0, ocsp_helper, "OCSP helper", "ocsphelper", NULL}, {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign", NULL}, }; @@ -447,6 +447,10 @@ static void x509v3_cache_extensions(X509 *x) case NID_dvcs: x->ex_xkusage |= XKU_DVCS; break; + + case NID_anyExtendedKeyUsage: + x->ex_xkusage |= XKU_ANYEKU; + break; } } sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free); diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h index b308abe7cd..34909475ae 100644 --- a/crypto/x509v3/x509v3.h +++ b/crypto/x509v3/x509v3.h @@ -451,6 +451,7 @@ struct ISSUING_DIST_POINT_st #define XKU_OCSP_SIGN 0x20 #define XKU_TIMESTAMP 0x40 #define XKU_DVCS 0x80 +#define XKU_ANYEKU 0x100 #define X509_PURPOSE_DYNAMIC 0x1 #define X509_PURPOSE_DYNAMIC_NAME 0x2 diff --git a/test/Makefile b/test/Makefile index 3bb739001c..331c721c9b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -137,7 +137,7 @@ alltests: \ test_enc test_x509 test_rsa test_crl test_sid \ test_gen test_req test_pkcs7 test_verify test_dh test_dsa \ test_ss test_ca test_engine test_evp test_ssl test_tsa test_ige \ - test_jpake test_srp test_cms + test_jpake test_srp test_cms test_ocsp test_evp: ../util/shlib_wrap.sh ./$(EVPTEST) evptests.txt @@ -318,6 +318,10 @@ test_srp: $(SRPTEST)$(EXE_EXT) @echo "Test SRP" ../util/shlib_wrap.sh ./srptest +test_ocsp: + @echo "Test OCSP" + @sh ./tocsp + lint: lint -DLINT $(INCLUDES) $(SRC)>fluff diff --git a/test/ocsp-tests/D1.ors b/test/ocsp-tests/D1.ors new file mode 100644 index 0000000000..3fa4a11de2 --- /dev/null +++ b/test/ocsp-tests/D1.ors @@ -0,0 +1,32 @@ +MIIFzwoBAKCCBcgwggXEBgkrBgEFBQcwAQEEggW1MIIFsTCBoKIWBBRf2uQDFpGg +Ywh4P1y2H9bZ2/BQNBgPMjAxMjEwMjMxMDI1MzZaMHUwczBLMAkGBSsOAwIaBQAE +FKByDqBqfGICVPKo9Z3Se6Tzty+kBBSwsEr9HHUo+BxhqhP2+sGQPWsWowISESG8 +vx4IzALnkqQG05AvM+2bgAAYDzIwMTIxMDIzMDcwMDAwWqARGA8yMDEyMTAzMDA4 +MDAwMFowCwYJKoZIhvcNAQEFA4IBAQAJU3hXN7NApN50/vlZTG2p8+QQJp4uaod3 +wyBQ0Ux3DoQZQ9RG6/7Mm4qpOLCCSTh/lJjZ0fD+9eB3gcp/JupN1JrU+dgTyv/Y +9MOctJz7y+VoU9I+qB8knV4sQCwohAVm8GmA9s4p/rHq5Oymci0SuG/QCfkVxOub +rI1bWjbHLvvXyvF3PoGMORVHG3SA+jJ9VkHWJyi6brHxY+QR/iYxer8lJsBtpyc7 +q2itFgvax/OHwne3lxsck9q0QgKpmEdJu2LuGyWFIhrEwR3b7ASEu1G/nKClv3dR +vyOXMm1XIwuUhCjAcpNEKiOMorFwnLS1F8LhfqFWTAFG0JbWpAi8oIID+DCCA/Qw +ggPwMIIC2KADAgECAhIRISdENsrz1CSWG3VIBwfQERQwDQYJKoZIhvcNAQEFBQAw +WTELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExLzAtBgNV +BAMTJkdsb2JhbFNpZ24gRXh0ZW5kZWQgVmFsaWRhdGlvbiBDQSAtIEcyMB4XDTEy +MDkxOTA3NDA1MFoXDTEyMTIxOTA4NDA1MFowgYUxCzAJBgNVBAYTAkJFMRkwFwYD +VQQKExBHbG9iYWxTaWduIG52LXNhMUIwQAYDVQQDEzlHbG9iYWxTaWduIEV4dGVu +ZGVkIFZhbGlkYXRpb24gQ0EgLSBHMiBPQ1NQIHJlc3BvbmRlciAtIDIxFzAVBgNV +BAUTDjIwMTIwOTE5MDk0MDAwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAnCgMsBO+IxIqCnXCOfXJoIC3wj+f0s4DV9h2gJBzisWXkaJD2DfNrd0kHUXK +qVVPUxnA4G5iZu0Z385/KiOt1/P6vQ/Z2/AsEh/8Z/hIyeZCHL31wrSZW4yLeZwi +M76wPiBHJxPun681HQlVs/OGKSHnbHc1XJAIeA/M8u+lLWqIKB+AJ82TrOqUMj1s +LjGhQNs84xPliONN5K7DrEy+Y65X/rFxN77Smw+UtcH1GgH2NgaHH8dpt1m25sgm +UxZWhdx66opB/lbRQwWdGt7MC0kJFaWHDZq64DTuYoekFYSxAFu0nd0EekEHEJEi +9mquB9cv/96SuEJl8BcUWU/1LwIDAQABo4GEMIGBMAkGA1UdEwQCMAAwDgYDVR0P +AQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMJMA8GCSsGAQUFBzABBQQCBQAw +HQYDVR0OBBYEFF/a5AMWkaBjCHg/XLYf1tnb8FA0MB8GA1UdIwQYMBaAFLCwSv0c +dSj4HGGqE/b6wZA9axajMA0GCSqGSIb3DQEBBQUAA4IBAQCKRl1iXFmOQtLseDWP +Y5icDDBGiRi17CGgvIzGJi/ha0PhbO+X0TmQIEnRX3Mu0Er/Mm4RZSjMtJ2iZRh3 +tGf4Dn+jKgKOmgXC3oOG/l8RPHLf0yaPSdn/z0TXtA30vTFBLlFeWnhbfhovea4+ +snPdBxLqWZdtxmiwojgqA7YATCWwavizrBr09YRyDwzgtpZ2BwMruGuFuV9FsEwL +PCM53yFlrM32oFghyfyE5kYjgnnueKM+pw1kA0jgb1CnVJRrMEN1TXuXDAZLtHKG +5X/drah1JtkoZhCzxzZ3bYdVDQJ90OHFqM58lwGD6z3XuPKrHDKZKt+CPIsl5g7p +4J2l diff --git a/test/ocsp-tests/D1_Cert_EE.pem b/test/ocsp-tests/D1_Cert_EE.pem new file mode 100644 index 0000000000..c5b993c0ad --- /dev/null +++ b/test/ocsp-tests/D1_Cert_EE.pem @@ -0,0 +1,38 @@ +-----BEGIN CERTIFICATE----- +MIIGujCCBaKgAwIBAgISESG8vx4IzALnkqQG05AvM+2bMA0GCSqGSIb3DQEBBQUA +MFkxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMS8wLQYD +VQQDEyZHbG9iYWxTaWduIEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EgLSBHMjAeFw0x +MjA4MTQxMjM1MDJaFw0xMzA4MTUxMDMxMjlaMIIBCjEdMBsGA1UEDwwUUHJpdmF0 +ZSBPcmdhbml6YXRpb24xDzANBgNVBAUTBjU3ODYxMTETMBEGCysGAQQBgjc8AgED +EwJVUzEeMBwGCysGAQQBgjc8AgECEw1OZXcgSGFtcHNoaXJlMQswCQYDVQQGEwJV +UzEWMBQGA1UECAwNTmV3IEhhbXBzaGlyZTETMBEGA1UEBwwKUG9ydHNtb3V0aDEg +MB4GA1UECRMXVHdvIEludGVybmF0aW9uYWwgRHJpdmUxDTALBgNVBAsMBC5DT00x +GzAZBgNVBAoMEkdNTyBHbG9iYWxTaWduIEluYzEbMBkGA1UEAwwSd3d3Lmdsb2Jh +bHNpZ24uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqx/nHBP4 +6s5KKMDlfZS4qFDiAWsoPSRn6WO4nrUF/G2S3I/AdJ0IcSDOHb48/3APj5alqbgo +o4IzdG6KLAbENpHMl0L3pHBq/5tJPTi02SbiYUHfp2fhueMauRo8spfEk6fNRnDn +QpyMFRkYd7Jz+KMerTO1xAcOH+xp0KkcP0i2jFTEuM3LwR0yTms1rry+RryjDDt5 +7W0DLnNFWhyGd6YymzNkCPeL6weV8uk2uYRKKf2XOAzgIpNo3zU6iakZOzlQB9h9 +qRuIks2AU/cZ89cBkDjHua0ezX5rG3/Url33jAT9cR5zCXHWtj7VzlOjDXXnn16b +L9/AWsvGMNkYHQIDAQABo4ICxzCCAsMwDgYDVR0PAQH/BAQDAgWgMEwGA1UdIARF +MEMwQQYJKwYBBAGgMgEBMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2Jh +bHNpZ24uY29tL3JlcG9zaXRvcnkvMIIBKwYDVR0RBIIBIjCCAR6CEnd3dy5nbG9i +YWxzaWduLmNvbYIVc3RhdHVzLm |