1109998Smarkm/* ocsp_cl.c */ 2280304Sjkim/* 3280304Sjkim * Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL 4280304Sjkim * project. 5280304Sjkim */ 6109998Smarkm 7280304Sjkim/* 8280304Sjkim * History: This file was transfered to Richard Levitte from CertCo by Kathy 9280304Sjkim * Weinhold in mid-spring 2000 to be included in OpenSSL or released as a 10280304Sjkim * patch kit. 11280304Sjkim */ 12109998Smarkm 13109998Smarkm/* ==================================================================== 14109998Smarkm * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. 15109998Smarkm * 16109998Smarkm * Redistribution and use in source and binary forms, with or without 17109998Smarkm * modification, are permitted provided that the following conditions 18109998Smarkm * are met: 19109998Smarkm * 20109998Smarkm * 1. Redistributions of source code must retain the above copyright 21280304Sjkim * notice, this list of conditions and the following disclaimer. 22109998Smarkm * 23109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 24109998Smarkm * notice, this list of conditions and the following disclaimer in 25109998Smarkm * the documentation and/or other materials provided with the 26109998Smarkm * distribution. 27109998Smarkm * 28109998Smarkm * 3. All advertising materials mentioning features or use of this 29109998Smarkm * software must display the following acknowledgment: 30109998Smarkm * "This product includes software developed by the OpenSSL Project 31109998Smarkm * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 32109998Smarkm * 33109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 34109998Smarkm * endorse or promote products derived from this software without 35109998Smarkm * prior written permission. For written permission, please contact 36109998Smarkm * openssl-core@openssl.org. 37109998Smarkm * 38109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 39109998Smarkm * nor may "OpenSSL" appear in their names without prior written 40109998Smarkm * permission of the OpenSSL Project. 41109998Smarkm * 42109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 43109998Smarkm * acknowledgment: 44109998Smarkm * "This product includes software developed by the OpenSSL Project 45109998Smarkm * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 46109998Smarkm * 47109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 48109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 50109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 51109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 52109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 53109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 54109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 56109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 57109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 58109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 59109998Smarkm * ==================================================================== 60109998Smarkm * 61109998Smarkm * This product includes cryptographic software written by Eric Young 62109998Smarkm * (eay@cryptsoft.com). This product includes software written by Tim 63109998Smarkm * Hudson (tjh@cryptsoft.com). 64109998Smarkm * 65109998Smarkm */ 66109998Smarkm 67109998Smarkm#include <stdio.h> 68109998Smarkm#include <time.h> 69109998Smarkm#include <cryptlib.h> 70109998Smarkm#include <openssl/objects.h> 71109998Smarkm#include <openssl/rand.h> 72109998Smarkm#include <openssl/x509.h> 73109998Smarkm#include <openssl/pem.h> 74109998Smarkm#include <openssl/x509v3.h> 75109998Smarkm#include <openssl/ocsp.h> 76109998Smarkm 77280304Sjkim/* 78280304Sjkim * Utility functions related to sending OCSP requests and extracting relevant 79280304Sjkim * information from the response. 80109998Smarkm */ 81109998Smarkm 82280304Sjkim/* 83280304Sjkim * Add an OCSP_CERTID to an OCSP request. Return new OCSP_ONEREQ pointer: 84280304Sjkim * useful if we want to add extensions. 85109998Smarkm */ 86109998Smarkm 87109998SmarkmOCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid) 88280304Sjkim{ 89280304Sjkim OCSP_ONEREQ *one = NULL; 90109998Smarkm 91280304Sjkim if (!(one = OCSP_ONEREQ_new())) 92280304Sjkim goto err; 93280304Sjkim if (one->reqCert) 94280304Sjkim OCSP_CERTID_free(one->reqCert); 95280304Sjkim one->reqCert = cid; 96280304Sjkim if (req && !sk_OCSP_ONEREQ_push(req->tbsRequest->requestList, one)) 97280304Sjkim goto err; 98280304Sjkim return one; 99280304Sjkim err: 100280304Sjkim OCSP_ONEREQ_free(one); 101280304Sjkim return NULL; 102280304Sjkim} 103109998Smarkm 104109998Smarkm/* Set requestorName from an X509_NAME structure */ 105109998Smarkm 106109998Smarkmint OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm) 107280304Sjkim{ 108280304Sjkim GENERAL_NAME *gen; 109280304Sjkim gen = GENERAL_NAME_new(); 110280304Sjkim if (gen == NULL) 111280304Sjkim return 0; 112280304Sjkim if (!X509_NAME_set(&gen->d.directoryName, nm)) { 113280304Sjkim GENERAL_NAME_free(gen); 114280304Sjkim return 0; 115280304Sjkim } 116280304Sjkim gen->type = GEN_DIRNAME; 117280304Sjkim if (req->tbsRequest->requestorName) 118280304Sjkim GENERAL_NAME_free(req->tbsRequest->requestorName); 119280304Sjkim req->tbsRequest->requestorName = gen; 120280304Sjkim return 1; 121280304Sjkim} 122109998Smarkm 123109998Smarkm/* Add a certificate to an OCSP request */ 124109998Smarkm 125109998Smarkmint OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert) 126280304Sjkim{ 127280304Sjkim OCSP_SIGNATURE *sig; 128280304Sjkim if (!req->optionalSignature) 129280304Sjkim req->optionalSignature = OCSP_SIGNATURE_new(); 130280304Sjkim sig = req->optionalSignature; 131280304Sjkim if (!sig) 132280304Sjkim return 0; 133280304Sjkim if (!cert) 134280304Sjkim return 1; 135280304Sjkim if (!sig->certs && !(sig->certs = sk_X509_new_null())) 136280304Sjkim return 0; 137109998Smarkm 138280304Sjkim if (!sk_X509_push(sig->certs, cert)) 139280304Sjkim return 0; 140280304Sjkim CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); 141280304Sjkim return 1; 142280304Sjkim} 143109998Smarkm 144280304Sjkim/* 145280304Sjkim * Sign an OCSP request set the requestorName to the subjec name of an 146280304Sjkim * optional signers certificate and include one or more optional certificates 147280304Sjkim * in the request. Behaves like PKCS7_sign(). 148109998Smarkm */ 149109998Smarkm 150280304Sjkimint OCSP_request_sign(OCSP_REQUEST *req, 151280304Sjkim X509 *signer, 152280304Sjkim EVP_PKEY *key, 153280304Sjkim const EVP_MD *dgst, 154280304Sjkim STACK_OF(X509) *certs, unsigned long flags) 155280304Sjkim{ 156280304Sjkim int i; 157280304Sjkim OCSP_SIGNATURE *sig; 158280304Sjkim X509 *x; 159109998Smarkm 160280304Sjkim if (!OCSP_request_set1_name(req, X509_get_subject_name(signer))) 161280304Sjkim goto err; 162109998Smarkm 163280304Sjkim if (!(req->optionalSignature = sig = OCSP_SIGNATURE_new())) 164280304Sjkim goto err; 165280304Sjkim if (key) { 166280304Sjkim if (!X509_check_private_key(signer, key)) { 167280304Sjkim OCSPerr(OCSP_F_OCSP_REQUEST_SIGN, 168280304Sjkim OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); 169280304Sjkim goto err; 170280304Sjkim } 171280304Sjkim if (!OCSP_REQUEST_sign(req, key, dgst)) 172280304Sjkim goto err; 173280304Sjkim } 174109998Smarkm 175280304Sjkim if (!(flags & OCSP_NOCERTS)) { 176280304Sjkim if (!OCSP_request_add1_cert(req, signer)) 177280304Sjkim goto err; 178280304Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 179280304Sjkim x = sk_X509_value(certs, i); 180280304Sjkim if (!OCSP_request_add1_cert(req, x)) 181280304Sjkim goto err; 182280304Sjkim } 183280304Sjkim } 184109998Smarkm 185280304Sjkim return 1; 186280304Sjkim err: 187280304Sjkim OCSP_SIGNATURE_free(req->optionalSignature); 188280304Sjkim req->optionalSignature = NULL; 189280304Sjkim return 0; 190280304Sjkim} 191109998Smarkm 192109998Smarkm/* Get response status */ 193109998Smarkm 194109998Smarkmint OCSP_response_status(OCSP_RESPONSE *resp) 195280304Sjkim{ 196280304Sjkim return ASN1_ENUMERATED_get(resp->responseStatus); 197280304Sjkim} 198109998Smarkm 199280304Sjkim/* 200280304Sjkim * Extract basic response from OCSP_RESPONSE or NULL if no basic response 201280304Sjkim * present. 202109998Smarkm */ 203109998Smarkm 204109998SmarkmOCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp) 205280304Sjkim{ 206280304Sjkim OCSP_RESPBYTES *rb; 207280304Sjkim rb = resp->responseBytes; 208280304Sjkim if (!rb) { 209280304Sjkim OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NO_RESPONSE_DATA); 210280304Sjkim return NULL; 211280304Sjkim } 212280304Sjkim if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic) { 213280304Sjkim OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NOT_BASIC_RESPONSE); 214280304Sjkim return NULL; 215280304Sjkim } 216109998Smarkm 217280304Sjkim return ASN1_item_unpack(rb->response, ASN1_ITEM_rptr(OCSP_BASICRESP)); 218280304Sjkim} 219109998Smarkm 220280304Sjkim/* 221280304Sjkim * Return number of OCSP_SINGLERESP reponses present in a basic response. 222109998Smarkm */ 223109998Smarkm 224109998Smarkmint OCSP_resp_count(OCSP_BASICRESP *bs) 225280304Sjkim{ 226280304Sjkim if (!bs) 227280304Sjkim return -1; 228280304Sjkim return sk_OCSP_SINGLERESP_num(bs->tbsResponseData->responses); 229280304Sjkim} 230109998Smarkm 231109998Smarkm/* Extract an OCSP_SINGLERESP response with a given index */ 232109998Smarkm 233109998SmarkmOCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx) 234280304Sjkim{ 235280304Sjkim if (!bs) 236280304Sjkim return NULL; 237280304Sjkim return sk_OCSP_SINGLERESP_value(bs->tbsResponseData->responses, idx); 238280304Sjkim} 239109998Smarkm 240109998Smarkm/* Look single response matching a given certificate ID */ 241109998Smarkm 242109998Smarkmint OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last) 243280304Sjkim{ 244280304Sjkim int i; 245280304Sjkim STACK_OF(OCSP_SINGLERESP) *sresp; 246280304Sjkim OCSP_SINGLERESP *single; 247280304Sjkim if (!bs) 248280304Sjkim return -1; 249280304Sjkim if (last < 0) 250280304Sjkim last = 0; 251280304Sjkim else 252280304Sjkim last++; 253280304Sjkim sresp = bs->tbsResponseData->responses; 254280304Sjkim for (i = last; i < sk_OCSP_SINGLERESP_num(sresp); i++) { 255280304Sjkim single = sk_OCSP_SINGLERESP_value(sresp, i); 256280304Sjkim if (!OCSP_id_cmp(id, single->certId)) 257280304Sjkim return i; 258280304Sjkim } 259280304Sjkim return -1; 260280304Sjkim} 261109998Smarkm 262280304Sjkim/* 263280304Sjkim * Extract status information from an OCSP_SINGLERESP structure. Note: the 264280304Sjkim * revtime and reason values are only set if the certificate status is 265280304Sjkim * revoked. Returns numerical value of status. 266109998Smarkm */ 267109998Smarkm 268109998Smarkmint OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason, 269280304Sjkim ASN1_GENERALIZEDTIME **revtime, 270280304Sjkim ASN1_GENERALIZEDTIME **thisupd, 271280304Sjkim ASN1_GENERALIZEDTIME **nextupd) 272280304Sjkim{ 273280304Sjkim int ret; 274280304Sjkim OCSP_CERTSTATUS *cst; 275280304Sjkim if (!single) 276280304Sjkim return -1; 277280304Sjkim cst = single->certStatus; 278280304Sjkim ret = cst->type; 279280304Sjkim if (ret == V_OCSP_CERTSTATUS_REVOKED) { 280280304Sjkim OCSP_REVOKEDINFO *rev = cst->value.revoked; 281280304Sjkim if (revtime) 282280304Sjkim *revtime = rev->revocationTime; 283280304Sjkim if (reason) { 284280304Sjkim if (rev->revocationReason) 285280304Sjkim *reason = ASN1_ENUMERATED_get(rev->revocationReason); 286280304Sjkim else 287280304Sjkim *reason = -1; 288280304Sjkim } 289280304Sjkim } 290280304Sjkim if (thisupd) 291280304Sjkim *thisupd = single->thisUpdate; 292280304Sjkim if (nextupd) 293280304Sjkim *nextupd = single->nextUpdate; 294280304Sjkim return ret; 295280304Sjkim} 296109998Smarkm 297280304Sjkim/* 298280304Sjkim * This function combines the previous ones: look up a certificate ID and if 299280304Sjkim * found extract status information. Return 0 is successful. 300109998Smarkm */ 301109998Smarkm 302109998Smarkmint OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status, 303280304Sjkim int *reason, 304280304Sjkim ASN1_GENERALIZEDTIME **revtime, 305280304Sjkim ASN1_GENERALIZEDTIME **thisupd, 306280304Sjkim ASN1_GENERALIZEDTIME **nextupd) 307280304Sjkim{ 308280304Sjkim int i; 309280304Sjkim OCSP_SINGLERESP *single; 310280304Sjkim i = OCSP_resp_find(bs, id, -1); 311280304Sjkim /* Maybe check for multiple responses and give an error? */ 312280304Sjkim if (i < 0) 313280304Sjkim return 0; 314280304Sjkim single = OCSP_resp_get0(bs, i); 315280304Sjkim i = OCSP_single_get0_status(single, reason, revtime, thisupd, nextupd); 316280304Sjkim if (status) 317280304Sjkim *status = i; 318280304Sjkim return 1; 319280304Sjkim} 320109998Smarkm 321280304Sjkim/* 322280304Sjkim * Check validity of thisUpdate and nextUpdate fields. It is possible that 323280304Sjkim * the request will take a few seconds to process and/or the time wont be 324280304Sjkim * totally accurate. Therefore to avoid rejecting otherwise valid time we 325280304Sjkim * allow the times to be within 'nsec' of the current time. Also to avoid 326280304Sjkim * accepting very old responses without a nextUpdate field an optional maxage 327109998Smarkm * parameter specifies the maximum age the thisUpdate field can be. 328109998Smarkm */ 329109998Smarkm 330280304Sjkimint OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, 331280304Sjkim ASN1_GENERALIZEDTIME *nextupd, long nsec, long maxsec) 332280304Sjkim{ 333280304Sjkim int ret = 1; 334280304Sjkim time_t t_now, t_tmp; 335280304Sjkim time(&t_now); 336280304Sjkim /* Check thisUpdate is valid and not more than nsec in the future */ 337280304Sjkim if (!ASN1_GENERALIZEDTIME_check(thisupd)) { 338280304Sjkim OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_ERROR_IN_THISUPDATE_FIELD); 339280304Sjkim ret = 0; 340280304Sjkim } else { 341280304Sjkim t_tmp = t_now + nsec; 342280304Sjkim if (X509_cmp_time(thisupd, &t_tmp) > 0) { 343280304Sjkim OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_NOT_YET_VALID); 344280304Sjkim ret = 0; 345280304Sjkim } 346109998Smarkm 347280304Sjkim /* 348280304Sjkim * If maxsec specified check thisUpdate is not more than maxsec in 349280304Sjkim * the past 350280304Sjkim */ 351280304Sjkim if (maxsec >= 0) { 352280304Sjkim t_tmp = t_now - maxsec; 353280304Sjkim if (X509_cmp_time(thisupd, &t_tmp) < 0) { 354280304Sjkim OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_TOO_OLD); 355280304Sjkim ret = 0; 356280304Sjkim } 357280304Sjkim } 358280304Sjkim } 359109998Smarkm 360280304Sjkim if (!nextupd) 361280304Sjkim return ret; 362109998Smarkm 363280304Sjkim /* Check nextUpdate is valid and not more than nsec in the past */ 364280304Sjkim if (!ASN1_GENERALIZEDTIME_check(nextupd)) { 365280304Sjkim OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_ERROR_IN_NEXTUPDATE_FIELD); 366280304Sjkim ret = 0; 367280304Sjkim } else { 368280304Sjkim t_tmp = t_now - nsec; 369280304Sjkim if (X509_cmp_time(nextupd, &t_tmp) < 0) { 370280304Sjkim OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_EXPIRED); 371280304Sjkim ret = 0; 372280304Sjkim } 373280304Sjkim } 374109998Smarkm 375280304Sjkim /* Also don't allow nextUpdate to precede thisUpdate */ 376280304Sjkim if (ASN1_STRING_cmp(nextupd, thisupd) < 0) { 377280304Sjkim OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, 378280304Sjkim OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE); 379280304Sjkim ret = 0; 380280304Sjkim } 381109998Smarkm 382280304Sjkim return ret; 383280304Sjkim} 384