3e73e3bb17ed649cc717cb0ad25e3d0f92ebaa3c
[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 (signer &&
152                 !OCSP_request_set1_name(req, X509_get_subject_name(signer)))
153                         goto err;
154
155         if (!(req->optionalSignature = sig = OCSP_SIGNATURE_new())) goto err;
156         if (!dgst) dgst = EVP_sha1();
157         if (key && !OCSP_REQUEST_sign(req, key, dgst)) goto err;
158         if (!(flags & OCSP_NOCERTS))
159                 {
160                 if (!OCSP_request_add1_cert(req, signer)) goto err;
161                 for (i = 0; i < sk_X509_num(certs); i++)
162                         {
163                         x = sk_X509_value(certs, i);
164                         if (!OCSP_request_add1_cert(req, x)) goto err;
165                         }
166                 }
167         return 1;
168 err:
169         OCSP_SIGNATURE_free(req->optionalSignature);
170         req->optionalSignature = NULL;
171         return 0;
172         }
173
174 /* Get response status */
175
176 int OCSP_response_status(OCSP_RESPONSE *resp)
177         {
178         return ASN1_ENUMERATED_get(resp->responseStatus);
179         }
180
181 /* Extract basic response from OCSP_RESPONSE or NULL if
182  * no basic response present.
183  */
184  
185
186 OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp)
187         {
188         OCSP_RESPBYTES *rb;
189         rb = resp->responseBytes;
190         if (!rb)
191                 {
192                 OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NO_RESPONSE_DATA);
193                 return NULL;
194                 }
195         if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic)
196                 {
197                 OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NOT_BASIC_RESPONSE);
198                 return NULL;
199                 }
200
201         return ASN1_item_unpack(rb->response, &OCSP_BASICRESP_it);
202         }
203
204 /* Return number of OCSP_SINGLERESP reponses present in
205  * a basic response.
206  */
207
208 int OCSP_resp_count(OCSP_BASICRESP *bs)
209         {
210         if (!bs) return -1;
211         return sk_OCSP_SINGLERESP_num(bs->tbsResponseData->responses);
212         }
213
214 /* Extract an OCSP_SINGLERESP response with a given index */
215
216 OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx)
217         {
218         if (!bs) return NULL;
219         return sk_OCSP_SINGLERESP_value(bs->tbsResponseData->responses, idx);
220         }
221
222 /* Look single response matching a given certificate ID */
223
224 int OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last)
225         {
226         int i;
227         STACK_OF(OCSP_SINGLERESP) *sresp;
228         OCSP_SINGLERESP *single;
229         if (!bs) return -1;
230         if (last < 0) last = 0;
231         else last++;
232         sresp = bs->tbsResponseData->responses;
233         for (i = last; i < sk_OCSP_SINGLERESP_num(sresp); i++)
234                 {
235                 single = sk_OCSP_SINGLERESP_value(sresp, i);
236                 if (!OCSP_id_cmp(id, single->certId)) return i;
237                 }
238         return -1;
239         }
240
241 /* Extract status information from an OCSP_SINGLERESP structure.
242  * Note: the revtime and reason values are only set if the 
243  * certificate status is revoked. Returns numerical value of
244  * status.
245  */
246
247 int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason,
248                                 ASN1_GENERALIZEDTIME **revtime,
249                                 ASN1_GENERALIZEDTIME **thisupd,
250                                 ASN1_GENERALIZEDTIME **nextupd)
251         {
252         int ret;
253         OCSP_CERTSTATUS *cst = single->certStatus;
254         if(!single) return -1;
255         ret = cst->type;
256         if (ret == V_OCSP_CERTSTATUS_REVOKED)
257                 {
258                 OCSP_REVOKEDINFO *rev = cst->value.revoked;
259                 if (revtime) *revtime = rev->revocationTime;
260                 if (reason) 
261                         {
262                         if(rev->revocationReason)
263                                 *reason = ASN1_ENUMERATED_get(rev->revocationReason);
264                         else *reason = -1;
265                         }
266                 }
267         if(thisupd) *thisupd = single->thisUpdate;
268         if(nextupd) *nextupd = single->nextUpdate;
269         return ret;
270         }
271
272 /* This function combines the previous ones: look a certificate ID and
273  * if found extract status information. Return 0 is successful.
274  */
275
276 int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status,
277                                 int *reason,
278                                 ASN1_GENERALIZEDTIME **revtime,
279                                 ASN1_GENERALIZEDTIME **thisupd,
280                                 ASN1_GENERALIZEDTIME **nextupd)
281         {
282         int i;
283         OCSP_SINGLERESP *single;
284         i = OCSP_resp_find(bs, id, -1);
285         /* Maybe check for multiple responses and give an error? */
286         if(i < 0) return 0;
287         single = OCSP_resp_get0(bs, i);
288         i = OCSP_single_get0_status(single, reason, revtime, thisupd, nextupd);
289         if(reason) *reason = i;
290         return 1;
291         }