Make OCSP cert id code tolerate a missing issuer certificate
[openssl.git] / crypto / ocsp / ocsp_cl.c
1 /* ocsp_cl.c */
2 /* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL
3  * project. */
4
5 /* History:
6    This file was transfered to Richard Levitte from CertCo by Kathy
7    Weinhold in mid-spring 2000 to be included in OpenSSL or released
8    as a patch kit. */
9
10 /* ====================================================================
11  * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  *
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer. 
19  *
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in
22  *    the documentation and/or other materials provided with the
23  *    distribution.
24  *
25  * 3. All advertising materials mentioning features or use of this
26  *    software must display the following acknowledgment:
27  *    "This product includes software developed by the OpenSSL Project
28  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
29  *
30  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
31  *    endorse or promote products derived from this software without
32  *    prior written permission. For written permission, please contact
33  *    openssl-core@openssl.org.
34  *
35  * 5. Products derived from this software may not be called "OpenSSL"
36  *    nor may "OpenSSL" appear in their names without prior written
37  *    permission of the OpenSSL Project.
38  *
39  * 6. Redistributions of any form whatsoever must retain the following
40  *    acknowledgment:
41  *    "This product includes software developed by the OpenSSL Project
42  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
43  *
44  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
45  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
48  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
51  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55  * OF THE POSSIBILITY OF SUCH DAMAGE.
56  * ====================================================================
57  *
58  * This product includes cryptographic software written by Eric Young
59  * (eay@cryptsoft.com).  This product includes software written by Tim
60  * Hudson (tjh@cryptsoft.com).
61  *
62  */
63
64 #include <stdio.h>
65 #include <cryptlib.h>
66 #include <openssl/objects.h>
67 #include <openssl/rand.h>
68 #include <openssl/x509.h>
69 #include <openssl/pem.h>
70 #include <openssl/x509v3.h>
71 #include <openssl/ocsp.h>
72
73 /* Utility functions related to sending OCSP requests and extracting
74  * relevant information from the response.
75  */
76
77 /* Add an OCSP_CERTID to an OCSP request. Return new OCSP_ONEREQ 
78  * pointer: useful if we want to add extensions.
79  */
80
81 OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid)
82         {
83         OCSP_ONEREQ *one = NULL;
84
85         if (!(one = OCSP_ONEREQ_new())) goto err;
86         if (one->reqCert) OCSP_CERTID_free(one->reqCert);
87         one->reqCert = cid;
88         if (req &&
89                 !sk_OCSP_ONEREQ_push(req->tbsRequest->requestList, one))
90                                 goto err;
91         return one;
92 err:
93         OCSP_ONEREQ_free(one);
94         return NULL;
95         }
96
97 /* Set requestorName from an X509_NAME structure */
98
99 int OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm)
100         {
101         GENERAL_NAME *gen;
102         gen = GENERAL_NAME_new();
103         if (!X509_NAME_set(&gen->d.directoryName, nm))
104                 {
105                 GENERAL_NAME_free(gen);
106                 return 0;
107                 }
108         gen->type = GEN_DIRNAME;
109         if (req->tbsRequest->requestorName)
110                 GENERAL_NAME_free(req->tbsRequest->requestorName);
111         req->tbsRequest->requestorName = gen;
112         return 1;
113         }
114         
115
116 /* Add a certificate to an OCSP request */
117
118 int OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert)
119         {
120         OCSP_SIGNATURE *sig;
121         if (!req->optionalSignature)
122                 req->optionalSignature = OCSP_SIGNATURE_new();
123         sig = req->optionalSignature;
124         if (!sig) return 0;
125         if (!cert) return 1;
126         if (!sig->certs && !(sig->certs = sk_X509_new_null()))
127                 return 0;
128
129         if(!sk_X509_push(sig->certs, cert)) return 0;
130         CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
131         return 1;
132         }
133
134 /* Sign an OCSP request set the requestorName to the subjec
135  * name of an optional signers certificate and include one
136  * or more optional certificates in the request. Behaves
137  * like PKCS7_sign().
138  */
139
140 int OCSP_request_sign(OCSP_REQUEST   *req,
141                       X509           *signer,
142                       EVP_PKEY       *key,
143                       const EVP_MD   *dgst,
144                       STACK_OF(X509) *certs,
145                       unsigned long flags)
146         {
147         int i;
148         OCSP_SIGNATURE *sig;
149         X509 *x;
150
151         if (!OCSP_request_set1_name(req, X509_get_subject_name(signer)))
152                         goto err;
153
154         if (!(req->optionalSignature = sig = OCSP_SIGNATURE_new())) goto err;
155         if (!dgst) dgst = EVP_sha1();
156         if (key)
157                 {
158                 if (!X509_check_private_key(signer, key))
159                         {
160                         OCSPerr(OCSP_F_OCSP_REQUEST_SIGN, OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
161                         goto err;
162                         }
163                 if (!OCSP_REQUEST_sign(req, key, dgst)) goto err;
164                 }
165
166         if (!(flags & OCSP_NOCERTS))
167                 {
168                 if(!OCSP_request_add1_cert(req, signer)) goto err;
169                 for (i = 0; i < sk_X509_num(certs); i++)
170                         {
171                         x = sk_X509_value(certs, i);
172                         if (!OCSP_request_add1_cert(req, x)) goto err;
173                         }
174                 }
175
176         return 1;
177 err:
178         OCSP_SIGNATURE_free(req->optionalSignature);
179         req->optionalSignature = NULL;
180         return 0;
181         }
182
183 /* Get response status */
184
185 int OCSP_response_status(OCSP_RESPONSE *resp)
186         {
187         return ASN1_ENUMERATED_get(resp->responseStatus);
188         }
189
190 /* Extract basic response from OCSP_RESPONSE or NULL if
191  * no basic response present.
192  */
193  
194
195 OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp)
196         {
197         OCSP_RESPBYTES *rb;
198         rb = resp->responseBytes;
199         if (!rb)
200                 {
201                 OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NO_RESPONSE_DATA);
202                 return NULL;
203                 }
204         if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic)
205                 {
206                 OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NOT_BASIC_RESPONSE);
207                 return NULL;
208                 }
209
210         return ASN1_item_unpack(rb->response, ASN1_ITEM_rptr(OCSP_BASICRESP));
211         }
212
213 /* Return number of OCSP_SINGLERESP reponses present in
214  * a basic response.
215  */
216
217 int OCSP_resp_count(OCSP_BASICRESP *bs)
218         {
219         if (!bs) return -1;
220         return sk_OCSP_SINGLERESP_num(bs->tbsResponseData->responses);
221         }
222
223 /* Extract an OCSP_SINGLERESP response with a given index */
224
225 OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx)
226         {
227         if (!bs) return NULL;
228         return sk_OCSP_SINGLERESP_value(bs->tbsResponseData->responses, idx);
229         }
230
231 /* Look single response matching a given certificate ID */
232
233 int OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last)
234         {
235         int i;
236         STACK_OF(OCSP_SINGLERESP) *sresp;
237         OCSP_SINGLERESP *single;
238         if (!bs) return -1;
239         if (last < 0) last = 0;
240         else last++;
241         sresp = bs->tbsResponseData->responses;
242         for (i = last; i < sk_OCSP_SINGLERESP_num(sresp); i++)
243                 {
244                 single = sk_OCSP_SINGLERESP_value(sresp, i);
245                 if (!OCSP_id_cmp(id, single->certId)) return i;
246                 }
247         return -1;
248         }
249
250 /* Extract status information from an OCSP_SINGLERESP structure.
251  * Note: the revtime and reason values are only set if the 
252  * certificate status is revoked. Returns numerical value of
253  * status.
254  */
255
256 int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason,
257                                 ASN1_GENERALIZEDTIME **revtime,
258                                 ASN1_GENERALIZEDTIME **thisupd,
259                                 ASN1_GENERALIZEDTIME **nextupd)
260         {
261         int ret;
262         OCSP_CERTSTATUS *cst = single->certStatus;
263         if(!single) return -1;
264         ret = cst->type;
265         if (ret == V_OCSP_CERTSTATUS_REVOKED)
266                 {
267                 OCSP_REVOKEDINFO *rev = cst->value.revoked;
268                 if (revtime) *revtime = rev->revocationTime;
269                 if (reason) 
270                         {
271                         if(rev->revocationReason)
272                                 *reason = ASN1_ENUMERATED_get(rev->revocationReason);
273                         else *reason = -1;
274                         }
275                 }
276         if(thisupd) *thisupd = single->thisUpdate;
277         if(nextupd) *nextupd = single->nextUpdate;
278         return ret;
279         }
280
281 /* This function combines the previous ones: look a certificate ID and
282  * if found extract status information. Return 0 is successful.
283  */
284
285 int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status,
286                                 int *reason,
287                                 ASN1_GENERALIZEDTIME **revtime,
288                                 ASN1_GENERALIZEDTIME **thisupd,
289                                 ASN1_GENERALIZEDTIME **nextupd)
290         {
291         int i;
292         OCSP_SINGLERESP *single;
293         i = OCSP_resp_find(bs, id, -1);
294         /* Maybe check for multiple responses and give an error? */
295         if(i < 0) return 0;
296         single = OCSP_resp_get0(bs, i);
297         i = OCSP_single_get0_status(single, reason, revtime, thisupd, nextupd);
298         if(status) *status = i;
299         return 1;
300         }
301
302