1 | /* |
2 | * Copyright 2006-2019 The OpenSSL Project Authors. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
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 |
8 | */ |
9 | |
10 | #include <stdio.h> |
11 | #include "internal/cryptlib.h" |
12 | #include <openssl/objects.h> |
13 | #include <openssl/ts.h> |
14 | #include <openssl/pkcs7.h> |
15 | #include "ts_local.h" |
16 | #include "crypto/ess.h" |
17 | |
18 | static int ts_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted, |
19 | X509 *signer, STACK_OF(X509) **chain); |
20 | static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si, |
21 | STACK_OF(X509) *chain); |
22 | static int ts_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert); |
23 | static int ts_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509 *cert); |
24 | static int int_ts_RESP_verify_token(TS_VERIFY_CTX *ctx, |
25 | PKCS7 *token, TS_TST_INFO *tst_info); |
26 | static int ts_check_status_info(TS_RESP *response); |
27 | static char *ts_get_status_text(STACK_OF(ASN1_UTF8STRING) *text); |
28 | static int ts_check_policy(const ASN1_OBJECT *req_oid, |
29 | const TS_TST_INFO *tst_info); |
30 | static int ts_compute_imprint(BIO *data, TS_TST_INFO *tst_info, |
31 | X509_ALGOR **md_alg, |
32 | unsigned char **imprint, unsigned *imprint_len); |
33 | static int ts_check_imprints(X509_ALGOR *algor_a, |
34 | const unsigned char *imprint_a, unsigned len_a, |
35 | TS_TST_INFO *tst_info); |
36 | static int ts_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info); |
37 | static int ts_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer); |
38 | static int ts_find_name(STACK_OF(GENERAL_NAME) *gen_names, |
39 | GENERAL_NAME *name); |
40 | static int ts_find_cert_v2(STACK_OF(ESS_CERT_ID_V2) *cert_ids, X509 *cert); |
41 | |
42 | /* |
43 | * This must be large enough to hold all values in ts_status_text (with |
44 | * comma separator) or all text fields in ts_failure_info (also with comma). |
45 | */ |
46 | #define TS_STATUS_BUF_SIZE 256 |
47 | |
48 | /* |
49 | * Local mapping between response codes and descriptions. |
50 | */ |
51 | static const char *ts_status_text[] = { |
52 | "granted" , |
53 | "grantedWithMods" , |
54 | "rejection" , |
55 | "waiting" , |
56 | "revocationWarning" , |
57 | "revocationNotification" |
58 | }; |
59 | |
60 | #define TS_STATUS_TEXT_SIZE OSSL_NELEM(ts_status_text) |
61 | |
62 | static struct { |
63 | int code; |
64 | const char *text; |
65 | } ts_failure_info[] = { |
66 | {TS_INFO_BAD_ALG, "badAlg" }, |
67 | {TS_INFO_BAD_REQUEST, "badRequest" }, |
68 | {TS_INFO_BAD_DATA_FORMAT, "badDataFormat" }, |
69 | {TS_INFO_TIME_NOT_AVAILABLE, "timeNotAvailable" }, |
70 | {TS_INFO_UNACCEPTED_POLICY, "unacceptedPolicy" }, |
71 | {TS_INFO_UNACCEPTED_EXTENSION, "unacceptedExtension" }, |
72 | {TS_INFO_ADD_INFO_NOT_AVAILABLE, "addInfoNotAvailable" }, |
73 | {TS_INFO_SYSTEM_FAILURE, "systemFailure" } |
74 | }; |
75 | |
76 | |
77 | /*- |
78 | * This function carries out the following tasks: |
79 | * - Checks if there is one and only one signer. |
80 | * - Search for the signing certificate in 'certs' and in the response. |
81 | * - Check the extended key usage and key usage fields of the signer |
82 | * certificate (done by the path validation). |
83 | * - Build and validate the certificate path. |
84 | * - Check if the certificate path meets the requirements of the |
85 | * SigningCertificate ESS signed attribute. |
86 | * - Verify the signature value. |
87 | * - Returns the signer certificate in 'signer', if 'signer' is not NULL. |
88 | */ |
89 | int TS_RESP_verify_signature(PKCS7 *token, STACK_OF(X509) *certs, |
90 | X509_STORE *store, X509 **signer_out) |
91 | { |
92 | STACK_OF(PKCS7_SIGNER_INFO) *sinfos = NULL; |
93 | PKCS7_SIGNER_INFO *si; |
94 | STACK_OF(X509) *signers = NULL; |
95 | X509 *signer; |
96 | STACK_OF(X509) *chain = NULL; |
97 | char buf[4096]; |
98 | int i, j = 0, ret = 0; |
99 | BIO *p7bio = NULL; |
100 | |
101 | /* Some sanity checks first. */ |
102 | if (!token) { |
103 | TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_INVALID_NULL_POINTER); |
104 | goto err; |
105 | } |
106 | if (!PKCS7_type_is_signed(token)) { |
107 | TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_WRONG_CONTENT_TYPE); |
108 | goto err; |
109 | } |
110 | sinfos = PKCS7_get_signer_info(token); |
111 | if (!sinfos || sk_PKCS7_SIGNER_INFO_num(sinfos) != 1) { |
112 | TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_THERE_MUST_BE_ONE_SIGNER); |
113 | goto err; |
114 | } |
115 | si = sk_PKCS7_SIGNER_INFO_value(sinfos, 0); |
116 | if (PKCS7_get_detached(token)) { |
117 | TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_NO_CONTENT); |
118 | goto err; |
119 | } |
120 | |
121 | /* |
122 | * Get hold of the signer certificate, search only internal certificates |
123 | * if it was requested. |
124 | */ |
125 | signers = PKCS7_get0_signers(token, certs, 0); |
126 | if (!signers || sk_X509_num(signers) != 1) |
127 | goto err; |
128 | signer = sk_X509_value(signers, 0); |
129 | |
130 | if (!ts_verify_cert(store, certs, signer, &chain)) |
131 | goto err; |
132 | if (!ts_check_signing_certs(si, chain)) |
133 | goto err; |
134 | p7bio = PKCS7_dataInit(token, NULL); |
135 | |
136 | /* We now have to 'read' from p7bio to calculate digests etc. */ |
137 | while ((i = BIO_read(p7bio, buf, sizeof(buf))) > 0) |
138 | continue; |
139 | |
140 | j = PKCS7_signatureVerify(p7bio, token, si, signer); |
141 | if (j <= 0) { |
142 | TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_SIGNATURE_FAILURE); |
143 | goto err; |
144 | } |
145 | |
146 | if (signer_out) { |
147 | *signer_out = signer; |
148 | X509_up_ref(signer); |
149 | } |
150 | ret = 1; |
151 | |
152 | err: |
153 | BIO_free_all(p7bio); |
154 | sk_X509_pop_free(chain, X509_free); |
155 | sk_X509_free(signers); |
156 | |
157 | return ret; |
158 | } |
159 | |
160 | /* |
161 | * The certificate chain is returned in chain. Caller is responsible for |
162 | * freeing the vector. |
163 | */ |
164 | static int ts_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted, |
165 | X509 *signer, STACK_OF(X509) **chain) |
166 | { |
167 | X509_STORE_CTX *cert_ctx = NULL; |
168 | int i; |
169 | int ret = 0; |
170 | |
171 | *chain = NULL; |
172 | cert_ctx = X509_STORE_CTX_new(); |
173 | if (cert_ctx == NULL) { |
174 | TSerr(TS_F_TS_VERIFY_CERT, ERR_R_MALLOC_FAILURE); |
175 | goto err; |
176 | } |
177 | if (!X509_STORE_CTX_init(cert_ctx, store, signer, untrusted)) |
178 | goto end; |
179 | X509_STORE_CTX_set_purpose(cert_ctx, X509_PURPOSE_TIMESTAMP_SIGN); |
180 | i = X509_verify_cert(cert_ctx); |
181 | if (i <= 0) { |
182 | int j = X509_STORE_CTX_get_error(cert_ctx); |
183 | TSerr(TS_F_TS_VERIFY_CERT, TS_R_CERTIFICATE_VERIFY_ERROR); |
184 | ERR_add_error_data(2, "Verify error:" , |
185 | X509_verify_cert_error_string(j)); |
186 | goto err; |
187 | } |
188 | *chain = X509_STORE_CTX_get1_chain(cert_ctx); |
189 | ret = 1; |
190 | goto end; |
191 | |
192 | err: |
193 | ret = 0; |
194 | |
195 | end: |
196 | X509_STORE_CTX_free(cert_ctx); |
197 | return ret; |
198 | } |
199 | |
200 | static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si, |
201 | STACK_OF(X509) *chain) |
202 | { |
203 | ESS_SIGNING_CERT *ss = ESS_SIGNING_CERT_get(si); |
204 | STACK_OF(ESS_CERT_ID) *cert_ids = NULL; |
205 | ESS_SIGNING_CERT_V2 *ssv2 = ESS_SIGNING_CERT_V2_get(si); |
206 | STACK_OF(ESS_CERT_ID_V2) *cert_ids_v2 = NULL; |
207 | X509 *cert; |
208 | int i = 0; |
209 | int ret = 0; |
210 | |
211 | if (ss != NULL) { |
212 | cert_ids = ss->cert_ids; |
213 | cert = sk_X509_value(chain, 0); |
214 | if (ts_find_cert(cert_ids, cert) != 0) |
215 | goto err; |
216 | |
217 | /* |
218 | * Check the other certificates of the chain if there are more than one |
219 | * certificate ids in cert_ids. |
220 | */ |
221 | if (sk_ESS_CERT_ID_num(cert_ids) > 1) { |
222 | for (i = 1; i < sk_X509_num(chain); ++i) { |
223 | cert = sk_X509_value(chain, i); |
224 | if (ts_find_cert(cert_ids, cert) < 0) |
225 | goto err; |
226 | } |
227 | } |
228 | } else if (ssv2 != NULL) { |
229 | cert_ids_v2 = ssv2->cert_ids; |
230 | cert = sk_X509_value(chain, 0); |
231 | if (ts_find_cert_v2(cert_ids_v2, cert) != 0) |
232 | goto err; |
233 | |
234 | /* |
235 | * Check the other certificates of the chain if there are more than one |
236 | * certificate ids in cert_ids. |
237 | */ |
238 | if (sk_ESS_CERT_ID_V2_num(cert_ids_v2) > 1) { |
239 | for (i = 1; i < sk_X509_num(chain); ++i) { |
240 | cert = sk_X509_value(chain, i); |
241 | if (ts_find_cert_v2(cert_ids_v2, cert) < 0) |
242 | goto err; |
243 | } |
244 | } |
245 | } else { |
246 | goto err; |
247 | } |
248 | |
249 | ret = 1; |
250 | err: |
251 | if (!ret) |
252 | TSerr(TS_F_TS_CHECK_SIGNING_CERTS, |
253 | TS_R_ESS_SIGNING_CERTIFICATE_ERROR); |
254 | ESS_SIGNING_CERT_free(ss); |
255 | ESS_SIGNING_CERT_V2_free(ssv2); |
256 | return ret; |
257 | } |
258 | |
259 | /* Returns < 0 if certificate is not found, certificate index otherwise. */ |
260 | static int ts_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert) |
261 | { |
262 | int i; |
263 | unsigned char cert_sha1[SHA_DIGEST_LENGTH]; |
264 | |
265 | if (!cert_ids || !cert) |
266 | return -1; |
267 | |
268 | X509_digest(cert, EVP_sha1(), cert_sha1, NULL); |
269 | |
270 | /* Recompute SHA1 hash of certificate if necessary (side effect). */ |
271 | X509_check_purpose(cert, -1, 0); |
272 | |
273 | /* Look for cert in the cert_ids vector. */ |
274 | for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i) { |
275 | ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i); |
276 | |
277 | if (cid->hash->length == SHA_DIGEST_LENGTH |
278 | && memcmp(cid->hash->data, cert_sha1, SHA_DIGEST_LENGTH) == 0) { |
279 | ESS_ISSUER_SERIAL *is = cid->issuer_serial; |
280 | if (!is || !ts_issuer_serial_cmp(is, cert)) |
281 | return i; |
282 | } |
283 | } |
284 | |
285 | return -1; |
286 | } |
287 | |
288 | /* Returns < 0 if certificate is not found, certificate index otherwise. */ |
289 | static int ts_find_cert_v2(STACK_OF(ESS_CERT_ID_V2) *cert_ids, X509 *cert) |
290 | { |
291 | int i; |
292 | unsigned char cert_digest[EVP_MAX_MD_SIZE]; |
293 | unsigned int len; |
294 | |
295 | /* Look for cert in the cert_ids vector. */ |
296 | for (i = 0; i < sk_ESS_CERT_ID_V2_num(cert_ids); ++i) { |
297 | ESS_CERT_ID_V2 *cid = sk_ESS_CERT_ID_V2_value(cert_ids, i); |
298 | const EVP_MD *md; |
299 | |
300 | if (cid->hash_alg != NULL) |
301 | md = EVP_get_digestbyobj(cid->hash_alg->algorithm); |
302 | else |
303 | md = EVP_sha256(); |
304 | |
305 | X509_digest(cert, md, cert_digest, &len); |
306 | if (cid->hash->length != (int)len) |
307 | return -1; |
308 | |
309 | if (memcmp(cid->hash->data, cert_digest, cid->hash->length) == 0) { |
310 | ESS_ISSUER_SERIAL *is = cid->issuer_serial; |
311 | |
312 | if (is == NULL || !ts_issuer_serial_cmp(is, cert)) |
313 | return i; |
314 | } |
315 | } |
316 | |
317 | return -1; |
318 | } |
319 | |
320 | static int ts_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509 *cert) |
321 | { |
322 | GENERAL_NAME *issuer; |
323 | |
324 | if (!is || !cert || sk_GENERAL_NAME_num(is->issuer) != 1) |
325 | return -1; |
326 | |
327 | issuer = sk_GENERAL_NAME_value(is->issuer, 0); |
328 | if (issuer->type != GEN_DIRNAME |
329 | || X509_NAME_cmp(issuer->d.dirn, X509_get_issuer_name(cert))) |
330 | return -1; |
331 | |
332 | if (ASN1_INTEGER_cmp(is->serial, X509_get_serialNumber(cert))) |
333 | return -1; |
334 | |
335 | return 0; |
336 | } |
337 | |
338 | /*- |
339 | * Verifies whether 'response' contains a valid response with regards |
340 | * to the settings of the context: |
341 | * - Gives an error message if the TS_TST_INFO is not present. |
342 | * - Calls _TS_RESP_verify_token to verify the token content. |
343 | */ |
344 | int TS_RESP_verify_response(TS_VERIFY_CTX *ctx, TS_RESP *response) |
345 | { |
346 | PKCS7 *token = response->token; |
347 | TS_TST_INFO *tst_info = response->tst_info; |
348 | int ret = 0; |
349 | |
350 | if (!ts_check_status_info(response)) |
351 | goto err; |
352 | if (!int_ts_RESP_verify_token(ctx, token, tst_info)) |
353 | goto err; |
354 | ret = 1; |
355 | |
356 | err: |
357 | return ret; |
358 | } |
359 | |
360 | /* |
361 | * Tries to extract a TS_TST_INFO structure from the PKCS7 token and |
362 | * calls the internal int_TS_RESP_verify_token function for verifying it. |
363 | */ |
364 | int TS_RESP_verify_token(TS_VERIFY_CTX *ctx, PKCS7 *token) |
365 | { |
366 | TS_TST_INFO *tst_info = PKCS7_to_TS_TST_INFO(token); |
367 | int ret = 0; |
368 | if (tst_info) { |
369 | ret = int_ts_RESP_verify_token(ctx, token, tst_info); |
370 | TS_TST_INFO_free(tst_info); |
371 | } |
372 | return ret; |
373 | } |
374 | |
375 | /*- |
376 | * Verifies whether the 'token' contains a valid time stamp token |
377 | * with regards to the settings of the context. Only those checks are |
378 | * carried out that are specified in the context: |
379 | * - Verifies the signature of the TS_TST_INFO. |
380 | * - Checks the version number of the response. |
381 | * - Check if the requested and returned policies math. |
382 | * - Check if the message imprints are the same. |
383 | * - Check if the nonces are the same. |
384 | * - Check if the TSA name matches the signer. |
385 | * - Check if the TSA name is the expected TSA. |
386 | */ |
387 | static int int_ts_RESP_verify_token(TS_VERIFY_CTX *ctx, |
388 | PKCS7 *token, TS_TST_INFO *tst_info) |
389 | { |
390 | X509 *signer = NULL; |
391 | GENERAL_NAME *tsa_name = tst_info->tsa; |
392 | X509_ALGOR *md_alg = NULL; |
393 | unsigned char *imprint = NULL; |
394 | unsigned imprint_len = 0; |
395 | int ret = 0; |
396 | int flags = ctx->flags; |
397 | |
398 | /* Some options require us to also check the signature */ |
399 | if (((flags & TS_VFY_SIGNER) && tsa_name != NULL) |
400 | || (flags & TS_VFY_TSA_NAME)) { |
401 | flags |= TS_VFY_SIGNATURE; |
402 | } |
403 | |
404 | if ((flags & TS_VFY_SIGNATURE) |
405 | && !TS_RESP_verify_signature(token, ctx->certs, ctx->store, &signer)) |
406 | goto err; |
407 | if ((flags & TS_VFY_VERSION) |
408 | && TS_TST_INFO_get_version(tst_info) != 1) { |
409 | TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_UNSUPPORTED_VERSION); |
410 | goto err; |
411 | } |
412 | if ((flags & TS_VFY_POLICY) |
413 | && !ts_check_policy(ctx->policy, tst_info)) |
414 | goto err; |
415 | if ((flags & TS_VFY_IMPRINT) |
416 | && !ts_check_imprints(ctx->md_alg, ctx->imprint, ctx->imprint_len, |
417 | tst_info)) |
418 | goto err; |
419 | if ((flags & TS_VFY_DATA) |
420 | && (!ts_compute_imprint(ctx->data, tst_info, |
421 | &md_alg, &imprint, &imprint_len) |
422 | || !ts_check_imprints(md_alg, imprint, imprint_len, tst_info))) |
423 | goto err; |
424 | if ((flags & TS_VFY_NONCE) |
425 | && !ts_check_nonces(ctx->nonce, tst_info)) |
426 | goto err; |
427 | if ((flags & TS_VFY_SIGNER) |
428 | && tsa_name && !ts_check_signer_name(tsa_name, signer)) { |
429 | TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_TSA_NAME_MISMATCH); |
430 | goto err; |
431 | } |
432 | if ((flags & TS_VFY_TSA_NAME) |
433 | && !ts_check_signer_name(ctx->tsa_name, signer)) { |
434 | TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_TSA_UNTRUSTED); |
435 | goto err; |
436 | } |
437 | ret = 1; |
438 | |
439 | err: |
440 | X509_free(signer); |
441 | X509_ALGOR_free(md_alg); |
442 | OPENSSL_free(imprint); |
443 | return ret; |
444 | } |
445 | |
446 | static int ts_check_status_info(TS_RESP *response) |
447 | { |
448 | TS_STATUS_INFO *info = response->status_info; |
449 | long status = ASN1_INTEGER_get(info->status); |
450 | const char *status_text = NULL; |
451 | char *embedded_status_text = NULL; |
452 | char failure_text[TS_STATUS_BUF_SIZE] = "" ; |
453 | |
454 | if (status == 0 || status == 1) |
455 | return 1; |
456 | |
457 | /* There was an error, get the description in status_text. */ |
458 | if (0 <= status && status < (long) OSSL_NELEM(ts_status_text)) |
459 | status_text = ts_status_text[status]; |
460 | else |
461 | status_text = "unknown code" ; |
462 | |
463 | if (sk_ASN1_UTF8STRING_num(info->text) > 0 |
464 | && (embedded_status_text = ts_get_status_text(info->text)) == NULL) |
465 | return 0; |
466 | |
467 | /* Fill in failure_text with the failure information. */ |
468 | if (info->failure_info) { |
469 | int i; |
470 | int first = 1; |
471 | for (i = 0; i < (int)OSSL_NELEM(ts_failure_info); ++i) { |
472 | if (ASN1_BIT_STRING_get_bit(info->failure_info, |
473 | ts_failure_info[i].code)) { |
474 | if (!first) |
475 | strcat(failure_text, "," ); |
476 | else |
477 | first = 0; |
478 | strcat(failure_text, ts_failure_info[i].text); |
479 | } |
480 | } |
481 | } |
482 | if (failure_text[0] == '\0') |
483 | strcpy(failure_text, "unspecified" ); |
484 | |
485 | TSerr(TS_F_TS_CHECK_STATUS_INFO, TS_R_NO_TIME_STAMP_TOKEN); |
486 | ERR_add_error_data(6, |
487 | "status code: " , status_text, |
488 | ", status text: " , embedded_status_text ? |
489 | embedded_status_text : "unspecified" , |
490 | ", failure codes: " , failure_text); |
491 | OPENSSL_free(embedded_status_text); |
492 | |
493 | return 0; |
494 | } |
495 | |
496 | static char *ts_get_status_text(STACK_OF(ASN1_UTF8STRING) *text) |
497 | { |
498 | int i; |
499 | int length = 0; |
500 | char *result = NULL; |
501 | char *p; |
502 | |
503 | for (i = 0; i < sk_ASN1_UTF8STRING_num(text); ++i) { |
504 | ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i); |
505 | if (ASN1_STRING_length(current) > TS_MAX_STATUS_LENGTH - length - 1) |
506 | return NULL; |
507 | length += ASN1_STRING_length(current); |
508 | length += 1; /* separator character */ |
509 | } |
510 | if ((result = OPENSSL_malloc(length)) == NULL) { |
511 | TSerr(TS_F_TS_GET_STATUS_TEXT, ERR_R_MALLOC_FAILURE); |
512 | return NULL; |
513 | } |
514 | |
515 | for (i = 0, p = result; i < sk_ASN1_UTF8STRING_num(text); ++i) { |
516 | ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i); |
517 | length = ASN1_STRING_length(current); |
518 | if (i > 0) |
519 | *p++ = '/'; |
520 | strncpy(p, (const char *)ASN1_STRING_get0_data(current), length); |
521 | p += length; |
522 | } |
523 | *p = '\0'; |
524 | |
525 | return result; |
526 | } |
527 | |
528 | static int ts_check_policy(const ASN1_OBJECT *req_oid, |
529 | const TS_TST_INFO *tst_info) |
530 | { |
531 | const ASN1_OBJECT *resp_oid = tst_info->policy_id; |
532 | |
533 | if (OBJ_cmp(req_oid, resp_oid) != 0) { |
534 | TSerr(TS_F_TS_CHECK_POLICY, TS_R_POLICY_MISMATCH); |
535 | return 0; |
536 | } |
537 | |
538 | return 1; |
539 | } |
540 | |
541 | static int ts_compute_imprint(BIO *data, TS_TST_INFO *tst_info, |
542 | X509_ALGOR **md_alg, |
543 | unsigned char **imprint, unsigned *imprint_len) |
544 | { |
545 | TS_MSG_IMPRINT *msg_imprint = tst_info->msg_imprint; |
546 | X509_ALGOR *md_alg_resp = msg_imprint->hash_algo; |
547 | const EVP_MD *md; |
548 | EVP_MD_CTX *md_ctx = NULL; |
549 | unsigned char buffer[4096]; |
550 | int length; |
551 | |
552 | *md_alg = NULL; |
553 | *imprint = NULL; |
554 | |
555 | if ((*md_alg = X509_ALGOR_dup(md_alg_resp)) == NULL) |
556 | goto err; |
557 | if ((md = EVP_get_digestbyobj((*md_alg)->algorithm)) == NULL) { |
558 | TSerr(TS_F_TS_COMPUTE_IMPRINT, TS_R_UNSUPPORTED_MD_ALGORITHM); |
559 | goto err; |
560 | } |
561 | length = EVP_MD_size(md); |
562 | if (length < 0) |
563 | goto err; |
564 | *imprint_len = length; |
565 | if ((*imprint = OPENSSL_malloc(*imprint_len)) == NULL) { |
566 | TSerr(TS_F_TS_COMPUTE_IMPRINT, ERR_R_MALLOC_FAILURE); |
567 | goto err; |
568 | } |
569 | |
570 | md_ctx = EVP_MD_CTX_new(); |
571 | if (md_ctx == NULL) { |
572 | TSerr(TS_F_TS_COMPUTE_IMPRINT, ERR_R_MALLOC_FAILURE); |
573 | goto err; |
574 | } |
575 | if (!EVP_DigestInit(md_ctx, md)) |
576 | goto err; |
577 | while ((length = BIO_read(data, buffer, sizeof(buffer))) > 0) { |
578 | if (!EVP_DigestUpdate(md_ctx, buffer, length)) |
579 | goto err; |
580 | } |
581 | if (!EVP_DigestFinal(md_ctx, *imprint, NULL)) |
582 | goto err; |
583 | EVP_MD_CTX_free(md_ctx); |
584 | |
585 | return 1; |
586 | err: |
587 | EVP_MD_CTX_free(md_ctx); |
588 | X509_ALGOR_free(*md_alg); |
589 | OPENSSL_free(*imprint); |
590 | *imprint_len = 0; |
591 | *imprint = 0; |
592 | return 0; |
593 | } |
594 | |
595 | static int ts_check_imprints(X509_ALGOR *algor_a, |
596 | const unsigned char *imprint_a, unsigned len_a, |
597 | TS_TST_INFO *tst_info) |
598 | { |
599 | TS_MSG_IMPRINT *b = tst_info->msg_imprint; |
600 | X509_ALGOR *algor_b = b->hash_algo; |
601 | int ret = 0; |
602 | |
603 | if (algor_a) { |
604 | if (OBJ_cmp(algor_a->algorithm, algor_b->algorithm)) |
605 | goto err; |
606 | |
607 | /* The parameter must be NULL in both. */ |
608 | if ((algor_a->parameter |
609 | && ASN1_TYPE_get(algor_a->parameter) != V_ASN1_NULL) |
610 | || (algor_b->parameter |
611 | && ASN1_TYPE_get(algor_b->parameter) != V_ASN1_NULL)) |
612 | goto err; |
613 | } |
614 | |
615 | ret = len_a == (unsigned)ASN1_STRING_length(b->hashed_msg) && |
616 | memcmp(imprint_a, ASN1_STRING_get0_data(b->hashed_msg), len_a) == 0; |
617 | err: |
618 | if (!ret) |
619 | TSerr(TS_F_TS_CHECK_IMPRINTS, TS_R_MESSAGE_IMPRINT_MISMATCH); |
620 | return ret; |
621 | } |
622 | |
623 | static int ts_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info) |
624 | { |
625 | const ASN1_INTEGER *b = tst_info->nonce; |
626 | |
627 | if (!b) { |
628 | TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_NOT_RETURNED); |
629 | return 0; |
630 | } |
631 | |
632 | /* No error if a nonce is returned without being requested. */ |
633 | if (ASN1_INTEGER_cmp(a, b) != 0) { |
634 | TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_MISMATCH); |
635 | return 0; |
636 | } |
637 | |
638 | return 1; |
639 | } |
640 | |
641 | /* |
642 | * Check if the specified TSA name matches either the subject or one of the |
643 | * subject alternative names of the TSA certificate. |
644 | */ |
645 | static int ts_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer) |
646 | { |
647 | STACK_OF(GENERAL_NAME) *gen_names = NULL; |
648 | int idx = -1; |
649 | int found = 0; |
650 | |
651 | if (tsa_name->type == GEN_DIRNAME |
652 | && X509_name_cmp(tsa_name->d.dirn, X509_get_subject_name(signer)) == 0) |
653 | return 1; |
654 | gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name, NULL, &idx); |
655 | while (gen_names != NULL) { |
656 | found = ts_find_name(gen_names, tsa_name) >= 0; |
657 | if (found) |
658 | break; |
659 | /* |
660 | * Get the next subject alternative name, although there should be no |
661 | * more than one. |
662 | */ |
663 | GENERAL_NAMES_free(gen_names); |
664 | gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name, NULL, &idx); |
665 | } |
666 | GENERAL_NAMES_free(gen_names); |
667 | |
668 | return found; |
669 | } |
670 | |
671 | /* Returns 1 if name is in gen_names, 0 otherwise. */ |
672 | static int ts_find_name(STACK_OF(GENERAL_NAME) *gen_names, GENERAL_NAME *name) |
673 | { |
674 | int i, found; |
675 | for (i = 0, found = 0; !found && i < sk_GENERAL_NAME_num(gen_names); ++i) { |
676 | GENERAL_NAME *current = sk_GENERAL_NAME_value(gen_names, i); |
677 | found = GENERAL_NAME_cmp(current, name) == 0; |
678 | } |
679 | return found ? i - 1 : -1; |
680 | } |
681 | |