Commit 0b33bc65 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Add set of OCSP client functions. All experimental
and subject to addition, modifcation or deletion.

Add two OCSP nonce utility functions.

Fix typo in status code name.
parent 0f5fa24a
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
@@ -3,7 +3,29 @@

 Changes between 0.9.6 and 0.9.7  [xx XXX 2000]

  *) Change function OCSP_request_add() to OCSP_request_add0().
  *) Move OCSP client related routines to ocsp_cl.c. These
     provide utility functions which an application needing
     to issue a request to an OCSP responder and analyse the
     response will typically need: as opposed to those which an
     OCSP responder itself would need which will be added later.

     OCSP_request_sign() signs an OCSP request with an API similar
     to PKCS7_sign(). OCSP_response_status() returns status of OCSP
     response. OCSP_response_get1_basic() extracts basic response
     from response. OCSP_resp_find_status(): finds and extracts status
     information from an OCSP_CERTID structure (which will be created
     when the request structure is built). These are built from lower
     level functions which work on OCSP_SINGLERESP structures but
     wont normally be used unless the application wishes to examine
     extensions in the OCSP response for example.

     Replace nonce routines with a pair of functions.
     OCSP_request_add1_nonce() adds a nonce value and optionally
     generates a random value. OCSP_check_nonce() checks the
     validity of the nonce in an OCSP response.
     [Steve Henson]

  *) Change function OCSP_request_add() to OCSP_request_add0_id().
     This doesn't copy the supplied OCSP_CERTID and avoids the
     need to free up the newly created id. Change return type
     to OCSP_ONEREQ to return the internal OCSP_ONEREQ structure.
+2 −2
Original line number Diff line number Diff line
@@ -23,10 +23,10 @@ APPS=

LIB=$(TOP)/libcrypto.a
LIBSRC= ocsp_asn.c ocsp_ext.c ocsp_ht.c \
	ocsp_lib.c ocsp_prn.c ocsp_err.c
	ocsp_lib.c ocsp_cl.c ocsp_prn.c ocsp_err.c

LIBOBJ= ocsp_asn.o ocsp_ext.o ocsp_ht.o \
	ocsp_lib.o ocsp_prn.o ocsp_err.o
	ocsp_lib.o ocsp_cl.o ocsp_prn.o ocsp_err.o

SRC= $(LIBSRC)

+31 −10
Original line number Diff line number Diff line
@@ -72,6 +72,12 @@
extern "C" {
#endif

/* Various flags and values */

#define OCSP_DEFAULT_NONCE_LENGTH	16

#define OCSP_NOCERTS			0x1

/*   CertID ::= SEQUENCE {
 *       hashAlgorithm            AlgorithmIdentifier,
 *       issuerNameHash     OCTET STRING, -- Hash of Issuer's DN
@@ -146,7 +152,7 @@ typedef struct ocsp_request_st
 *       unauthorized          (6)       --Request unauthorized
 *   }
 */
#define OCSP_RESPONSE_STATUS_SUCCESSFULL          0
#define OCSP_RESPONSE_STATUS_SUCCESSFUL          0
#define OCSP_RESPONSE_STATUS_MALFORMEDREQUEST     1
#define OCSP_RESPONSE_STATUS_INTERNALERROR        2
#define OCSP_RESPONSE_STATUS_TRYLATER             3
@@ -361,21 +367,21 @@ typedef struct ocsp_service_locator_st
#define OCSP_REQUEST_sign(o,pkey,md) \
	ASN1_item_sign(&OCSP_REQINFO_it,\
		o->optionalSignature->signatureAlgorithm,NULL,\
	        o->optionalSignature->signature,(char *)o->tbsRequest,pkey,md)
	        o->optionalSignature->signature,o->tbsRequest,pkey,md)

#define OCSP_BASICRESP_sign(o,pkey,md,d) \
	ASN1_item_sign(&OCSP_RESPDATA_it,o->signatureAlgorithm,NULL,\
		o->signature,(char *)o->tbsResponseData,pkey,md)
		o->signature,o->tbsResponseData,pkey,md)

#define OCSP_REQUEST_verify(a,r) ASN1_item_verify(&OCSP_REQINFO_it,\
        a->optionalSignature->signatureAlgorithm,\
	a->optionalSignature->signature,(char *)a->tbsRequest,r)
	a->optionalSignature->signature,a->tbsRequest,r)

#define OCSP_BASICRESP_verify(a,r,d) ASN1_item_verify(&OCSP_RESPDATA_it,\
	a->signatureAlgorithm,a->signature,(char *)a->tbsResponseData,r)
	a->signatureAlgorithm,a->signature,a->tbsResponseData,r)

#define ASN1_BIT_STRING_digest(data,type,md,len) \
	ASN1_item_digest(&ASN1_BIT_STRING_it,type,(char *)data,md,len)
	ASN1_item_digest(&ASN1_BIT_STRING_it,type,data,md,len)

#define OCSP_CERTID_dup(cid) (OCSP_CERTID*)ASN1_dup((int(*)())i2d_OCSP_CERTID,\
		(char *(*)())d2i_OCSP_CERTID,(char *)(cid))
@@ -395,15 +401,26 @@ OCSP_CERTID *OCSP_cert_id_new(const EVP_MD *dgst,

OCSP_CERTSTATUS *OCSP_cert_status_new(int status, int reason, char *tim);

OCSP_ONEREQ *OCSP_request_add0(OCSP_REQUEST *req, OCSP_CERTID *cid);
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_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs);
int OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm);
int OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert);

int OCSP_request_sign(OCSP_REQUEST   *req,
		      X509           *signer,
		      EVP_PKEY       *key,
		      const EVP_MD   *dgst,
		      STACK_OF(X509) *certs);
		      STACK_OF(X509) *certs,
		      unsigned long flags);

int OCSP_response_status(OCSP_RESPONSE *resp);
OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp);

int OCSP_request_verify(OCSP_REQUEST *req, EVP_PKEY *pkey);

int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b);

OCSP_BASICRESP *OCSP_basic_response_new(int tag,
					X509* cert);

@@ -431,8 +448,6 @@ OCSP_RESPONSE *OCSP_response_new(int status,
ASN1_STRING *ASN1_STRING_encode(ASN1_STRING *s, int (*i2d)(), 
				char *data, STACK_OF(ASN1_OBJECT) *sk);

X509_EXTENSION *OCSP_nonce_new(void *p, unsigned int len);

X509_EXTENSION *OCSP_crlID_new(char *url, long *n, char *tim);

X509_EXTENSION *OCSP_accept_responses_new(char **oids);
@@ -520,6 +535,8 @@ void ERR_load_OCSP_strings(void);
#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_CHECK_NONCE				 112
#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
@@ -534,6 +551,9 @@ void ERR_load_OCSP_strings(void);
#define OCSP_R_FAILED_TO_READ				 110
#define OCSP_R_FAILED_TO_STAT				 111
#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_CONTENT				 115
#define OCSP_R_NO_PUBLIC_KEY				 103
@@ -544,6 +564,7 @@ void ERR_load_OCSP_strings(void);
#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_UNEXPECTED_NONCE_IN_RESPONSE		 123
#define OCSP_R_UNKNOWN_NID				 107
#define OCSP_R_UNSUPPORTED_OPTION			 113
#define OCSP_R_VALUE_ALREADY				 114

crypto/ocsp/ocsp_cl.c

0 → 100644
+291 −0
Original line number Diff line number Diff line
/* ocsp_cl.c */
/* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL
 * project. */

/* History:
   This file was transfered to Richard Levitte from CertCo by Kathy
   Weinhold in mid-spring 2000 to be included in OpenSSL or released
   as a patch kit. */

/* ====================================================================
 * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    openssl-core@openssl.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes cryptographic software written by Eric Young
 * (eay@cryptsoft.com).  This product includes software written by Tim
 * Hudson (tjh@cryptsoft.com).
 *
 */

#include <stdio.h>
#include <cryptlib.h>
#include <openssl/objects.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/ocsp.h>

/* Utility functions related to sending OCSP requests and extracting
 * relevant information from the response.
 */

/* Add an OCSP_CERTID to an OCSP request. Return new OCSP_ONEREQ 
 * pointer: useful if we want to add extensions.
 */

OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid)
        {
	OCSP_ONEREQ *one = NULL;

	if (!(one = OCSP_ONEREQ_new())) goto err;
	if (one->reqCert) OCSP_CERTID_free(one->reqCert);
	one->reqCert = cid;
	if (req &&
		!sk_OCSP_ONEREQ_push(req->tbsRequest->requestList, one))
				goto err;
	return one;
err:
	OCSP_ONEREQ_free(one);
	return NULL;
        }

/* Set requestorName from an X509_NAME structure */

int OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm)
	{
	GENERAL_NAME *gen;
	gen = GENERAL_NAME_new();
	if (!X509_NAME_set(&gen->d.directoryName, nm))
		{
		GENERAL_NAME_free(gen);
		return 0;
		}
	gen->type = GEN_DIRNAME;
	if (req->tbsRequest->requestorName)
		GENERAL_NAME_free(req->tbsRequest->requestorName);
	req->tbsRequest->requestorName = gen;
	return 1;
	}
	

/* Add a certificate to an OCSP request */

int OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert)
	{
	OCSP_SIGNATURE *sig;
	if (!req->optionalSignature)
		req->optionalSignature = OCSP_SIGNATURE_new();
	sig = req->optionalSignature;
	if (!sig) return 0;
	if (!cert) return 1;
	if (!sig->certs && !(sig->certs = sk_X509_new_null()))
		return 0;

	if(!sk_X509_push(sig->certs, cert)) return 0;
	CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
	return 1;
	}

/* Sign an OCSP request set the requestorName to the subjec
 * name of an optional signers certificate and include one
 * or more optional certificates in the request. Behaves
 * like PKCS7_sign().
 */

int OCSP_request_sign(OCSP_REQUEST   *req,
		      X509           *signer,
		      EVP_PKEY       *key,
		      const EVP_MD   *dgst,
		      STACK_OF(X509) *certs,
		      unsigned long flags)
        {
	int i;
	OCSP_SIGNATURE *sig;
	X509 *x;

	if (signer &&
		!OCSP_request_set1_name(req, X509_get_subject_name(signer)))
			goto err;

	if (!(req->optionalSignature = sig = OCSP_SIGNATURE_new())) goto err;
	if (!dgst) dgst = EVP_sha1();
	if (key && !OCSP_REQUEST_sign(req, key, dgst)) goto err;
	if (!(flags & OCSP_NOCERTS))
		{
		if (!OCSP_request_add1_cert(req, signer)) goto err;
	        for (i = 0; i < sk_X509_num(certs); i++)
			{
			x = sk_X509_value(certs, i);
			if (!OCSP_request_add1_cert(req, x)) goto err;
			}
		}
	return 1;
err:
	OCSP_SIGNATURE_free(req->optionalSignature);
	req->optionalSignature = NULL;
	return 0;
	}

/* Get response status */

int OCSP_response_status(OCSP_RESPONSE *resp)
	{
	return ASN1_ENUMERATED_get(resp->responseStatus);
	}

/* Extract basic response from OCSP_RESPONSE or NULL if
 * no basic response present.
 */
 

OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp)
	{
	OCSP_RESPBYTES *rb;
	rb = resp->responseBytes;
	if (!rb)
		{
		OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NO_RESPONSE_DATA);
		return NULL;
		}
	if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic)
		{
		OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NOT_BASIC_RESPONSE);
		return NULL;
		}

	return ASN1_item_unpack(rb->response, &OCSP_BASICRESP_it);
	}

/* Return number of OCSP_SINGLERESP reponses present in
 * a basic response.
 */

int OCSP_resp_count(OCSP_BASICRESP *bs)
	{
	if (!bs) return -1;
	return sk_OCSP_SINGLERESP_num(bs->tbsResponseData->responses);
	}

/* Extract an OCSP_SINGLERESP response with a given index */

OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx)
	{
	if (!bs) return NULL;
	return sk_OCSP_SINGLERESP_value(bs->tbsResponseData->responses, idx);
	}

/* Look single response matching a given certificate ID */

int OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last)
	{
	int i;
	STACK_OF(OCSP_SINGLERESP) *sresp;
	OCSP_SINGLERESP *single;
	if (!bs) return -1;
	if (last < 0) last = 0;
	else last++;
	sresp = bs->tbsResponseData->responses;
	for (i = last; i < sk_OCSP_SINGLERESP_num(sresp); i++)
		{
		single = sk_OCSP_SINGLERESP_value(sresp, i);
		if (!OCSP_id_cmp(id, single->certId)) return i;
		}
	return -1;
	}

/* Extract status information from an OCSP_SINGLERESP structure.
 * Note: the revtime and reason values are only set if the 
 * certificate status is revoked. Returns numerical value of
 * status.
 */

int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason,
				ASN1_GENERALIZEDTIME **revtime,
				ASN1_GENERALIZEDTIME **thisupd,
				ASN1_GENERALIZEDTIME **nextupd)
	{
	int ret;
	OCSP_CERTSTATUS *cst = single->certStatus;
	if(!single) return -1;
	ret = cst->type;
	if (ret == V_OCSP_CERTSTATUS_REVOKED)
		{
		OCSP_REVOKEDINFO *rev = cst->value.revoked;
		if (revtime) *revtime = rev->revocationTime;
		if (reason) 
			{
			if(rev->revocationReason)
				*reason = ASN1_ENUMERATED_get(rev->revocationReason);
			else *reason = -1;
			}
		}
	if(thisupd) *thisupd = single->thisUpdate;
	if(nextupd) *nextupd = single->nextUpdate;
	return ret;
	}

/* This function combines the previous ones: look a certificate ID and
 * if found extract status information. Return 0 is successful.
 */

int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status,
				int *reason,
				ASN1_GENERALIZEDTIME **revtime,
				ASN1_GENERALIZEDTIME **thisupd,
				ASN1_GENERALIZEDTIME **nextupd)
	{
	int i;
	OCSP_SINGLERESP *single;
	i = OCSP_resp_find(bs, id, -1);
	/* Maybe check for multiple responses and give an error? */
	if(i < 0) return 0;
	single = OCSP_resp_get0(bs, i);
	i = OCSP_single_get0_status(single, reason, revtime, thisupd, nextupd);
	if(reason) *reason = i;
	return 1;
	}
+6 −0
Original line number Diff line number Diff line
@@ -72,6 +72,8 @@ static ERR_STRING_DATA OCSP_str_functs[]=
{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_CHECK_NONCE,0),	"OCSP_check_nonce"},
{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"},
@@ -89,6 +91,9 @@ static ERR_STRING_DATA OCSP_str_reasons[]=
{OCSP_R_FAILED_TO_READ                   ,"failed to read"},
{OCSP_R_FAILED_TO_STAT                   ,"failed to stat"},
{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_CONTENT                       ,"no content"},
{OCSP_R_NO_PUBLIC_KEY                    ,"no public key"},
@@ -99,6 +104,7 @@ static ERR_STRING_DATA OCSP_str_reasons[]=
{OCSP_R_SERVER_RESPONSE_ERROR            ,"server response error"},
{OCSP_R_SERVER_RESPONSE_PARSE_ERROR      ,"server response parse error"},
{OCSP_R_SERVER_WRITE_ERROR               ,"server write error"},
{OCSP_R_UNEXPECTED_NONCE_IN_RESPONSE     ,"unexpected nonce in response"},
{OCSP_R_UNKNOWN_NID                      ,"unknown nid"},
{OCSP_R_UNSUPPORTED_OPTION               ,"unsupported option"},
{OCSP_R_VALUE_ALREADY                    ,"value already"},
Loading