The branch master has been updated via 4ff993d7912516a2fd1d5c1e97a6f26a4644c1c6 (commit) via cf61b97d5fb9208ac254e999d86b1cf40c12b442 (commit) via 37326895b75297071560eb09d167f3ac90af71b4 (commit) via 7d5ea3fecbfb12cdbcfce32cc4ea00b96ee4218d (commit) from 4f5b222b84432a11c44d8c9a11c7fa98351db79b (commit)
- Log ----------------------------------------------------------------- commit 4ff993d7912516a2fd1d5c1e97a6f26a4644c1c6 Author: Dr. David von Oheimb <david.von.ohe...@siemens.com> Date: Tue Sep 22 08:36:22 2020 +0200 Implement treatment of id-pkix-ocsp-no-check extension for OCSP_basic_verify() Fixes #7761 Reviewed-by: Tomas Mraz <tm...@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/12947) commit cf61b97d5fb9208ac254e999d86b1cf40c12b442 Author: Tomas Mraz <tm...@fedoraproject.org> Date: Wed Sep 23 09:43:43 2020 +0200 Generate a certificate with critical id-pkix-ocsp-nocheck extension Reviewed-by: David von Oheimb <david.von.ohe...@siemens.com> (Merged from https://github.com/openssl/openssl/pull/12947) commit 37326895b75297071560eb09d167f3ac90af71b4 Author: Dr. David von Oheimb <david.von.ohe...@siemens.com> Date: Tue Sep 22 08:31:17 2020 +0200 OCSP_resp_find_status.pod: Slightly improve the documentation of various flags Reviewed-by: Tomas Mraz <tm...@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/12947) commit 7d5ea3fecbfb12cdbcfce32cc4ea00b96ee4218d Author: Dr. David von Oheimb <david.von.ohe...@siemens.com> Date: Tue Sep 22 08:18:31 2020 +0200 OCSP_resp_find_status.pod: Replace function arg references B<...> by I<...> Reviewed-by: Tomas Mraz <tm...@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/12947) ----------------------------------------------------------------------- Summary of changes: crypto/ocsp/ocsp_vfy.c | 19 +++-- crypto/x509/v3_purp.c | 1 + doc/man3/OCSP_resp_find_status.pod | 109 +++++++++++++++-------------- test/certs/ee-cert-crit-unknown-ext.pem | 20 ++++++ test/certs/ee-cert-noncrit-unknown-ext.pem | 20 ++++++ test/certs/ee-cert-ocsp-nocheck.pem | 20 ++++++ test/certs/mkcert.sh | 36 +++++++++- test/certs/setup.sh | 9 +++ test/recipes/25-test_verify.t | 11 ++- 9 files changed, 185 insertions(+), 60 deletions(-) create mode 100644 test/certs/ee-cert-crit-unknown-ext.pem create mode 100644 test/certs/ee-cert-noncrit-unknown-ext.pem create mode 100644 test/certs/ee-cert-ocsp-nocheck.pem diff --git a/crypto/ocsp/ocsp_vfy.c b/crypto/ocsp/ocsp_vfy.c index 92512829c9..0cd59f9221 100644 --- a/crypto/ocsp/ocsp_vfy.c +++ b/crypto/ocsp/ocsp_vfy.c @@ -26,7 +26,8 @@ static int ocsp_req_find_signer(X509 **psigner, OCSP_REQUEST *req, unsigned long flags); /* Returns 1 on success, 0 on failure, or -1 on fatal error */ -static int ocsp_verify_signer(X509 *signer, X509_STORE *st, unsigned long flags, +static int ocsp_verify_signer(X509 *signer, int response, + X509_STORE *st, unsigned long flags, STACK_OF(X509) *untrusted, STACK_OF(X509) **chain) { X509_STORE_CTX *ctx = X509_STORE_CTX_new(); @@ -41,9 +42,17 @@ static int ocsp_verify_signer(X509 *signer, X509_STORE *st, unsigned long flags, OCSPerr(0, ERR_R_X509_LIB); goto end; } - if ((flags & OCSP_PARTIAL_CHAIN) != 0 - && (vp = X509_STORE_CTX_get0_param(ctx)) != NULL) + if ((vp = X509_STORE_CTX_get0_param(ctx)) == NULL) + goto end; + if ((flags & OCSP_PARTIAL_CHAIN) != 0) X509_VERIFY_PARAM_set_flags(vp, X509_V_FLAG_PARTIAL_CHAIN); + if (response + && X509_get_ext_by_NID(signer, NID_id_pkix_OCSP_noCheck, -1) >= 0) + /* + * Locally disable revocation status checking for OCSP responder cert. + * Done here for CRLs; TODO should be done also for OCSP-based checks. + */ + X509_VERIFY_PARAM_clear_flags(vp, X509_V_FLAG_CRL_CHECK); X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER); X509_STORE_CTX_set_trust(ctx, X509_TRUST_OCSP_REQUEST); /* TODO: why is X509_TRUST_OCSP_REQUEST set? Seems to get ignored. */ @@ -117,7 +126,7 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, } else { untrusted = bs->certs; } - ret = ocsp_verify_signer(signer, st, flags, untrusted, &chain); + ret = ocsp_verify_signer(signer, 1, st, flags, untrusted, &chain); if (ret <= 0) goto end; if ((flags & OCSP_NOCHECKS) != 0) { @@ -390,7 +399,7 @@ int OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs, return 0; /* not returning 'ret' here for backward compatibility*/ if ((flags & OCSP_NOVERIFY) != 0) return 1; - return ocsp_verify_signer(signer, store, flags, + return ocsp_verify_signer(signer, 0, store, flags, (flags & OCSP_NOCHAIN) != 0 ? NULL : req->optionalSignature->certs, NULL) > 0; /* using '> 0' here to avoid breaking backward compatibility returning -1 */ diff --git a/crypto/x509/v3_purp.c b/crypto/x509/v3_purp.c index 8b0dfd9759..fd512419f0 100644 --- a/crypto/x509/v3_purp.c +++ b/crypto/x509/v3_purp.c @@ -283,6 +283,7 @@ int X509_supported_extension(X509_EXTENSION *ex) NID_sbgp_ipAddrBlock, /* 290 */ NID_sbgp_autonomousSysNum, /* 291 */ #endif + NID_id_pkix_OCSP_noCheck, /* 369 */ NID_policy_constraints, /* 401 */ NID_proxyCertInfo, /* 663 */ NID_name_constraints, /* 666 */ diff --git a/doc/man3/OCSP_resp_find_status.pod b/doc/man3/OCSP_resp_find_status.pod index 7dd90837b6..7c16b8c889 100644 --- a/doc/man3/OCSP_resp_find_status.pod +++ b/doc/man3/OCSP_resp_find_status.pod @@ -60,12 +60,12 @@ OCSP_basic_verify =head1 DESCRIPTION -OCSP_resp_find_status() searches B<bs> for an OCSP response for B<id>. If it is -successful the fields of the response are returned in B<*status>, B<*reason>, -B<*revtime>, B<*thisupd> and B<*nextupd>. The B<*status> value will be one of +OCSP_resp_find_status() searches I<bs> for an OCSP response for I<id>. If it is +successful the fields of the response are returned in I<*status>, I<*reason>, +I<*revtime>, I<*thisupd> and I<*nextupd>. The I<*status> value will be one of B<V_OCSP_CERTSTATUS_GOOD>, B<V_OCSP_CERTSTATUS_REVOKED> or -B<V_OCSP_CERTSTATUS_UNKNOWN>. The B<*reason> and B<*revtime> fields are only -set if the status is B<V_OCSP_CERTSTATUS_REVOKED>. If set the B<*reason> field +B<V_OCSP_CERTSTATUS_UNKNOWN>. The I<*reason> and I<*revtime> fields are only +set if the status is B<V_OCSP_CERTSTATUS_REVOKED>. If set the I<*reason> field will be set to the revocation reason which will be one of B<OCSP_REVOKED_STATUS_NOSTATUS>, B<OCSP_REVOKED_STATUS_UNSPECIFIED>, B<OCSP_REVOKED_STATUS_KEYCOMPROMISE>, B<OCSP_REVOKED_STATUS_CACOMPROMISE>, @@ -73,88 +73,91 @@ B<OCSP_REVOKED_STATUS_AFFILIATIONCHANGED>, B<OCSP_REVOKED_STATUS_SUPERSEDED>, B<OCSP_REVOKED_STATUS_CESSATIONOFOPERATION>, B<OCSP_REVOKED_STATUS_CERTIFICATEHOLD> or B<OCSP_REVOKED_STATUS_REMOVEFROMCRL>. -OCSP_resp_count() returns the number of B<OCSP_SINGLERESP> structures in B<bs>. +OCSP_resp_count() returns the number of B<OCSP_SINGLERESP> structures in I<bs>. -OCSP_resp_get0() returns the B<OCSP_SINGLERESP> structure in B<bs> -corresponding to index B<idx>. Where B<idx> runs from 0 to +OCSP_resp_get0() returns the B<OCSP_SINGLERESP> structure in I<bs> +corresponding to index I<idx>. Where I<idx> runs from 0 to OCSP_resp_count(bs) - 1. -OCSP_resp_find() searches B<bs> for B<id> and returns the index of the first -matching entry after B<last> or starting from the beginning if B<last> is -1. +OCSP_resp_find() searches I<bs> for I<id> and returns the index of the first +matching entry after I<last> or starting from the beginning if I<last> is -1. -OCSP_single_get0_status() extracts the fields of B<single> in B<*reason>, -B<*revtime>, B<*thisupd> and B<*nextupd>. +OCSP_single_get0_status() extracts the fields of I<single> in I<*reason>, +I<*revtime>, I<*thisupd> and I<*nextupd>. OCSP_resp_get0_produced_at() extracts the B<producedAt> field from the -single response B<bs>. +single response I<bs>. -OCSP_resp_get0_signature() returns the signature from B<bs>. +OCSP_resp_get0_signature() returns the signature from I<bs>. -OCSP_resp_get0_tbs_sigalg() returns the B<signatureAlgorithm> from B<bs>. +OCSP_resp_get0_tbs_sigalg() returns the B<signatureAlgorithm> from I<bs>. -OCSP_resp_get0_respdata() returns the B<tbsResponseData> from B<bs>. +OCSP_resp_get0_respdata() returns the B<tbsResponseData> from I<bs>. -OCSP_resp_get0_certs() returns any certificates included in B<bs>. +OCSP_resp_get0_certs() returns any certificates included in I<bs>. OCSP_resp_get0_signer() attempts to retrieve the certificate that directly -signed B<bs>. The OCSP protocol does not require that this certificate +signed I<bs>. The OCSP protocol does not require that this certificate is included in the B<certs> field of the response, so additional certificates -can be supplied in B<extra_certs> if the certificates that may have +can be supplied via the I<extra_certs> if the certificates that may have signed the response are known via some out-of-band mechanism. -OCSP_resp_get0_id() gets the responder id of B<bs>. If the responder ID is -a name then <*pname> is set to the name and B<*pid> is set to NULL. If the -responder ID is by key ID then B<*pid> is set to the key ID and B<*pname> -is set to NULL. OCSP_resp_get1_id() leaves ownership of B<*pid> and B<*pname> +OCSP_resp_get0_id() gets the responder id of I<bs>. If the responder ID is +a name then <*pname> is set to the name and I<*pid> is set to NULL. If the +responder ID is by key ID then I<*pid> is set to the key ID and I<*pname> +is set to NULL. OCSP_resp_get1_id() leaves ownership of I<*pid> and I<*pname> with the caller, who is responsible for freeing them. Both functions return 1 in case of success and 0 in case of failure. If OCSP_resp_get1_id() returns 0, no freeing of the results is necessary. -OCSP_check_validity() checks the validity of B<thisupd> and B<nextupd> values -which will be typically obtained from OCSP_resp_find_status() or -OCSP_single_get0_status(). If B<sec> is nonzero it indicates how many seconds -leeway should be allowed in the check. If B<maxsec> is positive it indicates -the maximum age of B<thisupd> in seconds. +OCSP_check_validity() checks the validity of its I<thisupd> and I<nextupd> +arguments, which will be typically obtained from OCSP_resp_find_status() or +OCSP_single_get0_status(). If I<sec> is nonzero it indicates how many seconds +leeway should be allowed in the check. If I<maxsec> is positive it indicates +the maximum age of I<thisupd> in seconds. -OCSP_basic_verify() checks that the basic response message B<bs> is correctly -signed and that the signer certificate can be validated. It takes B<st> as -the trusted store and B<certs> as a set of untrusted intermediate certificates. +OCSP_basic_verify() checks that the basic response message I<bs> is correctly +signed and that the signer certificate can be validated. It takes I<st> as +the trusted store and I<certs> as a set of untrusted intermediate certificates. The function first tries to find the signer certificate of the response -in B<certs>. It also searches the certificates the responder may have included -in B<bs> unless the B<flags> contain B<OCSP_NOINTERN>. +in I<certs>. It then searches the certificates the responder may have included +in I<bs> unless I<flags> contains B<OCSP_NOINTERN>. It fails if the signer certificate cannot be found. -Next, the function checks the signature of B<bs> and fails on error -unless the B<flags> contain B<OCSP_NOSIGS>. Then the function already returns -success if the B<flags> contain B<OCSP_NOVERIFY> or if the signer certificate -was found in B<certs> and the B<flags> contain B<OCSP_TRUSTOTHER>. +Next, unless I<flags> contains B<OCSP_NOSIGS>, the function checks +the signature of I<bs> and fails on error. Then the function already returns +success if I<flags> contains B<OCSP_NOVERIFY> or if the signer certificate +was found in I<certs> and I<flags> contains B<OCSP_TRUSTOTHER>. Otherwise the function continues by validating the signer certificate. -If B<flags> contains B<OCSP_PARTIAL_CHAIN>, intermediate CA certificates -in B<st> are trust-anchors. +If I<flags> contains B<OCSP_PARTIAL_CHAIN> it takes intermediate CA +certificates in I<st> as trust anchors. For more details, see the description of B<X509_V_FLAG_PARTIAL_CHAIN> in L<X509_VERIFY_PARAM_set_flags(3)/VERIFICATION FLAGS>. -To this end, all certificates in B<cert> and in B<bs> are considered as -untrusted certificates for the construction of the validation path for the -signer certificate unless the B<OCSP_NOCHAIN> flag is set. After successful path +If I<flags> contains B<OCSP_NOCHAIN> it ignores all certificates in I<certs> +and in I<bs>, else it takes them as untrusted intermediate CA certificates +and uses them for constructing the validation path for the signer certificate. +Certicate revocation status checks using CRLs is disabled during path validation +if the signer certificate contains the B<id-pkix-ocsp-no-check> extension. +After successful path validation the function returns success if the B<OCSP_NOCHECKS> flag is set. Otherwise it verifies that the signer certificate meets the OCSP issuer criteria including potential delegation. If this does not succeed and the -B<flags> do not contain B<OCSP_NOEXPLICIT> the function checks for explicit +B<OCSP_NOEXPLICIT> flag is not set the function checks for explicit trust for OCSP signing in the root CA certificate. =head1 RETURN VALUES -OCSP_resp_find_status() returns 1 if B<id> is found in B<bs> and 0 otherwise. +OCSP_resp_find_status() returns 1 if I<id> is found in I<bs> and 0 otherwise. OCSP_resp_count() returns the total number of B<OCSP_SINGLERESP> fields in -B<bs>. +I<bs>. OCSP_resp_get0() returns a pointer to an B<OCSP_SINGLERESP> structure or -B<NULL> if B<idx> is out of range. +NULL if I<idx> is out of range. -OCSP_resp_find() returns the index of B<id> in B<bs> (which may be 0) or -1 if -B<id> was not found. +OCSP_resp_find() returns the index of I<id> in I<bs> (which may be 0) or -1 if +I<id> was not found. -OCSP_single_get0_status() returns the status of B<single> or -1 if an error +OCSP_single_get0_status() returns the status of I<single> or -1 if an error occurred. OCSP_resp_get0_signer() returns 1 if the signing certificate was located, @@ -171,15 +174,15 @@ can then take appropriate action based on the status of the certificate. An OCSP response for a certificate contains B<thisUpdate> and B<nextUpdate> fields. Normally the current time should be between these two values. To -account for clock skew the B<maxsec> field can be set to nonzero in +account for clock skew the I<maxsec> field can be set to nonzero in OCSP_check_validity(). Some responders do not set the B<nextUpdate> field, this would otherwise mean an ancient response would be considered valid: the -B<maxsec> parameter to OCSP_check_validity() can be used to limit the permitted +I<maxsec> parameter to OCSP_check_validity() can be used to limit the permitted age of responses. -The values written to B<*revtime>, B<*thisupd> and B<*nextupd> by +The values written to I<*revtime>, I<*thisupd> and I<*nextupd> by OCSP_resp_find_status() and OCSP_single_get0_status() are internal pointers -which B<MUST NOT> be freed up by the calling application. Any or all of these +which MUST NOT be freed up by the calling application. Any or all of these parameters can be set to NULL if their value is not required. =head1 SEE ALSO diff --git a/test/certs/ee-cert-crit-unknown-ext.pem b/test/certs/ee-cert-crit-unknown-ext.pem new file mode 100644 index 0000000000..34f69357c1 --- /dev/null +++ b/test/certs/ee-cert-crit-unknown-ext.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgIBAjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJDQTAg +Fw0yMDA5MjMxMDM5MTNaGA8yMTIwMDkyNDEwMzkxM1owGTEXMBUGA1UEAwwOc2Vy +dmVyLmV4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo/4lY +YYWu3tssD9Vz++K3qBt6dWAr1H08c3a1rt6TL38kkG3JHPSKOM2fooAWVsu0LLuT +5Rcf/w3GQ/4xNPgo2HXpo7uIgu+jcuJTYgVFTeAxl++qnRDSWA2eBp4yuxsIVl1l +Dz9mjsI2oBH/wFk1/Ukc3RxCMwZ4rgQ4I+XndWfTlK1aqUAfrFkQ9QzBZK1KxMY1 +U7OWaoIbFYvRmavknm+UqtKW5Vf7jJFkijwkFsbSGb6CYBM7YrDtPh2zyvlr3zG5 +ep5LR2inKcc/SuIiJ7TvkGPX79ByST5brbkb1Ctvhmjd1XMSuEPJ3EEPoqNGT4tn +iIQPYf55NB9KiR+3AgMBAAGjgYwwgYkwHQYDVR0OBBYEFOeb4iqtimw6y3ZR5Y4H +mCKX4XOiMB8GA1UdIwQYMBaAFLQRM/HX4l73U54gIhBPhga/H8leMAkGA1UdEwQC +MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGQYDVR0RBBIwEIIOc2VydmVyLmV4YW1w +bGUwDAYDKgMEAQH/BAIFADANBgkqhkiG9w0BAQsFAAOCAQEAOjBX/mPKtROMdd3S +jGMxScTndXy+OMCTGmRMpFGrR8yQAgUDhcPytxN7FU+5Uo1qaV6+9xH9Q80mtJ6i +Db5qHdxAw/1CTDKMzVUU3eVq1AMPbERSC/JYSeQct+rQ0N4QfOjEpTXnVMbeaL+Q +yCsetPK2I8o8e63wuCYgWWIFQtszunGnKdbF60n9MI8uAryaCCDUptOdXIiHBDIW +1ZLnhAAr9RvwK5+ph4pBefHMC9P/tZ/eB14kszaAPBhv8cJKEvM6dgboEbU1KMoz +VY7rT7+7rTE6/2AoL6c5z+RE0oC/UE/i1vgEjO9GwBuL9QVhmkt7ejJR0+oM9EqA +0l7sxw== +-----END CERTIFICATE----- diff --git a/test/certs/ee-cert-noncrit-unknown-ext.pem b/test/certs/ee-cert-noncrit-unknown-ext.pem new file mode 100644 index 0000000000..8c4695a5d8 --- /dev/null +++ b/test/certs/ee-cert-noncrit-unknown-ext.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDLTCCAhWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJDQTAg +Fw0yMDA5MjMxMDM5NTJaGA8yMTIwMDkyNDEwMzk1MlowGTEXMBUGA1UEAwwOc2Vy +dmVyLmV4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo/4lY +YYWu3tssD9Vz++K3qBt6dWAr1H08c3a1rt6TL38kkG3JHPSKOM2fooAWVsu0LLuT +5Rcf/w3GQ/4xNPgo2HXpo7uIgu+jcuJTYgVFTeAxl++qnRDSWA2eBp4yuxsIVl1l +Dz9mjsI2oBH/wFk1/Ukc3RxCMwZ4rgQ4I+XndWfTlK1aqUAfrFkQ9QzBZK1KxMY1 +U7OWaoIbFYvRmavknm+UqtKW5Vf7jJFkijwkFsbSGb6CYBM7YrDtPh2zyvlr3zG5 +ep5LR2inKcc/SuIiJ7TvkGPX79ByST5brbkb1Ctvhmjd1XMSuEPJ3EEPoqNGT4tn +iIQPYf55NB9KiR+3AgMBAAGjgYkwgYYwHQYDVR0OBBYEFOeb4iqtimw6y3ZR5Y4H +mCKX4XOiMB8GA1UdIwQYMBaAFLQRM/HX4l73U54gIhBPhga/H8leMAkGA1UdEwQC +MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGQYDVR0RBBIwEIIOc2VydmVyLmV4YW1w +bGUwCQYDKgMEBAIFADANBgkqhkiG9w0BAQsFAAOCAQEAGPgQHSiAqGMAur2KW4BS +opArthSh7ZT1wVEX0lP5lI/BUv/Q1YYnKEWuR9o+8vP1w4gUhFzg9Zrwj3rCNoC5 +x2JipZt8kRo5ycXv4tzr6V4n1zSgGByjradc0VEfuqmw1WpxvLoHeV9hbiXFQf8/ +PiLVF5BZ0ZSJjTDqMWfqYGSZnWqLglAqhZtHXkdaGIS+MJ2MhwPaUgLNATzptJ4a +fjUF9apbCLtz0UzvojF/Wmby/fzbnPbKDyV6P8IzsfLgrH9NXN/9OBG5evVZo4PR +32eZwgjdftu64b2QwoZi0dInHOwJO30UfgkeypYTjnQLSXhrz56EPu9sWCNGXs61 +LA== +-----END CERTIFICATE----- diff --git a/test/certs/ee-cert-ocsp-nocheck.pem b/test/certs/ee-cert-ocsp-nocheck.pem new file mode 100644 index 0000000000..d70ffa7553 --- /dev/null +++ b/test/certs/ee-cert-ocsp-nocheck.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNjCCAh6gAwIBAgIBAjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJDQTAg +Fw0yMDA5MjMxMDM4NDlaGA8yMTIwMDkyNDEwMzg0OVowGTEXMBUGA1UEAwwOc2Vy +dmVyLmV4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo/4lY +YYWu3tssD9Vz++K3qBt6dWAr1H08c3a1rt6TL38kkG3JHPSKOM2fooAWVsu0LLuT +5Rcf/w3GQ/4xNPgo2HXpo7uIgu+jcuJTYgVFTeAxl++qnRDSWA2eBp4yuxsIVl1l +Dz9mjsI2oBH/wFk1/Ukc3RxCMwZ4rgQ4I+XndWfTlK1aqUAfrFkQ9QzBZK1KxMY1 +U7OWaoIbFYvRmavknm+UqtKW5Vf7jJFkijwkFsbSGb6CYBM7YrDtPh2zyvlr3zG5 +ep5LR2inKcc/SuIiJ7TvkGPX79ByST5brbkb1Ctvhmjd1XMSuEPJ3EEPoqNGT4tn +iIQPYf55NB9KiR+3AgMBAAGjgZIwgY8wHQYDVR0OBBYEFOeb4iqtimw6y3ZR5Y4H +mCKX4XOiMB8GA1UdIwQYMBaAFLQRM/HX4l73U54gIhBPhga/H8leMAkGA1UdEwQC +MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGQYDVR0RBBIwEIIOc2VydmVyLmV4YW1w +bGUwEgYJKwYBBQUHMAEFAQH/BAIFADANBgkqhkiG9w0BAQsFAAOCAQEADK7EvoaQ +Q/hwA48Vt+umuaquwUTn7IP5eWD6TivgTxnx5Qj1vqCC4AqZF4L8fV4RW2kXhbW+ +gwJIWr0w2EzzZnaObJK/zWyXdb+fpyLsl65BAABDjm2GVZEuX7Zvm+4cJ9mUozWz +/r1d4x9s2bmuo+6S3HH+ceXhyYPHnMc9gkzLubMZp7yO9FaDNmC9UoSnv1W0Ijkf +D+jV4ErjON9eCuFTt7xxa9xVNCnB1shXLvoyiGd9yCyO4cScpxNPl3/VY9kx5W2G +OeRYsJw4DZOY6hRkJq2ftDiOsDWiAXBkWuItf0hynOkSyBh1bcW+h94iBZ9uB1X+ +LRAbn7Qf3ITyCw== +-----END CERTIFICATE----- diff --git a/test/certs/mkcert.sh b/test/certs/mkcert.sh index 32fd5874d9..a564e30c6b 100755 --- a/test/certs/mkcert.sh +++ b/test/certs/mkcert.sh @@ -233,6 +233,40 @@ genee() { -set_serial 2 -days "${DAYS}" "$@" } +geneeextra() { + local OPTIND=1 + local purpose=serverAuth + + while getopts p: o + do + case $o in + p) purpose="$OPTARG";; + *) echo "Usage: $0 geneeextra [-p EKU] cn keyname certname cakeyname cacertname extraext" >&2 + return 1;; + esac + done + + shift $((OPTIND - 1)) + local cn=$1; shift + local key=$1; shift + local cert=$1; shift + local cakey=$1; shift + local ca=$1; shift + local extraext=$1; shift + + exts=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \ + "subjectKeyIdentifier = hash" \ + "authorityKeyIdentifier = keyid, issuer" \ + "basicConstraints = CA:false" \ + "extendedKeyUsage = $purpose" \ + "subjectAltName = @alts"\ + "$extraext" "DNS=${cn}") + csr=$(req "$key" "CN = $cn") || return 1 + echo "$csr" | + cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ + -set_serial 2 -days "${DAYS}" "$@" +} + geneenocsr() { local OPTIND=1 local purpose=serverAuth @@ -241,7 +275,7 @@ geneenocsr() { do case $o in p) purpose="$OPTARG";; - *) echo "Usage: $0 genee [-p EKU] cn certname cakeyname cacertname" >&2 + *) echo "Usage: $0 geneenocsr [-p EKU] cn certname cakeyname cacertname" >&2 return 1;; esac done diff --git a/test/certs/setup.sh b/test/certs/setup.sh index ee3d678219..eb7f77e231 100755 --- a/test/certs/setup.sh +++ b/test/certs/setup.sh @@ -400,3 +400,12 @@ OPENSSL_SIGALG=ED448 OPENSSL_KEYALG=ed448 ./mkcert.sh genroot "Root Ed448" \ root-ed448-key root-ed448-cert OPENSSL_SIGALG=ED448 OPENSSL_KEYALG=ed448 ./mkcert.sh genee ed448 \ server-ed448-key server-ed448-cert root-ed448-key root-ed448-cert + +# non-critical unknown extension +./mkcert.sh geneeextra server.example ee-key ee-cert-noncrit-unknown-ext ca-key ca-cert "1.2.3.4=DER:05:00" + +# critical unknown extension +./mkcert.sh geneeextra server.example ee-key ee-cert-crit-unknown-ext ca-key ca-cert "1.2.3.4=critical,DER:05:00" + +# critical id-pkix-ocsp-no-check extension +./mkcert.sh geneeextra server.example ee-key ee-cert-ocsp-nocheck ca-key ca-cert "1.3.6.1.5.5.7.48.1.5=critical,DER:05:00" diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t index 6d8f78c978..9bbabd0fa3 100644 --- a/test/recipes/25-test_verify.t +++ b/test/recipes/25-test_verify.t @@ -27,7 +27,7 @@ sub verify { run(app([@args])); } -plan tests => 148; +plan tests => 151; # Canonical success ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]), @@ -45,6 +45,15 @@ ok(!verify("ee-cert", "sslserver", [qw(root-cert2)], [qw(ca-cert)]), ok(!verify("ee-cert", "sslserver", [qw(root-name2)], [qw(ca-cert)]), "fail wrong root DN"); +# Critical extensions + +ok(verify("ee-cert-noncrit-unknown-ext", "sslserver", [qw(root-cert)], [qw(ca-cert)]), + "accept non-critical unknown extension"); +ok(!verify("ee-cert-crit-unknown-ext", "sslserver", [qw(root-cert)], [qw(ca-cert)]), + "reject critical unknown extension"); +ok(verify("ee-cert-ocsp-nocheck", "sslserver", [qw(root-cert)], [qw(ca-cert)]), + "accept critical OCSP No Check"); + # Explicit trust/purpose combinations # ok(verify("ee-cert", "sslserver", [qw(sroot-cert)], [qw(ca-cert)]),