]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
04940147 | 2 | * Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved. |
02e4fbed | 3 | * |
0c496700 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
02e4fbed DSH |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
b39fc560 | 11 | #include "internal/cryptlib.h" |
02e4fbed | 12 | #include <openssl/objects.h> |
02e4fbed DSH |
13 | #include <openssl/x509.h> |
14 | #include <openssl/pem.h> | |
15 | #include <openssl/x509v3.h> | |
16 | #include <openssl/ocsp.h> | |
706457b7 | 17 | #include "ocsp_local.h" |
02e4fbed | 18 | |
0f113f3e MC |
19 | /* |
20 | * Utility functions related to sending OCSP responses and extracting | |
02e4fbed DSH |
21 | * relevant information from the request. |
22 | */ | |
23 | ||
24 | int OCSP_request_onereq_count(OCSP_REQUEST *req) | |
0f113f3e | 25 | { |
a332635e | 26 | return sk_OCSP_ONEREQ_num(req->tbsRequest.requestList); |
0f113f3e | 27 | } |
02e4fbed DSH |
28 | |
29 | OCSP_ONEREQ *OCSP_request_onereq_get0(OCSP_REQUEST *req, int i) | |
0f113f3e | 30 | { |
a332635e | 31 | return sk_OCSP_ONEREQ_value(req->tbsRequest.requestList, i); |
0f113f3e | 32 | } |
02e4fbed DSH |
33 | |
34 | OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *one) | |
0f113f3e MC |
35 | { |
36 | return one->reqCert; | |
37 | } | |
02e4fbed DSH |
38 | |
39 | int OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd, | |
0f113f3e MC |
40 | ASN1_OCTET_STRING **pikeyHash, |
41 | ASN1_INTEGER **pserial, OCSP_CERTID *cid) | |
42 | { | |
43 | if (!cid) | |
44 | return 0; | |
45 | if (pmd) | |
a332635e | 46 | *pmd = cid->hashAlgorithm.algorithm; |
0f113f3e | 47 | if (piNameHash) |
af170194 | 48 | *piNameHash = &cid->issuerNameHash; |
0f113f3e | 49 | if (pikeyHash) |
af170194 | 50 | *pikeyHash = &cid->issuerKeyHash; |
0f113f3e | 51 | if (pserial) |
af170194 | 52 | *pserial = &cid->serialNumber; |
0f113f3e MC |
53 | return 1; |
54 | } | |
02e4fbed | 55 | |
fafc7f98 | 56 | int OCSP_request_is_signed(OCSP_REQUEST *req) |
0f113f3e MC |
57 | { |
58 | if (req->optionalSignature) | |
59 | return 1; | |
60 | return 0; | |
61 | } | |
fafc7f98 | 62 | |
02e4fbed DSH |
63 | /* Create an OCSP response and encode an optional basic response */ |
64 | OCSP_RESPONSE *OCSP_response_create(int status, OCSP_BASICRESP *bs) | |
0f113f3e MC |
65 | { |
66 | OCSP_RESPONSE *rsp = NULL; | |
67 | ||
75ebbd9a | 68 | if ((rsp = OCSP_RESPONSE_new()) == NULL) |
0f113f3e MC |
69 | goto err; |
70 | if (!(ASN1_ENUMERATED_set(rsp->responseStatus, status))) | |
71 | goto err; | |
72 | if (!bs) | |
73 | return rsp; | |
75ebbd9a | 74 | if ((rsp->responseBytes = OCSP_RESPBYTES_new()) == NULL) |
0f113f3e MC |
75 | goto err; |
76 | rsp->responseBytes->responseType = OBJ_nid2obj(NID_id_pkix_OCSP_basic); | |
77 | if (!ASN1_item_pack | |
78 | (bs, ASN1_ITEM_rptr(OCSP_BASICRESP), &rsp->responseBytes->response)) | |
79 | goto err; | |
80 | return rsp; | |
81 | err: | |
25aaa98a | 82 | OCSP_RESPONSE_free(rsp); |
0f113f3e MC |
83 | return NULL; |
84 | } | |
02e4fbed DSH |
85 | |
86 | OCSP_SINGLERESP *OCSP_basic_add1_status(OCSP_BASICRESP *rsp, | |
0f113f3e MC |
87 | OCSP_CERTID *cid, |
88 | int status, int reason, | |
89 | ASN1_TIME *revtime, | |
90 | ASN1_TIME *thisupd, | |
91 | ASN1_TIME *nextupd) | |
92 | { | |
93 | OCSP_SINGLERESP *single = NULL; | |
94 | OCSP_CERTSTATUS *cs; | |
95 | OCSP_REVOKEDINFO *ri; | |
96 | ||
a332635e DSH |
97 | if (rsp->tbsResponseData.responses == NULL |
98 | && (rsp->tbsResponseData.responses | |
75ebbd9a | 99 | = sk_OCSP_SINGLERESP_new_null()) == NULL) |
0f113f3e MC |
100 | goto err; |
101 | ||
75ebbd9a | 102 | if ((single = OCSP_SINGLERESP_new()) == NULL) |
0f113f3e MC |
103 | goto err; |
104 | ||
105 | if (!ASN1_TIME_to_generalizedtime(thisupd, &single->thisUpdate)) | |
106 | goto err; | |
107 | if (nextupd && | |
108 | !ASN1_TIME_to_generalizedtime(nextupd, &single->nextUpdate)) | |
109 | goto err; | |
110 | ||
111 | OCSP_CERTID_free(single->certId); | |
112 | ||
75ebbd9a | 113 | if ((single->certId = OCSP_CERTID_dup(cid)) == NULL) |
0f113f3e MC |
114 | goto err; |
115 | ||
116 | cs = single->certStatus; | |
117 | switch (cs->type = status) { | |
118 | case V_OCSP_CERTSTATUS_REVOKED: | |
119 | if (!revtime) { | |
120 | OCSPerr(OCSP_F_OCSP_BASIC_ADD1_STATUS, OCSP_R_NO_REVOKED_TIME); | |
121 | goto err; | |
122 | } | |
75ebbd9a | 123 | if ((cs->value.revoked = ri = OCSP_REVOKEDINFO_new()) == NULL) |
0f113f3e MC |
124 | goto err; |
125 | if (!ASN1_TIME_to_generalizedtime(revtime, &ri->revocationTime)) | |
126 | goto err; | |
127 | if (reason != OCSP_REVOKED_STATUS_NOSTATUS) { | |
75ebbd9a | 128 | if ((ri->revocationReason = ASN1_ENUMERATED_new()) == NULL) |
0f113f3e MC |
129 | goto err; |
130 | if (!(ASN1_ENUMERATED_set(ri->revocationReason, reason))) | |
131 | goto err; | |
132 | } | |
133 | break; | |
134 | ||
135 | case V_OCSP_CERTSTATUS_GOOD: | |
90945fa3 MC |
136 | if ((cs->value.good = ASN1_NULL_new()) == NULL) |
137 | goto err; | |
0f113f3e MC |
138 | break; |
139 | ||
140 | case V_OCSP_CERTSTATUS_UNKNOWN: | |
90945fa3 MC |
141 | if ((cs->value.unknown = ASN1_NULL_new()) == NULL) |
142 | goto err; | |
0f113f3e MC |
143 | break; |
144 | ||
145 | default: | |
146 | goto err; | |
147 | ||
148 | } | |
a332635e | 149 | if (!(sk_OCSP_SINGLERESP_push(rsp->tbsResponseData.responses, single))) |
0f113f3e MC |
150 | goto err; |
151 | return single; | |
152 | err: | |
153 | OCSP_SINGLERESP_free(single); | |
154 | return NULL; | |
155 | } | |
02e4fbed DSH |
156 | |
157 | /* Add a certificate to an OCSP request */ | |
158 | ||
159 | int OCSP_basic_add1_cert(OCSP_BASICRESP *resp, X509 *cert) | |
0f113f3e | 160 | { |
75ebbd9a RS |
161 | if (resp->certs == NULL |
162 | && (resp->certs = sk_X509_new_null()) == NULL) | |
0f113f3e MC |
163 | return 0; |
164 | ||
165 | if (!sk_X509_push(resp->certs, cert)) | |
166 | return 0; | |
05f0fb9f | 167 | X509_up_ref(cert); |
0f113f3e MC |
168 | return 1; |
169 | } | |
170 | ||
04940147 DC |
171 | /* |
172 | * Sign an OCSP response using the parameters contained in the digest context, | |
173 | * set the responderID to the subject name in the signer's certificate, and | |
174 | * include one or more optional certificates in the response. | |
175 | */ | |
176 | ||
b4dd21a7 DC |
177 | int OCSP_basic_sign_ctx(OCSP_BASICRESP *brsp, |
178 | X509 *signer, EVP_MD_CTX *ctx, | |
0f113f3e MC |
179 | STACK_OF(X509) *certs, unsigned long flags) |
180 | { | |
181 | int i; | |
182 | OCSP_RESPID *rid; | |
04940147 DC |
183 | EVP_PKEY *pkey; |
184 | ||
185 | if (ctx == NULL || EVP_MD_CTX_pkey_ctx(ctx) == NULL) { | |
186 | OCSPerr(OCSP_F_OCSP_BASIC_SIGN_CTX, OCSP_R_NO_SIGNER_KEY); | |
187 | goto err; | |
188 | } | |
0f113f3e | 189 | |
04940147 DC |
190 | pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx)); |
191 | if (pkey == NULL || !X509_check_private_key(signer, pkey)) { | |
b4dd21a7 | 192 | OCSPerr(OCSP_F_OCSP_BASIC_SIGN_CTX, |
0f113f3e MC |
193 | OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); |
194 | goto err; | |
195 | } | |
196 | ||
197 | if (!(flags & OCSP_NOCERTS)) { | |
198 | if (!OCSP_basic_add1_cert(brsp, signer)) | |
199 | goto err; | |
200 | for (i = 0; i < sk_X509_num(certs); i++) { | |
201 | X509 *tmpcert = sk_X509_value(certs, i); | |
202 | if (!OCSP_basic_add1_cert(brsp, tmpcert)) | |
203 | goto err; | |
204 | } | |
205 | } | |
206 | ||
a332635e | 207 | rid = &brsp->tbsResponseData.responderId; |
0f113f3e | 208 | if (flags & OCSP_RESPID_KEY) { |
e12c0beb | 209 | if (!OCSP_RESPID_set_by_key(rid, signer)) |
0f113f3e | 210 | goto err; |
e12c0beb MC |
211 | } else if (!OCSP_RESPID_set_by_name(rid, signer)) { |
212 | goto err; | |
0f113f3e MC |
213 | } |
214 | ||
215 | if (!(flags & OCSP_NOTIME) && | |
a332635e | 216 | !X509_gmtime_adj(brsp->tbsResponseData.producedAt, 0)) |
0f113f3e MC |
217 | goto err; |
218 | ||
219 | /* | |
220 | * Right now, I think that not doing double hashing is the right thing. | |
221 | * -- Richard Levitte | |
222 | */ | |
223 | ||
b4dd21a7 | 224 | if (!OCSP_BASICRESP_sign_ctx(brsp, ctx, 0)) |
0f113f3e MC |
225 | goto err; |
226 | ||
227 | return 1; | |
228 | err: | |
229 | return 0; | |
230 | } | |
e12c0beb | 231 | |
b4dd21a7 DC |
232 | int OCSP_basic_sign(OCSP_BASICRESP *brsp, |
233 | X509 *signer, EVP_PKEY *key, const EVP_MD *dgst, | |
234 | STACK_OF(X509) *certs, unsigned long flags) | |
235 | { | |
236 | EVP_MD_CTX *ctx = EVP_MD_CTX_new(); | |
237 | EVP_PKEY_CTX *pkctx = NULL; | |
238 | int i; | |
239 | ||
a8d3dbe1 P |
240 | if (ctx == NULL) |
241 | return 0; | |
242 | ||
b4dd21a7 DC |
243 | if (!EVP_DigestSignInit(ctx, &pkctx, dgst, NULL, key)) { |
244 | EVP_MD_CTX_free(ctx); | |
cace14b8 | 245 | return 0; |
b4dd21a7 DC |
246 | } |
247 | i = OCSP_basic_sign_ctx(brsp, signer, ctx, certs, flags); | |
248 | EVP_MD_CTX_free(ctx); | |
249 | return i; | |
250 | } | |
251 | ||
e12c0beb MC |
252 | int OCSP_RESPID_set_by_name(OCSP_RESPID *respid, X509 *cert) |
253 | { | |
254 | if (!X509_NAME_set(&respid->value.byName, X509_get_subject_name(cert))) | |
255 | return 0; | |
256 | ||
257 | respid->type = V_OCSP_RESPID_NAME; | |
258 | ||
259 | return 1; | |
260 | } | |
261 | ||
262 | int OCSP_RESPID_set_by_key(OCSP_RESPID *respid, X509 *cert) | |
263 | { | |
264 | ASN1_OCTET_STRING *byKey = NULL; | |
265 | unsigned char md[SHA_DIGEST_LENGTH]; | |
266 | ||
267 | /* RFC2560 requires SHA1 */ | |
268 | if (!X509_pubkey_digest(cert, EVP_sha1(), md, NULL)) | |
269 | return 0; | |
270 | ||
271 | byKey = ASN1_OCTET_STRING_new(); | |
272 | if (byKey == NULL) | |
273 | return 0; | |
274 | ||
a671b3e6 | 275 | if (!(ASN1_OCTET_STRING_set(byKey, md, SHA_DIGEST_LENGTH))) { |
e12c0beb MC |
276 | ASN1_OCTET_STRING_free(byKey); |
277 | return 0; | |
278 | } | |
279 | ||
280 | respid->type = V_OCSP_RESPID_KEY; | |
281 | respid->value.byKey = byKey; | |
282 | ||
283 | return 1; | |
284 | } | |
a671b3e6 MC |
285 | |
286 | int OCSP_RESPID_match(OCSP_RESPID *respid, X509 *cert) | |
287 | { | |
288 | if (respid->type == V_OCSP_RESPID_KEY) { | |
289 | unsigned char md[SHA_DIGEST_LENGTH]; | |
290 | ||
291 | if (respid->value.byKey == NULL) | |
292 | return 0; | |
293 | ||
294 | /* RFC2560 requires SHA1 */ | |
295 | if (!X509_pubkey_digest(cert, EVP_sha1(), md, NULL)) | |
296 | return 0; | |
297 | ||
298 | return (ASN1_STRING_length(respid->value.byKey) == SHA_DIGEST_LENGTH) | |
299 | && (memcmp(ASN1_STRING_get0_data(respid->value.byKey), md, | |
300 | SHA_DIGEST_LENGTH) == 0); | |
f479eab2 | 301 | } else if (respid->type == V_OCSP_RESPID_NAME) { |
a671b3e6 MC |
302 | if (respid->value.byName == NULL) |
303 | return 0; | |
304 | ||
305 | return X509_NAME_cmp(respid->value.byName, | |
306 | X509_get_subject_name(cert)) == 0; | |
307 | } | |
308 | ||
309 | return 0; | |
310 | } |