Documentation language corrections, contributed by Chris Pepper <pepper@mail.reppep...
[openssl.git] / crypto / ocsp / ocsp_vfy.c
1 /* ocsp_vfy.c */
2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
3  * project 2000.
4  */
5 /* ====================================================================
6  * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58
59 #include <openssl/ocsp.h>
60 #include <openssl/err.h>
61
62 static X509 *ocsp_find_signer(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
63                                 X509_STORE *st, unsigned long flags);
64 static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id);
65 static int ocsp_check_issuer(OCSP_BASICRESP *bs, STACK_OF(X509) *chain, unsigned long flags);
66 static int ocsp_check_ids(STACK_OF(OCSP_SINGLERESP) *sresp, OCSP_CERTID **ret);
67 static int ocsp_match_issuerid(X509 *cert, OCSP_CERTID *cid, STACK_OF(OCSP_SINGLERESP) *sresp);
68 static int ocsp_check_delegated(X509 *x, int flags);
69
70 /* Verify a basic response message */
71
72 int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
73                                 X509_STORE *st, unsigned long flags)
74         {
75         X509 *signer, *x;
76         STACK_OF(X509) *chain = NULL;
77         X509_STORE_CTX ctx;
78         int i, ret = 0;
79         signer = ocsp_find_signer(bs, certs, st, flags);
80         if (!signer)
81                 {
82                 OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND);
83                 goto end;
84                 }
85         if (!(flags & OCSP_NOSIGS))
86                 {
87                 EVP_PKEY *skey;
88                 skey = X509_get_pubkey(signer);
89                 ret = OCSP_BASICRESP_verify(bs, skey, 0);
90                 EVP_PKEY_free(skey);
91                 if(ret <= 0)
92                         {
93                         OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_SIGNATURE_FAILURE);
94                         goto end;
95                         }
96                 }
97         if (!(flags & OCSP_NOVERIFY))
98                 {
99                 if(flags & OCSP_NOCHAIN)
100                         X509_STORE_CTX_init(&ctx, st, signer, NULL);
101                 else
102                         X509_STORE_CTX_init(&ctx, st, signer, bs->certs);
103
104                 X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER);
105                 ret = X509_verify_cert(&ctx);
106                 chain = X509_STORE_CTX_get1_chain(&ctx);
107                 X509_STORE_CTX_cleanup(&ctx);
108                 if (ret <= 0)
109                         {
110                         i = X509_STORE_CTX_get_error(&ctx);     
111                         OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,OCSP_R_CERTIFICATE_VERIFY_ERROR);
112                         ERR_add_error_data(2, "Verify error:",
113                                         X509_verify_cert_error_string(i));
114                         goto end;
115                         }
116                 if(flags & OCSP_NOCHECKS)
117                         {
118                         ret = 1;
119                         goto end;
120                         }
121                 /* At this point we have a valid certificate chain
122                  * need to verify it against the OCSP issuer criteria.
123                  */
124                 ret = ocsp_check_issuer(bs, chain, flags);
125
126                 /* If fatal error or valid match then finish */
127                 if (ret != 0) goto end;
128
129                 /* Easy case: explicitly trusted. Get root CA and
130                  * check for explicit trust
131                  */
132                 if(flags & OCSP_NOEXPLICIT) goto end;
133
134                 x = sk_X509_value(chain, sk_X509_num(chain) - 1);
135                 if(X509_check_trust(x, NID_OCSP_sign, 0) != X509_TRUST_TRUSTED)
136                         {
137                         OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,OCSP_R_ROOT_CA_NOT_TRUSTED);
138                         goto end;
139                         }
140                 ret = 1;
141                 }
142                 
143
144
145         end:
146         if(chain) sk_X509_pop_free(chain, X509_free);
147         return ret;
148         }
149
150
151 static X509 *ocsp_find_signer(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
152                                 X509_STORE *st, unsigned long flags)
153         {
154         X509 *signer;
155         OCSP_RESPID *rid = bs->tbsResponseData->responderId;
156         if ((signer = ocsp_find_signer_sk(certs, rid)))
157                 return signer;
158         if(!(flags & OCSP_NOINTERN) &&
159             (signer = ocsp_find_signer_sk(bs->certs, rid)))
160                 return signer;
161         /* Maybe lookup from store if by subject name */
162
163         return NULL;
164         }
165
166
167 static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id)
168         {
169         int i;
170         unsigned char tmphash[SHA_DIGEST_LENGTH], *keyhash;
171         ASN1_BIT_STRING *key;
172         EVP_MD_CTX ctx;
173         X509 *x;
174
175         /* Easy if lookup by name */
176         if (id->type == V_OCSP_RESPID_NAME)
177                 return X509_find_by_subject(certs, id->value.byName);
178
179         /* Lookup by key hash */
180
181         /* If key hash isn't SHA1 length then forget it */
182         if (id->value.byKey->length != SHA_DIGEST_LENGTH) return NULL;
183         keyhash = id->value.byKey->data;
184         /* Calculate hash of each key and compare */
185         for (i = 0; i < sk_X509_num(certs); i++)
186                 {
187                 x = sk_X509_value(certs, i);
188                 key = x->cert_info->key->public_key;
189                 EVP_DigestInit(&ctx,EVP_sha1());
190                 EVP_DigestUpdate(&ctx,key->data, key->length);
191                 EVP_DigestFinal(&ctx,tmphash,NULL);
192                 if(!memcmp(keyhash, tmphash, SHA_DIGEST_LENGTH))
193                         return x;
194                 }
195         return NULL;
196         }
197
198
199 static int ocsp_check_issuer(OCSP_BASICRESP *bs, STACK_OF(X509) *chain, unsigned long flags)
200         {
201         STACK_OF(OCSP_SINGLERESP) *sresp;
202         X509 *signer, *sca;
203         OCSP_CERTID *caid = NULL;
204         int i;
205         sresp = bs->tbsResponseData->responses;
206
207         if (sk_X509_num(chain) <= 0)
208                 {
209                 OCSPerr(OCSP_F_OCSP_CHECK_ISSUER, OCSP_R_NO_CERTIFICATES_IN_CHAIN);
210                 return -1;
211                 }
212
213         /* See if the issuer IDs match. */
214         i = ocsp_check_ids(sresp, &caid);
215
216         /* If ID mismatch or other error then return */
217         if (i <= 0) return i;
218
219         signer = sk_X509_value(chain, 0);
220         /* Check to see if OCSP responder CA matches request CA */
221         if (sk_X509_num(chain) > 1)
222                 {
223                 sca = sk_X509_value(chain, 1);
224                 i = ocsp_match_issuerid(sca, caid, sresp);
225                 if (i < 0) return i;
226                 if (i)
227                         {
228                         /* We have a match, if extensions OK then success */
229                         if (ocsp_check_delegated(signer, flags)) return 1;
230                         return 0;
231                         }
232                 }
233
234         /* Otherwise check if OCSP request signed directly by request CA */
235         return ocsp_match_issuerid(signer, caid, sresp);
236         }
237
238
239 /* Check the issuer certificate IDs for equality. If there is a mismatch with the same
240  * algorithm then there's no point trying to match any certificates against the issuer.
241  * If the issuer IDs all match then we just need to check equality against one of them.
242  */
243         
244 static int ocsp_check_ids(STACK_OF(OCSP_SINGLERESP) *sresp, OCSP_CERTID **ret)
245         {
246         OCSP_CERTID *tmpid, *cid;
247         int i, idcount;
248
249         idcount = sk_OCSP_SINGLERESP_num(sresp);
250         if (idcount <= 0)
251                 {
252                 OCSPerr(OCSP_F_OCSP_CHECK_IDS, OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA);
253                 return -1;
254                 }
255
256         cid = sk_OCSP_SINGLERESP_value(sresp, 0)->certId;
257
258         *ret = NULL;
259
260         for (i = 1; i < idcount; i++)
261                 {
262                 tmpid = sk_OCSP_SINGLERESP_value(sresp, 0)->certId;
263                 /* Check to see if IDs match */
264                 if (OCSP_id_issuer_cmp(cid, tmpid))
265                         {
266                         /* If algoritm mismatch let caller deal with it */
267                         if (OBJ_cmp(tmpid->hashAlgorithm->algorithm,
268                                         cid->hashAlgorithm->algorithm))
269                                         return 2;
270                         /* Else mismatch */
271                         return 0;
272                         }
273                 }
274
275         /* All IDs match: only need to check one ID */
276         *ret = cid;
277         return 1;
278         }
279
280
281 static int ocsp_match_issuerid(X509 *cert, OCSP_CERTID *cid,
282                         STACK_OF(OCSP_SINGLERESP) *sresp)
283         {
284         /* If only one ID to match then do it */
285         if(cid)
286                 {
287                 const EVP_MD *dgst;
288                 EVP_MD_CTX ctx;
289                 X509_NAME *iname;
290                 ASN1_BIT_STRING *ikey;
291                 int mdlen;
292                 unsigned char md[EVP_MAX_MD_SIZE];
293                 if (!(dgst = EVP_get_digestbyobj(cid->hashAlgorithm->algorithm)))
294                         {
295                         OCSPerr(OCSP_F_OCSP_MATCH_ISSUERID, OCSP_R_UNKNOWN_MESSAGE_DIGEST);
296                         return -1;
297                         }
298
299                 mdlen = EVP_MD_size(dgst);
300                 if ((cid->issuerNameHash->length != mdlen) ||
301                    (cid->issuerKeyHash->length != mdlen))
302                         return 0;
303                 iname = X509_get_issuer_name(cert);
304                 if (!X509_NAME_digest(iname, dgst, md, NULL))
305                         return -1;
306                 if (memcmp(md, cid->issuerNameHash->data, mdlen))
307                         return 0;
308                 ikey = cert->cert_info->key->public_key;
309
310                 EVP_DigestInit(&ctx,dgst);
311                 EVP_DigestUpdate(&ctx,ikey->data, ikey->length);
312                 EVP_DigestFinal(&ctx,md,NULL);
313                 if (memcmp(md, cid->issuerKeyHash->data, mdlen))
314                         return 0;
315
316                 return 1;
317
318                 }
319         else
320                 {
321                 /* We have to match the whole lot */
322                 int i, ret;
323                 OCSP_CERTID *tmpid;
324                 for (i = 0; i < sk_OCSP_SINGLERESP_num(sresp); i++)
325                         {
326                         tmpid = sk_OCSP_SINGLERESP_value(sresp, 0)->certId;
327                         ret = ocsp_match_issuerid(cert, tmpid, NULL);
328                         if (ret <= 0) return ret;
329                         }
330                 return 1;
331                 }
332                         
333         }
334
335 static int ocsp_check_delegated(X509 *x, int flags)
336         {
337         X509_check_purpose(x, -1, 0);
338         if ((x->ex_flags & EXFLAG_XKUSAGE) &&
339             (x->ex_xkusage & XKU_OCSP_SIGN))
340                 return 1;
341         OCSPerr(OCSP_F_OCSP_CHECK_DELEGATED, OCSP_R_MISSING_OCSPSIGNING_USAGE);
342         return 0;
343         }