diff --git a/CHANGES b/CHANGES index c5eb0cf86604d410dc463cc7c5d26ffed4b900b4..2ff3d56f3dd9cfaf8c3313a102627e63ff0b4cba 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,15 @@ Changes between 0.9.6 and 0.9.7 [xx XXX 2000] + *) New nonce behavior. The return value of OCSP_check_nonce() now + reflects the various checks performed. Applications can decide + whether to tolerate certain situations such as an absent nonce + in a response when one was present in a request: the ocsp application + just prints out a warning. New function OCSP_add1_basic_nonce() + this is to allow responders to include a nonce in a response even if + the request is nonce-less. + [Steve Henson] + *) Use the cached encoding of an X509_NAME structure rather than copying it. This is apparently the reason for the libsafe "errors" but the code is actually correct. diff --git a/apps/ocsp.c b/apps/ocsp.c index 32506a37cb4d731b286fbdfa7493a1e36538412c..9a04dd751b70f7af05b074b6ef390cbadb8d20df 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c @@ -515,10 +515,15 @@ int MAIN(int argc, char **argv) if (!noverify) { - if (req && (OCSP_check_nonce(req, bs) <= 0)) + if (req && ((i = OCSP_check_nonce(req, bs)) <= 0)) { - BIO_printf(bio_err, "Nonce Verify error\n"); - goto end; + if (i == -1) + BIO_printf(bio_err, "WARNING: no nonce in response\n"); + else + { + BIO_printf(bio_err, "Nonce Verify error\n"); + goto end; + } } i = OCSP_basic_verify(bs, verify_other, store, verify_flags); diff --git a/crypto/ocsp/ocsp.h b/crypto/ocsp/ocsp.h index 4826a709f01e010b9cec60b85921859a1340051d..1463e2fbcf73d3f13391fced9d55f193da8c1b52 100644 --- a/crypto/ocsp/ocsp.h +++ b/crypto/ocsp/ocsp.h @@ -415,6 +415,7 @@ OCSP_CERTID *OCSP_cert_id_new(const EVP_MD *dgst, OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid); int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len); +int OCSP_basic_add1_nonce(OCSP_BASICRESP *resp, unsigned char *val, int len); int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs); int OCSP_copy_nonce(OCSP_BASICRESP *resp, OCSP_REQUEST *req); @@ -557,63 +558,43 @@ void ERR_load_OCSP_strings(void); /* Error codes for the OCSP functions. */ /* Function codes. */ -#define OCSP_F_ASN1_STRING_ENCODE 106 -#define OCSP_F_BASIC_RESPONSE_NEW 100 -#define OCSP_F_BASIC_RESPONSE_VERIFY 101 -#define OCSP_F_CERT_ID_NEW 102 -#define OCSP_F_CERT_STATUS_NEW 103 -#define OCSP_F_D2I_OCSP_NONCE 109 -#define OCSP_F_OCSP_BASIC_ADD1_STATUS 118 -#define OCSP_F_OCSP_BASIC_SIGN 119 -#define OCSP_F_OCSP_BASIC_VERIFY 113 -#define OCSP_F_OCSP_CHECK_DELEGATED 117 -#define OCSP_F_OCSP_CHECK_IDS 114 -#define OCSP_F_OCSP_CHECK_ISSUER 115 -#define OCSP_F_OCSP_CHECK_NONCE 112 -#define OCSP_F_OCSP_MATCH_ISSUERID 116 -#define OCSP_F_OCSP_REQUEST_SIGN 120 +#define OCSP_F_ASN1_STRING_ENCODE 100 +#define OCSP_F_CERT_ID_NEW 101 +#define OCSP_F_D2I_OCSP_NONCE 102 +#define OCSP_F_OCSP_BASIC_ADD1_STATUS 103 +#define OCSP_F_OCSP_BASIC_SIGN 104 +#define OCSP_F_OCSP_BASIC_VERIFY 105 +#define OCSP_F_OCSP_CHECK_DELEGATED 106 +#define OCSP_F_OCSP_CHECK_IDS 107 +#define OCSP_F_OCSP_CHECK_ISSUER 108 +#define OCSP_F_OCSP_MATCH_ISSUERID 109 +#define OCSP_F_OCSP_REQUEST_SIGN 110 #define OCSP_F_OCSP_RESPONSE_GET1_BASIC 111 -#define OCSP_F_OCSP_SENDREQ_BIO 110 -#define OCSP_F_REQUEST_VERIFY 104 -#define OCSP_F_RESPONSE_VERIFY 105 -#define OCSP_F_S2I_OCSP_NONCE 107 -#define OCSP_F_V2I_OCSP_CRLID 108 +#define OCSP_F_OCSP_SENDREQ_BIO 112 +#define OCSP_F_REQUEST_VERIFY 113 /* Reason codes. */ -#define OCSP_R_BAD_DATA 108 -#define OCSP_R_BAD_TAG 100 -#define OCSP_R_CERTIFICATE_VERIFY_ERROR 126 -#define OCSP_R_DIGEST_ERR 101 -#define OCSP_R_FAILED_TO_OPEN 109 -#define OCSP_R_FAILED_TO_READ 110 -#define OCSP_R_FAILED_TO_STAT 111 -#define OCSP_R_MISSING_OCSPSIGNING_USAGE 131 -#define OCSP_R_MISSING_VALUE 112 -#define OCSP_R_NONCE_MISSING_IN_RESPONSE 121 -#define OCSP_R_NONCE_VALUE_MISMATCH 122 -#define OCSP_R_NOT_BASIC_RESPONSE 120 -#define OCSP_R_NO_CERTIFICATE 102 -#define OCSP_R_NO_CERTIFICATES_IN_CHAIN 128 -#define OCSP_R_NO_CONTENT 115 -#define OCSP_R_NO_PUBLIC_KEY 103 -#define OCSP_R_NO_RESPONSE_DATA 104 -#define OCSP_R_NO_REVOKED_TIME 132 -#define OCSP_R_NO_SIGNATURE 105 -#define OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 133 -#define OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA 129 -#define OCSP_R_REVOKED_NO_TIME 106 -#define OCSP_R_ROOT_CA_NOT_TRUSTED 127 -#define OCSP_R_SERVER_READ_ERROR 116 -#define OCSP_R_SERVER_RESPONSE_ERROR 117 -#define OCSP_R_SERVER_RESPONSE_PARSE_ERROR 118 -#define OCSP_R_SERVER_WRITE_ERROR 119 -#define OCSP_R_SIGNATURE_FAILURE 124 -#define OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND 125 -#define OCSP_R_UNEXPECTED_NONCE_IN_RESPONSE 123 -#define OCSP_R_UNKNOWN_MESSAGE_DIGEST 130 -#define OCSP_R_UNKNOWN_NID 107 -#define OCSP_R_UNSUPPORTED_OPTION 113 -#define OCSP_R_VALUE_ALREADY 114 +#define OCSP_R_BAD_DATA 100 +#define OCSP_R_CERTIFICATE_VERIFY_ERROR 101 +#define OCSP_R_DIGEST_ERR 102 +#define OCSP_R_MISSING_OCSPSIGNING_USAGE 103 +#define OCSP_R_NOT_BASIC_RESPONSE 104 +#define OCSP_R_NO_CERTIFICATES_IN_CHAIN 105 +#define OCSP_R_NO_CONTENT 106 +#define OCSP_R_NO_PUBLIC_KEY 107 +#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_RESPONSE_CONTAINS_NO_REVOCATION_DATA 111 +#define OCSP_R_ROOT_CA_NOT_TRUSTED 112 +#define OCSP_R_SERVER_READ_ERROR 113 +#define OCSP_R_SERVER_RESPONSE_ERROR 114 +#define OCSP_R_SERVER_RESPONSE_PARSE_ERROR 115 +#define OCSP_R_SERVER_WRITE_ERROR 116 +#define OCSP_R_SIGNATURE_FAILURE 117 +#define OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND 118 +#define OCSP_R_UNKNOWN_MESSAGE_DIGEST 119 +#define OCSP_R_UNKNOWN_NID 120 #ifdef __cplusplus } diff --git a/crypto/ocsp/ocsp_err.c b/crypto/ocsp/ocsp_err.c index abf8307397401e67f16e39c117b12a43859cb10e..c7a1604343a5b4b3d4eed6a77ae97f6d475f70c7 100644 --- a/crypto/ocsp/ocsp_err.c +++ b/crypto/ocsp/ocsp_err.c @@ -67,10 +67,7 @@ static ERR_STRING_DATA OCSP_str_functs[]= { {ERR_PACK(0,OCSP_F_ASN1_STRING_ENCODE,0), "ASN1_STRING_encode"}, -{ERR_PACK(0,OCSP_F_BASIC_RESPONSE_NEW,0), "BASIC_RESPONSE_NEW"}, -{ERR_PACK(0,OCSP_F_BASIC_RESPONSE_VERIFY,0), "BASIC_RESPONSE_VERIFY"}, {ERR_PACK(0,OCSP_F_CERT_ID_NEW,0), "CERT_ID_NEW"}, -{ERR_PACK(0,OCSP_F_CERT_STATUS_NEW,0), "CERT_STATUS_NEW"}, {ERR_PACK(0,OCSP_F_D2I_OCSP_NONCE,0), "D2I_OCSP_NONCE"}, {ERR_PACK(0,OCSP_F_OCSP_BASIC_ADD1_STATUS,0), "OCSP_basic_add1_status"}, {ERR_PACK(0,OCSP_F_OCSP_BASIC_SIGN,0), "OCSP_basic_sign"}, @@ -78,42 +75,28 @@ static ERR_STRING_DATA OCSP_str_functs[]= {ERR_PACK(0,OCSP_F_OCSP_CHECK_DELEGATED,0), "OCSP_CHECK_DELEGATED"}, {ERR_PACK(0,OCSP_F_OCSP_CHECK_IDS,0), "OCSP_CHECK_IDS"}, {ERR_PACK(0,OCSP_F_OCSP_CHECK_ISSUER,0), "OCSP_CHECK_ISSUER"}, -{ERR_PACK(0,OCSP_F_OCSP_CHECK_NONCE,0), "OCSP_check_nonce"}, {ERR_PACK(0,OCSP_F_OCSP_MATCH_ISSUERID,0), "OCSP_MATCH_ISSUERID"}, {ERR_PACK(0,OCSP_F_OCSP_REQUEST_SIGN,0), "OCSP_request_sign"}, {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"}, -{ERR_PACK(0,OCSP_F_RESPONSE_VERIFY,0), "RESPONSE_VERIFY"}, -{ERR_PACK(0,OCSP_F_S2I_OCSP_NONCE,0), "S2I_OCSP_NONCE"}, -{ERR_PACK(0,OCSP_F_V2I_OCSP_CRLID,0), "V2I_OCSP_CRLID"}, {0,NULL} }; static ERR_STRING_DATA OCSP_str_reasons[]= { {OCSP_R_BAD_DATA ,"bad data"}, -{OCSP_R_BAD_TAG ,"bad tag"}, {OCSP_R_CERTIFICATE_VERIFY_ERROR ,"certificate verify error"}, {OCSP_R_DIGEST_ERR ,"digest err"}, -{OCSP_R_FAILED_TO_OPEN ,"failed to open"}, -{OCSP_R_FAILED_TO_READ ,"failed to read"}, -{OCSP_R_FAILED_TO_STAT ,"failed to stat"}, {OCSP_R_MISSING_OCSPSIGNING_USAGE ,"missing ocspsigning usage"}, -{OCSP_R_MISSING_VALUE ,"missing value"}, -{OCSP_R_NONCE_MISSING_IN_RESPONSE ,"nonce missing in response"}, -{OCSP_R_NONCE_VALUE_MISMATCH ,"nonce value mismatch"}, {OCSP_R_NOT_BASIC_RESPONSE ,"not basic response"}, -{OCSP_R_NO_CERTIFICATE ,"no certificate"}, {OCSP_R_NO_CERTIFICATES_IN_CHAIN ,"no certificates in chain"}, {OCSP_R_NO_CONTENT ,"no content"}, {OCSP_R_NO_PUBLIC_KEY ,"no public key"}, {OCSP_R_NO_RESPONSE_DATA ,"no response data"}, {OCSP_R_NO_REVOKED_TIME ,"no revoked time"}, -{OCSP_R_NO_SIGNATURE ,"no signature"}, {OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE,"private key does not match certificate"}, {OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA,"response contains no revocation data"}, -{OCSP_R_REVOKED_NO_TIME ,"revoked no time"}, {OCSP_R_ROOT_CA_NOT_TRUSTED ,"root ca not trusted"}, {OCSP_R_SERVER_READ_ERROR ,"server read error"}, {OCSP_R_SERVER_RESPONSE_ERROR ,"server response error"}, @@ -121,11 +104,8 @@ static ERR_STRING_DATA OCSP_str_reasons[]= {OCSP_R_SERVER_WRITE_ERROR ,"server write error"}, {OCSP_R_SIGNATURE_FAILURE ,"signature failure"}, {OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND ,"signer certificate not found"}, -{OCSP_R_UNEXPECTED_NONCE_IN_RESPONSE ,"unexpected nonce in response"}, {OCSP_R_UNKNOWN_MESSAGE_DIGEST ,"unknown message digest"}, {OCSP_R_UNKNOWN_NID ,"unknown nid"}, -{OCSP_R_UNSUPPORTED_OPTION ,"unsupported option"}, -{OCSP_R_VALUE_ALREADY ,"value already"}, {0,NULL} }; diff --git a/crypto/ocsp/ocsp_ext.c b/crypto/ocsp/ocsp_ext.c index dcd7869bfbe5fbfdcc58fa4918adbab101661c89..401cfec8b0d4f6447fe9c05cfb61cd66764674fb 100644 --- a/crypto/ocsp/ocsp_ext.c +++ b/crypto/ocsp/ocsp_ext.c @@ -303,11 +303,11 @@ err: /* Nonce handling functions */ -/* Add a nonce to an OCSP request. A nonce can be specificed or if NULL +/* Add a nonce to an extension stack. A nonce can be specificed or if NULL * a random nonce will be generated. */ -int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len) +static int ocsp_add1_nonce(STACK_OF(X509_EXTENSION) **exts, unsigned char *val, int len) { unsigned char *tmpval; ASN1_OCTET_STRING os; @@ -321,7 +321,7 @@ int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len) } os.data = tmpval; os.length = len; - if(!OCSP_REQUEST_add1_ext_i2d(req, NID_id_pkix_OCSP_Nonce, + if(!X509V3_add1_i2d(exts, NID_id_pkix_OCSP_Nonce, &os, 0, X509V3_ADD_REPLACE)) goto err; ret = 1; @@ -330,9 +330,34 @@ int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len) return ret; } -/* Check nonce validity in a request and response: the nonce - * must be either absent in both or present and equal in both. + +/* Add nonce to an OCSP request */ + +int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len) + { + return ocsp_add1_nonce(&req->tbsRequest->requestExtensions, val, len); + } + +/* Same as above but for a response */ + +int OCSP_basic_add1_nonce(OCSP_BASICRESP *resp, unsigned char *val, int len) + { + return ocsp_add1_nonce(&resp->tbsResponseData->responseExtensions, val, len); + } + +/* Check nonce validity in a request and response. + * Return value reflects result: + * 1: nonces present and equal. + * 2: nonces both absent. + * 3: nonce present in response only. + * 0: nonces both present and not equal. + * -1: nonce in request only. + * + * For most responders clients can check return > 0. + * If responder doesn't handle nonces return != 0 may be + * necessary. return == 0 is always an error. */ + int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs) { /* @@ -343,32 +368,25 @@ int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs) * freed immediately anyway. */ - int ret = 0, req_idx, resp_idx; + int req_idx, resp_idx; X509_EXTENSION *req_ext, *resp_ext; req_idx = OCSP_REQUEST_get_ext_by_NID(req, NID_id_pkix_OCSP_Nonce, -1); resp_idx = OCSP_BASICRESP_get_ext_by_NID(bs, NID_id_pkix_OCSP_Nonce, -1); - /* If both absent its OK */ - if((req_idx < 0) && (resp_idx < 0)) return 1; + /* Check both absent */ + if((req_idx < 0) && (resp_idx < 0)) + return 2; + /* Check in request only */ if((req_idx >= 0) && (resp_idx < 0)) - { - OCSPerr(OCSP_F_OCSP_CHECK_NONCE, OCSP_R_NONCE_MISSING_IN_RESPONSE); - goto err; - } + return -1; + /* Check in response but not request */ if((req_idx < 0) && (resp_idx >= 0)) - { - OCSPerr(OCSP_F_OCSP_CHECK_NONCE, OCSP_R_UNEXPECTED_NONCE_IN_RESPONSE); - goto err; - } + return 3; + /* Otherwise nonce in request and response so retrieve the extensions */ req_ext = OCSP_REQUEST_get_ext(req, req_idx); resp_ext = OCSP_BASICRESP_get_ext(bs, resp_idx); if(ASN1_OCTET_STRING_cmp(req_ext->value, resp_ext->value)) - { - OCSPerr(OCSP_F_OCSP_CHECK_NONCE, OCSP_R_NONCE_VALUE_MISMATCH); - goto err; - } - ret = 1; - err: - return ret; + return 0; + return 1; } /* Copy the nonce value (if any) from an OCSP request to