diff --git a/CHANGES b/CHANGES index becaab49f8b4f675de2cdd140edd47dc93ce6132..6a2480b24cbfe2d34bb644e52c4513542d901c38 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,12 @@ Changes between 0.9.6 and 0.9.7 [xx XXX 2000] + *) Function OCSP_request_verify(). This checks the signature on an + OCSP request and verifies the signer certificate. The signer + certificate is just checked for a generic purpose and OCSP request + trust settings. + [Steve Henson] + *) Add OCSP_check_validity() function to check the validity of OCSP responses. OCSP responses are prepared in real time and may only be a few seconds old. Simply checking that the current time lies diff --git a/crypto/ocsp/ocsp.h b/crypto/ocsp/ocsp.h index bccdf77b4f2373b0418392d0659d465dedb2fa26..02b0a72ae619ccb16ff8711a28e3413dc509986f 100644 --- a/crypto/ocsp/ocsp.h +++ b/crypto/ocsp/ocsp.h @@ -448,7 +448,7 @@ int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long sec, long maxsec); -int OCSP_request_verify(OCSP_REQUEST *req, EVP_PKEY *pkey); +int OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs, X509_STORE *store, unsigned long flags); int OCSP_parse_url(char *url, char **phost, char **pport, char **ppath, int *pssl); @@ -461,6 +461,7 @@ OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *one); int OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd, ASN1_OCTET_STRING **pikeyHash, ASN1_INTEGER **pserial, OCSP_CERTID *cid); +int OCSP_request_is_signed(OCSP_REQUEST *req); OCSP_RESPONSE *OCSP_response_create(int status, OCSP_BASICRESP *bs); OCSP_SINGLERESP *OCSP_basic_add1_status(OCSP_BASICRESP *rsp, OCSP_CERTID *cid, @@ -576,6 +577,7 @@ void ERR_load_OCSP_strings(void); #define OCSP_F_OCSP_MATCH_ISSUERID 109 #define OCSP_F_OCSP_PARSE_URL 114 #define OCSP_F_OCSP_REQUEST_SIGN 110 +#define OCSP_F_OCSP_REQUEST_VERIFY 116 #define OCSP_F_OCSP_RESPONSE_GET1_BASIC 111 #define OCSP_F_OCSP_SENDREQ_BIO 112 #define OCSP_F_REQUEST_VERIFY 113 @@ -596,6 +598,7 @@ void ERR_load_OCSP_strings(void); #define OCSP_R_NO_RESPONSE_DATA 108 #define OCSP_R_NO_REVOKED_TIME 109 #define OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 110 +#define OCSP_R_REQUEST_NOT_SIGNED 128 #define OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA 111 #define OCSP_R_ROOT_CA_NOT_TRUSTED 112 #define OCSP_R_SERVER_READ_ERROR 113 @@ -609,6 +612,7 @@ void ERR_load_OCSP_strings(void); #define OCSP_R_STATUS_TOO_OLD 127 #define OCSP_R_UNKNOWN_MESSAGE_DIGEST 119 #define OCSP_R_UNKNOWN_NID 120 +#define OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE 129 #ifdef __cplusplus } diff --git a/crypto/ocsp/ocsp_err.c b/crypto/ocsp/ocsp_err.c index 1cbf9cab306c08ad116febb760e5b099cbb25391..4c4d8306f8abe66d314b32f871033425cf538a67 100644 --- a/crypto/ocsp/ocsp_err.c +++ b/crypto/ocsp/ocsp_err.c @@ -79,6 +79,7 @@ static ERR_STRING_DATA OCSP_str_functs[]= {ERR_PACK(0,OCSP_F_OCSP_MATCH_ISSUERID,0), "OCSP_MATCH_ISSUERID"}, {ERR_PACK(0,OCSP_F_OCSP_PARSE_URL,0), "OCSP_parse_url"}, {ERR_PACK(0,OCSP_F_OCSP_REQUEST_SIGN,0), "OCSP_request_sign"}, +{ERR_PACK(0,OCSP_F_OCSP_REQUEST_VERIFY,0), "OCSP_request_verify"}, {ERR_PACK(0,OCSP_F_OCSP_RESPONSE_GET1_BASIC,0), "OCSP_response_get1_basic"}, {ERR_PACK(0,OCSP_F_OCSP_SENDREQ_BIO,0), "OCSP_sendreq_bio"}, {ERR_PACK(0,OCSP_F_REQUEST_VERIFY,0), "REQUEST_VERIFY"}, @@ -102,6 +103,7 @@ static ERR_STRING_DATA OCSP_str_reasons[]= {OCSP_R_NO_RESPONSE_DATA ,"no response data"}, {OCSP_R_NO_REVOKED_TIME ,"no revoked time"}, {OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE,"private key does not match certificate"}, +{OCSP_R_REQUEST_NOT_SIGNED ,"request not signed"}, {OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA,"response contains no revocation data"}, {OCSP_R_ROOT_CA_NOT_TRUSTED ,"root ca not trusted"}, {OCSP_R_SERVER_READ_ERROR ,"server read error"}, @@ -115,6 +117,7 @@ static ERR_STRING_DATA OCSP_str_reasons[]= {OCSP_R_STATUS_TOO_OLD ,"status too old"}, {OCSP_R_UNKNOWN_MESSAGE_DIGEST ,"unknown message digest"}, {OCSP_R_UNKNOWN_NID ,"unknown nid"}, +{OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE ,"unsupported requestorname type"}, {0,NULL} }; diff --git a/crypto/ocsp/ocsp_lib.c b/crypto/ocsp/ocsp_lib.c index 0ddf1b290639d2e957305acadcf0526872391f83..1ff8f4f423ecc390a6a20931984c66b76d6d18cf 100644 --- a/crypto/ocsp/ocsp_lib.c +++ b/crypto/ocsp/ocsp_lib.c @@ -158,24 +158,6 @@ int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b) return ASN1_INTEGER_cmp(a->serialNumber, b->serialNumber); } -/* XXX assumes certs in signature are sorted root to leaf XXX */ -int OCSP_request_verify(OCSP_REQUEST *req, EVP_PKEY *pkey) - { - STACK_OF(X509) *sk; - - if (!req->optionalSignature) return 0; - if (pkey == NULL) - { - if (!(sk = req->optionalSignature->certs)) return 0; - if (!(pkey=X509_get_pubkey(sk_X509_value(sk, sk_X509_num(sk)-1)))) - { - OCSPerr(OCSP_F_REQUEST_VERIFY,OCSP_R_NO_PUBLIC_KEY); - return 0; - } - } - return OCSP_REQUEST_verify(req, pkey); - } - /* Parse a URL and split it up into host, port and path components and whether * it is SSL. diff --git a/crypto/ocsp/ocsp_srv.c b/crypto/ocsp/ocsp_srv.c index 3ecbfc8d1ebdd5ba82ff6fa3931ac6bfa31df9a0..fffa134e7541aae8c1ab1043710fb4c624825181 100644 --- a/crypto/ocsp/ocsp_srv.c +++ b/crypto/ocsp/ocsp_srv.c @@ -96,6 +96,12 @@ int OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd, return 1; } +int OCSP_request_is_signed(OCSP_REQUEST *req) + { + if(req->optionalSignature) return 1; + return 0; + } + /* Create an OCSP response and encode an optional basic response */ OCSP_RESPONSE *OCSP_response_create(int status, OCSP_BASICRESP *bs) { diff --git a/crypto/ocsp/ocsp_vfy.c b/crypto/ocsp/ocsp_vfy.c index c4f513a3b61a6b3756477a5b2d63a6f73102bd0a..da4c5b20a5b87c1bd9a5c8d328ecc24e707cb5ce 100644 --- a/crypto/ocsp/ocsp_vfy.c +++ b/crypto/ocsp/ocsp_vfy.c @@ -67,6 +67,8 @@ static int ocsp_check_issuer(OCSP_BASICRESP *bs, STACK_OF(X509) *chain, unsigned static int ocsp_check_ids(STACK_OF(OCSP_SINGLERESP) *sresp, OCSP_CERTID **ret); static int ocsp_match_issuerid(X509 *cert, OCSP_CERTID *cid, STACK_OF(OCSP_SINGLERESP) *sresp); static int ocsp_check_delegated(X509 *x, int flags); +static int ocsp_req_find_signer(X509 **psigner, OCSP_REQUEST *req, X509_NAME *nm, STACK_OF(X509) *certs, + X509_STORE *st, unsigned long flags); /* Verify a basic response message */ @@ -340,3 +342,90 @@ static int ocsp_check_delegated(X509 *x, int flags) OCSPerr(OCSP_F_OCSP_CHECK_DELEGATED, OCSP_R_MISSING_OCSPSIGNING_USAGE); return 0; } + +/* Verify an OCSP request. This is fortunately much easier than OCSP + * request verify. Just find the signers certificate and verify it + * against a given trust value. + */ + +int OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs, X509_STORE *store, unsigned long flags) + { + X509 *signer; + X509_NAME *nm; + GENERAL_NAME *gen; + int ret; + X509_STORE_CTX ctx; + if (!req->optionalSignature) + { + OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, OCSP_R_REQUEST_NOT_SIGNED); + return 0; + } + gen = req->tbsRequest->requestorName; + if (gen->type != GEN_DIRNAME) + { + OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE); + return 0; + } + nm = gen->d.directoryName; + ret = ocsp_req_find_signer(&signer, req, nm, certs, store, flags); + if (ret <= 0) + { + OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND); + return 0; + } + if ((ret == 2) && (flags & OCSP_TRUSTOTHER)) + flags |= OCSP_NOVERIFY; + if (!(flags & OCSP_NOSIGS)) + { + EVP_PKEY *skey; + skey = X509_get_pubkey(signer); + ret = OCSP_REQUEST_verify(req, skey); + EVP_PKEY_free(skey); + if(ret <= 0) + { + OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, OCSP_R_SIGNATURE_FAILURE); + return 0; + } + } + if (!(flags & OCSP_NOVERIFY)) + { + if(flags & OCSP_NOCHAIN) + X509_STORE_CTX_init(&ctx, store, signer, NULL); + else + X509_STORE_CTX_init(&ctx, store, signer, req->optionalSignature->certs); + + X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER); + X509_STORE_CTX_set_trust(&ctx, X509_TRUST_OCSP_REQUEST); + ret = X509_verify_cert(&ctx); + X509_STORE_CTX_cleanup(&ctx); + if (ret <= 0) + { + ret = X509_STORE_CTX_get_error(&ctx); + OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY,OCSP_R_CERTIFICATE_VERIFY_ERROR); + ERR_add_error_data(2, "Verify error:", + X509_verify_cert_error_string(ret)); + return 0; + } + } + return 1; + } + +static int ocsp_req_find_signer(X509 **psigner, OCSP_REQUEST *req, X509_NAME *nm, STACK_OF(X509) *certs, + X509_STORE *st, unsigned long flags) + { + X509 *signer; + if(!(flags & OCSP_NOINTERN)) + { + signer = X509_find_by_subject(req->optionalSignature->certs, nm); + *psigner = signer; + return 1; + } + + signer = X509_find_by_subject(certs, nm); + if (signer) + { + *psigner = signer; + return 2; + } + return 0; + } diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h index 66ce26812d7f7e3e7f6313c16fdb7345471445a9..1aeea2003d49fe656fd556e7a9cb97c99d7752d2 100644 --- a/crypto/x509/x509.h +++ b/crypto/x509/x509.h @@ -301,10 +301,11 @@ DECLARE_STACK_OF(X509_TRUST) #define X509_TRUST_EMAIL 4 #define X509_TRUST_OBJECT_SIGN 5 #define X509_TRUST_OCSP_SIGN 6 +#define X509_TRUST_OCSP_REQUEST 7 /* Keep these up to date! */ #define X509_TRUST_MIN 1 -#define X509_TRUST_MAX 6 +#define X509_TRUST_MAX 7 /* trust_flags values */ diff --git a/crypto/x509/x509_trs.c b/crypto/x509/x509_trs.c index 7a41bc2d825fa9f5c1bc50f9cd5edbeb16e941a5..4f48b55160ff7076f6cd6d7d4cc3a96a84860926 100644 --- a/crypto/x509/x509_trs.c +++ b/crypto/x509/x509_trs.c @@ -82,7 +82,8 @@ static X509_TRUST trstandard[] = { {X509_TRUST_SSL_CLIENT, 0, trust_1oidany, "SSL Client", NID_client_auth, NULL}, {X509_TRUST_SSL_SERVER, 0, trust_1oidany, "SSL Client", NID_server_auth, NULL}, {X509_TRUST_EMAIL, 0, trust_1oidany, "S/MIME email", NID_email_protect, NULL}, -{X509_TRUST_OCSP_SIGN, 0, trust_1oid, "OCSP responder", NID_OCSP_sign, NULL} +{X509_TRUST_OCSP_SIGN, 0, trust_1oid, "OCSP responder", NID_OCSP_sign, NULL}, +{X509_TRUST_OCSP_REQUEST, 0, trust_1oid, "OCSP request", NID_ad_OCSP, NULL} }; #define X509_TRUST_COUNT (sizeof(trstandard)/sizeof(X509_TRUST))