New OCSP response verify option OCSP_TRUSTOTHER
[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 int ocsp_find_signer(X509 **psigner, 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         ret = ocsp_find_signer(&signer, bs, certs, st, flags);
80         if (!ret)
81                 {
82                 OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND);
83                 goto end;
84                 }
85         if ((ret == 2) && (flags & OCSP_TRUSTOTHER))
86                 flags |= OCSP_NOVERIFY;
87         if (!(flags & OCSP_NOSIGS))
88                 {
89                 EVP_PKEY *skey;
90                 skey = X509_get_pubkey(signer);
91                 ret = OCSP_BASICRESP_verify(bs, skey, 0);
92                 EVP_PKEY_free(skey);
93                 if(ret <= 0)
94                         {
95                         OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_SIGNATURE_FAILURE);
96                         goto end;
97                         }
98                 }
99         if (!(flags & OCSP_NOVERIFY))
100                 {
101                 if(flags & OCSP_NOCHAIN)
102                         X509_STORE_CTX_init(&ctx, st, signer, NULL);
103                 else
104                         X509_STORE_CTX_init(&ctx, st, signer, bs->certs);
105
106                 X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER);
107                 ret = X509_verify_cert(&ctx);
108                 chain = X509_STORE_CTX_get1_chain(&ctx);
109                 X509_STORE_CTX_cleanup(&ctx);
110                 if (ret <= 0)
111                         {
112                         i = X509_STORE_CTX_get_error(&ctx);     
113                         OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,OCSP_R_CERTIFICATE_VERIFY_ERROR);
114                         ERR_add_error_data(2, "Verify error:",
115                                         X509_verify_cert_error_string(i));
116                         goto end;
117                         }
118                 if(flags & OCSP_NOCHECKS)
119                         {
120                         ret = 1;
121                         goto end;
122                         }
123                 /* At this point we have a valid certificate chain
124                  * need to verify it against the OCSP issuer criteria.
125                  */
126                 ret = ocsp_check_issuer(bs, chain, flags);
127
128                 /* If fatal error or valid match then finish */
129                 if (ret != 0) goto end;
130
131                 /* Easy case: explicitly trusted. Get root CA and
132                  * check for explicit trust
133                  */
134                 if(flags & OCSP_NOEXPLICIT) goto end;
135
136                 x = sk_X509_value(chain, sk_X509_num(chain) - 1);
137                 if(X509_check_trust(x, NID_OCSP_sign, 0) != X509_TRUST_TRUSTED)
138                         {
139                         OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,OCSP_R_ROOT_CA_NOT_TRUSTED);
140                         goto end;
141                         }
142                 ret = 1;
143                 }
144                 
145
146
147         end:
148         if(chain) sk_X509_pop_free(chain, X509_free);
149         return ret;
150         }
151
152
153 static int ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
154                                 X509_STORE *st, unsigned long flags)
155         {
156         X509 *signer;
157         OCSP_RESPID *rid = bs->tbsResponseData->responderId;
158         if ((signer = ocsp_find_signer_sk(certs, rid)))
159                 {
160                 *psigner = signer;
161                 return 2;
162                 }
163         if(!(flags & OCSP_NOINTERN) &&
164             (signer = ocsp_find_signer_sk(bs->certs, rid)))
165                 {
166                 *psigner = signer;
167                 return 1;
168                 }
169         /* Maybe lookup from store if by subject name */
170
171         *psigner = NULL;
172         return 0;
173         }
174
175
176 static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id)
177         {
178         int i;
179         unsigned char tmphash[SHA_DIGEST_LENGTH], *keyhash;
180         ASN1_BIT_STRING *key;
181         EVP_MD_CTX ctx;
182         X509 *x;
183
184         /* Easy if lookup by name */
185         if (id->type == V_OCSP_RESPID_NAME)
186                 return X509_find_by_subject(certs, id->value.byName);
187
188         /* Lookup by key hash */
189
190         /* If key hash isn't SHA1 length then forget it */
191         if (id->value.byKey->length != SHA_DIGEST_LENGTH) return NULL;
192         keyhash = id->value.byKey->data;
193         /* Calculate hash of each key and compare */
194         for (i = 0; i < sk_X509_num(certs); i++)
195                 {
196                 x = sk_X509_value(certs, i);
197                 key = x->cert_info->key->public_key;
198                 EVP_DigestInit(&ctx,EVP_sha1());
199                 EVP_DigestUpdate(&ctx,key->data, key->length);
200                 EVP_DigestFinal(&ctx,tmphash,NULL);
201                 if(!memcmp(keyhash, tmphash, SHA_DIGEST_LENGTH))
202                         return x;
203                 }
204         return NULL;
205         }
206
207
208 static int ocsp_check_issuer(OCSP_BASICRESP *bs, STACK_OF(X509) *chain, unsigned long flags)
209         {
210         STACK_OF(OCSP_SINGLERESP) *sresp;
211         X509 *signer, *sca;
212         OCSP_CERTID *caid = NULL;
213         int i;
214         sresp = bs->tbsResponseData->responses;
215
216         if (sk_X509_num(chain) <= 0)
217                 {
218                 OCSPerr(OCSP_F_OCSP_CHECK_ISSUER, OCSP_R_NO_CERTIFICATES_IN_CHAIN);
219                 return -1;
220                 }
221
222         /* See if the issuer IDs match. */
223         i = ocsp_check_ids(sresp, &caid);
224
225         /* If ID mismatch or other error then return */
226         if (i <= 0) return i;
227
228         signer = sk_X509_value(chain, 0);
229         /* Check to see if OCSP responder CA matches request CA */
230         if (sk_X509_num(chain) > 1)
231                 {
232                 sca = sk_X509_value(chain, 1);
233                 i = ocsp_match_issuerid(sca, caid, sresp);
234                 if (i < 0) return i;
235                 if (i)
236                         {
237                         /* We have a match, if extensions OK then success */
238                         if (ocsp_check_delegated(signer, flags)) return 1;
239                         return 0;
240                         }
241                 }
242
243         /* Otherwise check if OCSP request signed directly by request CA */
244         return ocsp_match_issuerid(signer, caid, sresp);
245         }
246
247
248 /* Check the issuer certificate IDs for equality. If there is a mismatch with the same
249  * algorithm then there's no point trying to match any certificates against the issuer.
250  * If the issuer IDs all match then we just need to check equality against one of them.
251  */
252         
253 static int ocsp_check_ids(STACK_OF(OCSP_SINGLERESP) *sresp, OCSP_CERTID **ret)
254         {
255         OCSP_CERTID *tmpid, *cid;
256         int i, idcount;
257
258         idcount = sk_OCSP_SINGLERESP_num(sresp);
259         if (idcount <= 0)
260                 {
261                 OCSPerr(OCSP_F_OCSP_CHECK_IDS, OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA);
262                 return -1;
263                 }
264
265         cid = sk_OCSP_SINGLERESP_value(sresp, 0)->certId;
266
267         *ret = NULL;
268
269         for (i = 1; i < idcount; i++)
270                 {
271                 tmpid = sk_OCSP_SINGLERESP_value(sresp, 0)->certId;
272                 /* Check to see if IDs match */
273                 if (OCSP_id_issuer_cmp(cid, tmpid))
274                         {
275                         /* If algoritm mismatch let caller deal with it */
276                         if (OBJ_cmp(tmpid->hashAlgorithm->algorithm,
277                                         cid->hashAlgorithm->algorithm))
278                                         return 2;
279                         /* Else mismatch */
280                         return 0;
281                         }
282                 }
283
284         /* All IDs match: only need to check one ID */
285         *ret = cid;
286         return 1;
287         }
288
289
290 static int ocsp_match_issuerid(X509 *cert, OCSP_CERTID *cid,
291                         STACK_OF(OCSP_SINGLERESP) *sresp)
292         {
293         /* If only one ID to match then do it */
294         if(cid)
295                 {
296                 const EVP_MD *dgst;
297                 EVP_MD_CTX ctx;
298                 X509_NAME *iname;
299                 ASN1_BIT_STRING *ikey;
300                 int mdlen;
301                 unsigned char md[EVP_MAX_MD_SIZE];
302                 if (!(dgst = EVP_get_digestbyobj(cid->hashAlgorithm->algorithm)))
303                         {
304                         OCSPerr(OCSP_F_OCSP_MATCH_ISSUERID, OCSP_R_UNKNOWN_MESSAGE_DIGEST);
305                         return -1;
306                         }
307
308                 mdlen = EVP_MD_size(dgst);
309                 if ((cid->issuerNameHash->length != mdlen) ||
310                    (cid->issuerKeyHash->length != mdlen))
311                         return 0;
312                 iname = X509_get_issuer_name(cert);
313                 if (!X509_NAME_digest(iname, dgst, md, NULL))
314                         return -1;
315                 if (memcmp(md, cid->issuerNameHash->data, mdlen))
316                         return 0;
317                 ikey = cert->cert_info->key->public_key;
318
319                 EVP_DigestInit(&ctx,dgst);
320                 EVP_DigestUpdate(&ctx,ikey->data, ikey->length);
321                 EVP_DigestFinal(&ctx,md,NULL);
322                 if (memcmp(md, cid->issuerKeyHash->data, mdlen))
323                         return 0;
324
325                 return 1;
326
327                 }
328         else
329                 {
330                 /* We have to match the whole lot */
331                 int i, ret;
332                 OCSP_CERTID *tmpid;
333                 for (i = 0; i < sk_OCSP_SINGLERESP_num(sresp); i++)
334                         {
335                         tmpid = sk_OCSP_SINGLERESP_value(sresp, 0)->certId;
336                         ret = ocsp_match_issuerid(cert, tmpid, NULL);
337                         if (ret <= 0) return ret;
338                         }
339                 return 1;
340                 }
341                         
342         }
343
344 static int ocsp_check_delegated(X509 *x, int flags)
345         {
346         X509_check_purpose(x, -1, 0);
347         if ((x->ex_flags & EXFLAG_XKUSAGE) &&
348             (x->ex_xkusage & XKU_OCSP_SIGN))
349                 return 1;
350         OCSPerr(OCSP_F_OCSP_CHECK_DELEGATED, OCSP_R_MISSING_OCSPSIGNING_USAGE);
351         return 0;
352         }