1109998Smarkm/* ocsp_cl.c */ 2109998Smarkm/* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL 3109998Smarkm * project. */ 4109998Smarkm 5109998Smarkm/* History: 6109998Smarkm This file was transfered to Richard Levitte from CertCo by Kathy 7109998Smarkm Weinhold in mid-spring 2000 to be included in OpenSSL or released 8109998Smarkm as a patch kit. */ 9109998Smarkm 10109998Smarkm/* ==================================================================== 11109998Smarkm * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. 12109998Smarkm * 13109998Smarkm * Redistribution and use in source and binary forms, with or without 14109998Smarkm * modification, are permitted provided that the following conditions 15109998Smarkm * are met: 16109998Smarkm * 17109998Smarkm * 1. Redistributions of source code must retain the above copyright 18109998Smarkm * notice, this list of conditions and the following disclaimer. 19109998Smarkm * 20109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 21109998Smarkm * notice, this list of conditions and the following disclaimer in 22109998Smarkm * the documentation and/or other materials provided with the 23109998Smarkm * distribution. 24109998Smarkm * 25109998Smarkm * 3. All advertising materials mentioning features or use of this 26109998Smarkm * software must display the following acknowledgment: 27109998Smarkm * "This product includes software developed by the OpenSSL Project 28109998Smarkm * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 29109998Smarkm * 30109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 31109998Smarkm * endorse or promote products derived from this software without 32109998Smarkm * prior written permission. For written permission, please contact 33109998Smarkm * openssl-core@openssl.org. 34109998Smarkm * 35109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 36109998Smarkm * nor may "OpenSSL" appear in their names without prior written 37109998Smarkm * permission of the OpenSSL Project. 38109998Smarkm * 39109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 40109998Smarkm * acknowledgment: 41109998Smarkm * "This product includes software developed by the OpenSSL Project 42109998Smarkm * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 43109998Smarkm * 44109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 45109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 47109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 48109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 49109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 50109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 51109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 53109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 55109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 56109998Smarkm * ==================================================================== 57109998Smarkm * 58109998Smarkm * This product includes cryptographic software written by Eric Young 59109998Smarkm * (eay@cryptsoft.com). This product includes software written by Tim 60109998Smarkm * Hudson (tjh@cryptsoft.com). 61109998Smarkm * 62109998Smarkm */ 63109998Smarkm 64109998Smarkm#include <stdio.h> 65109998Smarkm#include <time.h> 66109998Smarkm#include <cryptlib.h> 67109998Smarkm#include <openssl/objects.h> 68109998Smarkm#include <openssl/rand.h> 69109998Smarkm#include <openssl/x509.h> 70109998Smarkm#include <openssl/pem.h> 71109998Smarkm#include <openssl/x509v3.h> 72109998Smarkm#include <openssl/ocsp.h> 73109998Smarkm 74109998Smarkm/* Utility functions related to sending OCSP requests and extracting 75109998Smarkm * relevant information from the response. 76109998Smarkm */ 77109998Smarkm 78109998Smarkm/* Add an OCSP_CERTID to an OCSP request. Return new OCSP_ONEREQ 79109998Smarkm * pointer: useful if we want to add extensions. 80109998Smarkm */ 81109998Smarkm 82109998SmarkmOCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid) 83109998Smarkm { 84109998Smarkm OCSP_ONEREQ *one = NULL; 85109998Smarkm 86109998Smarkm if (!(one = OCSP_ONEREQ_new())) goto err; 87109998Smarkm if (one->reqCert) OCSP_CERTID_free(one->reqCert); 88109998Smarkm one->reqCert = cid; 89109998Smarkm if (req && 90109998Smarkm !sk_OCSP_ONEREQ_push(req->tbsRequest->requestList, one)) 91109998Smarkm goto err; 92109998Smarkm return one; 93109998Smarkmerr: 94109998Smarkm OCSP_ONEREQ_free(one); 95109998Smarkm return NULL; 96109998Smarkm } 97109998Smarkm 98109998Smarkm/* Set requestorName from an X509_NAME structure */ 99109998Smarkm 100109998Smarkmint OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm) 101109998Smarkm { 102109998Smarkm GENERAL_NAME *gen; 103109998Smarkm gen = GENERAL_NAME_new(); 104160814Ssimon if (gen == NULL) 105160814Ssimon return 0; 106109998Smarkm if (!X509_NAME_set(&gen->d.directoryName, nm)) 107109998Smarkm { 108109998Smarkm GENERAL_NAME_free(gen); 109109998Smarkm return 0; 110109998Smarkm } 111109998Smarkm gen->type = GEN_DIRNAME; 112109998Smarkm if (req->tbsRequest->requestorName) 113109998Smarkm GENERAL_NAME_free(req->tbsRequest->requestorName); 114109998Smarkm req->tbsRequest->requestorName = gen; 115109998Smarkm return 1; 116109998Smarkm } 117109998Smarkm 118109998Smarkm 119109998Smarkm/* Add a certificate to an OCSP request */ 120109998Smarkm 121109998Smarkmint OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert) 122109998Smarkm { 123109998Smarkm OCSP_SIGNATURE *sig; 124109998Smarkm if (!req->optionalSignature) 125109998Smarkm req->optionalSignature = OCSP_SIGNATURE_new(); 126109998Smarkm sig = req->optionalSignature; 127109998Smarkm if (!sig) return 0; 128109998Smarkm if (!cert) return 1; 129109998Smarkm if (!sig->certs && !(sig->certs = sk_X509_new_null())) 130109998Smarkm return 0; 131109998Smarkm 132109998Smarkm if(!sk_X509_push(sig->certs, cert)) return 0; 133109998Smarkm CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); 134109998Smarkm return 1; 135109998Smarkm } 136109998Smarkm 137109998Smarkm/* Sign an OCSP request set the requestorName to the subjec 138109998Smarkm * name of an optional signers certificate and include one 139109998Smarkm * or more optional certificates in the request. Behaves 140109998Smarkm * like PKCS7_sign(). 141109998Smarkm */ 142109998Smarkm 143109998Smarkmint OCSP_request_sign(OCSP_REQUEST *req, 144109998Smarkm X509 *signer, 145109998Smarkm EVP_PKEY *key, 146109998Smarkm const EVP_MD *dgst, 147109998Smarkm STACK_OF(X509) *certs, 148109998Smarkm unsigned long flags) 149109998Smarkm { 150109998Smarkm int i; 151109998Smarkm OCSP_SIGNATURE *sig; 152109998Smarkm X509 *x; 153109998Smarkm 154109998Smarkm if (!OCSP_request_set1_name(req, X509_get_subject_name(signer))) 155109998Smarkm goto err; 156109998Smarkm 157109998Smarkm if (!(req->optionalSignature = sig = OCSP_SIGNATURE_new())) goto err; 158109998Smarkm if (key) 159109998Smarkm { 160109998Smarkm if (!X509_check_private_key(signer, key)) 161109998Smarkm { 162109998Smarkm OCSPerr(OCSP_F_OCSP_REQUEST_SIGN, OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); 163109998Smarkm goto err; 164109998Smarkm } 165109998Smarkm if (!OCSP_REQUEST_sign(req, key, dgst)) goto err; 166109998Smarkm } 167109998Smarkm 168109998Smarkm if (!(flags & OCSP_NOCERTS)) 169109998Smarkm { 170109998Smarkm if(!OCSP_request_add1_cert(req, signer)) goto err; 171109998Smarkm for (i = 0; i < sk_X509_num(certs); i++) 172109998Smarkm { 173109998Smarkm x = sk_X509_value(certs, i); 174109998Smarkm if (!OCSP_request_add1_cert(req, x)) goto err; 175109998Smarkm } 176109998Smarkm } 177109998Smarkm 178109998Smarkm return 1; 179109998Smarkmerr: 180109998Smarkm OCSP_SIGNATURE_free(req->optionalSignature); 181109998Smarkm req->optionalSignature = NULL; 182109998Smarkm return 0; 183109998Smarkm } 184109998Smarkm 185109998Smarkm/* Get response status */ 186109998Smarkm 187109998Smarkmint OCSP_response_status(OCSP_RESPONSE *resp) 188109998Smarkm { 189109998Smarkm return ASN1_ENUMERATED_get(resp->responseStatus); 190109998Smarkm } 191109998Smarkm 192109998Smarkm/* Extract basic response from OCSP_RESPONSE or NULL if 193109998Smarkm * no basic response present. 194109998Smarkm */ 195109998Smarkm 196109998Smarkm 197109998SmarkmOCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp) 198109998Smarkm { 199109998Smarkm OCSP_RESPBYTES *rb; 200109998Smarkm rb = resp->responseBytes; 201109998Smarkm if (!rb) 202109998Smarkm { 203109998Smarkm OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NO_RESPONSE_DATA); 204109998Smarkm return NULL; 205109998Smarkm } 206109998Smarkm if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic) 207109998Smarkm { 208109998Smarkm OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NOT_BASIC_RESPONSE); 209109998Smarkm return NULL; 210109998Smarkm } 211109998Smarkm 212109998Smarkm return ASN1_item_unpack(rb->response, ASN1_ITEM_rptr(OCSP_BASICRESP)); 213109998Smarkm } 214109998Smarkm 215109998Smarkm/* Return number of OCSP_SINGLERESP reponses present in 216109998Smarkm * a basic response. 217109998Smarkm */ 218109998Smarkm 219109998Smarkmint OCSP_resp_count(OCSP_BASICRESP *bs) 220109998Smarkm { 221109998Smarkm if (!bs) return -1; 222109998Smarkm return sk_OCSP_SINGLERESP_num(bs->tbsResponseData->responses); 223109998Smarkm } 224109998Smarkm 225109998Smarkm/* Extract an OCSP_SINGLERESP response with a given index */ 226109998Smarkm 227109998SmarkmOCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx) 228109998Smarkm { 229109998Smarkm if (!bs) return NULL; 230109998Smarkm return sk_OCSP_SINGLERESP_value(bs->tbsResponseData->responses, idx); 231109998Smarkm } 232109998Smarkm 233109998Smarkm/* Look single response matching a given certificate ID */ 234109998Smarkm 235109998Smarkmint OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last) 236109998Smarkm { 237109998Smarkm int i; 238109998Smarkm STACK_OF(OCSP_SINGLERESP) *sresp; 239109998Smarkm OCSP_SINGLERESP *single; 240109998Smarkm if (!bs) return -1; 241109998Smarkm if (last < 0) last = 0; 242109998Smarkm else last++; 243109998Smarkm sresp = bs->tbsResponseData->responses; 244109998Smarkm for (i = last; i < sk_OCSP_SINGLERESP_num(sresp); i++) 245109998Smarkm { 246109998Smarkm single = sk_OCSP_SINGLERESP_value(sresp, i); 247109998Smarkm if (!OCSP_id_cmp(id, single->certId)) return i; 248109998Smarkm } 249109998Smarkm return -1; 250109998Smarkm } 251109998Smarkm 252109998Smarkm/* Extract status information from an OCSP_SINGLERESP structure. 253109998Smarkm * Note: the revtime and reason values are only set if the 254109998Smarkm * certificate status is revoked. Returns numerical value of 255109998Smarkm * status. 256109998Smarkm */ 257109998Smarkm 258109998Smarkmint OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason, 259109998Smarkm ASN1_GENERALIZEDTIME **revtime, 260109998Smarkm ASN1_GENERALIZEDTIME **thisupd, 261109998Smarkm ASN1_GENERALIZEDTIME **nextupd) 262109998Smarkm { 263109998Smarkm int ret; 264109998Smarkm OCSP_CERTSTATUS *cst; 265109998Smarkm if(!single) return -1; 266109998Smarkm cst = single->certStatus; 267109998Smarkm ret = cst->type; 268109998Smarkm if (ret == V_OCSP_CERTSTATUS_REVOKED) 269109998Smarkm { 270109998Smarkm OCSP_REVOKEDINFO *rev = cst->value.revoked; 271109998Smarkm if (revtime) *revtime = rev->revocationTime; 272109998Smarkm if (reason) 273109998Smarkm { 274109998Smarkm if(rev->revocationReason) 275109998Smarkm *reason = ASN1_ENUMERATED_get(rev->revocationReason); 276109998Smarkm else *reason = -1; 277109998Smarkm } 278109998Smarkm } 279109998Smarkm if(thisupd) *thisupd = single->thisUpdate; 280109998Smarkm if(nextupd) *nextupd = single->nextUpdate; 281109998Smarkm return ret; 282109998Smarkm } 283109998Smarkm 284109998Smarkm/* This function combines the previous ones: look up a certificate ID and 285109998Smarkm * if found extract status information. Return 0 is successful. 286109998Smarkm */ 287109998Smarkm 288109998Smarkmint OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status, 289109998Smarkm int *reason, 290109998Smarkm ASN1_GENERALIZEDTIME **revtime, 291109998Smarkm ASN1_GENERALIZEDTIME **thisupd, 292109998Smarkm ASN1_GENERALIZEDTIME **nextupd) 293109998Smarkm { 294109998Smarkm int i; 295109998Smarkm OCSP_SINGLERESP *single; 296109998Smarkm i = OCSP_resp_find(bs, id, -1); 297109998Smarkm /* Maybe check for multiple responses and give an error? */ 298109998Smarkm if(i < 0) return 0; 299109998Smarkm single = OCSP_resp_get0(bs, i); 300109998Smarkm i = OCSP_single_get0_status(single, reason, revtime, thisupd, nextupd); 301109998Smarkm if(status) *status = i; 302109998Smarkm return 1; 303109998Smarkm } 304109998Smarkm 305109998Smarkm/* Check validity of thisUpdate and nextUpdate fields. It is possible that the request will 306109998Smarkm * take a few seconds to process and/or the time wont be totally accurate. Therefore to avoid 307109998Smarkm * rejecting otherwise valid time we allow the times to be within 'nsec' of the current time. 308109998Smarkm * Also to avoid accepting very old responses without a nextUpdate field an optional maxage 309109998Smarkm * parameter specifies the maximum age the thisUpdate field can be. 310109998Smarkm */ 311109998Smarkm 312109998Smarkmint OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long nsec, long maxsec) 313109998Smarkm { 314109998Smarkm int ret = 1; 315109998Smarkm time_t t_now, t_tmp; 316109998Smarkm time(&t_now); 317109998Smarkm /* Check thisUpdate is valid and not more than nsec in the future */ 318109998Smarkm if (!ASN1_GENERALIZEDTIME_check(thisupd)) 319109998Smarkm { 320109998Smarkm OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_ERROR_IN_THISUPDATE_FIELD); 321109998Smarkm ret = 0; 322109998Smarkm } 323109998Smarkm else 324109998Smarkm { 325109998Smarkm t_tmp = t_now + nsec; 326109998Smarkm if (X509_cmp_time(thisupd, &t_tmp) > 0) 327109998Smarkm { 328109998Smarkm OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_NOT_YET_VALID); 329109998Smarkm ret = 0; 330109998Smarkm } 331109998Smarkm 332109998Smarkm /* If maxsec specified check thisUpdate is not more than maxsec in the past */ 333109998Smarkm if (maxsec >= 0) 334109998Smarkm { 335109998Smarkm t_tmp = t_now - maxsec; 336109998Smarkm if (X509_cmp_time(thisupd, &t_tmp) < 0) 337109998Smarkm { 338109998Smarkm OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_TOO_OLD); 339109998Smarkm ret = 0; 340109998Smarkm } 341109998Smarkm } 342109998Smarkm } 343109998Smarkm 344109998Smarkm 345109998Smarkm if (!nextupd) return ret; 346109998Smarkm 347109998Smarkm /* Check nextUpdate is valid and not more than nsec in the past */ 348109998Smarkm if (!ASN1_GENERALIZEDTIME_check(nextupd)) 349109998Smarkm { 350109998Smarkm OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_ERROR_IN_NEXTUPDATE_FIELD); 351109998Smarkm ret = 0; 352109998Smarkm } 353109998Smarkm else 354109998Smarkm { 355109998Smarkm t_tmp = t_now - nsec; 356109998Smarkm if (X509_cmp_time(nextupd, &t_tmp) < 0) 357109998Smarkm { 358109998Smarkm OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_EXPIRED); 359109998Smarkm ret = 0; 360109998Smarkm } 361109998Smarkm } 362109998Smarkm 363109998Smarkm /* Also don't allow nextUpdate to precede thisUpdate */ 364109998Smarkm if (ASN1_STRING_cmp(nextupd, thisupd) < 0) 365109998Smarkm { 366109998Smarkm OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE); 367109998Smarkm ret = 0; 368109998Smarkm } 369109998Smarkm 370109998Smarkm return ret; 371109998Smarkm } 372