1238384Sjkim/* crypto/ts/ts_resp_verify.c */ 2296341Sdelphij/* 3296341Sdelphij * Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL project 4296341Sdelphij * 2002. 5238384Sjkim */ 6238384Sjkim/* ==================================================================== 7238384Sjkim * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 8238384Sjkim * 9238384Sjkim * Redistribution and use in source and binary forms, with or without 10238384Sjkim * modification, are permitted provided that the following conditions 11238384Sjkim * are met: 12238384Sjkim * 13238384Sjkim * 1. Redistributions of source code must retain the above copyright 14296341Sdelphij * notice, this list of conditions and the following disclaimer. 15238384Sjkim * 16238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 17238384Sjkim * notice, this list of conditions and the following disclaimer in 18238384Sjkim * the documentation and/or other materials provided with the 19238384Sjkim * distribution. 20238384Sjkim * 21238384Sjkim * 3. All advertising materials mentioning features or use of this 22238384Sjkim * software must display the following acknowledgment: 23238384Sjkim * "This product includes software developed by the OpenSSL Project 24238384Sjkim * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25238384Sjkim * 26238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27238384Sjkim * endorse or promote products derived from this software without 28238384Sjkim * prior written permission. For written permission, please contact 29238384Sjkim * licensing@OpenSSL.org. 30238384Sjkim * 31238384Sjkim * 5. Products derived from this software may not be called "OpenSSL" 32238384Sjkim * nor may "OpenSSL" appear in their names without prior written 33238384Sjkim * permission of the OpenSSL Project. 34238384Sjkim * 35238384Sjkim * 6. Redistributions of any form whatsoever must retain the following 36238384Sjkim * acknowledgment: 37238384Sjkim * "This product includes software developed by the OpenSSL Project 38238384Sjkim * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39238384Sjkim * 40238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43238384Sjkim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE. 52238384Sjkim * ==================================================================== 53238384Sjkim * 54238384Sjkim * This product includes cryptographic software written by Eric Young 55238384Sjkim * (eay@cryptsoft.com). This product includes software written by Tim 56238384Sjkim * Hudson (tjh@cryptsoft.com). 57238384Sjkim * 58238384Sjkim */ 59238384Sjkim 60238384Sjkim#include <stdio.h> 61238384Sjkim#include "cryptlib.h" 62238384Sjkim#include <openssl/objects.h> 63238384Sjkim#include <openssl/ts.h> 64238384Sjkim#include <openssl/pkcs7.h> 65238384Sjkim 66238384Sjkim/* Private function declarations. */ 67238384Sjkim 68238384Sjkimstatic int TS_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted, 69296341Sdelphij X509 *signer, STACK_OF(X509) **chain); 70296341Sdelphijstatic int TS_check_signing_certs(PKCS7_SIGNER_INFO *si, 71296341Sdelphij STACK_OF(X509) *chain); 72238384Sjkimstatic ESS_SIGNING_CERT *ESS_get_signing_cert(PKCS7_SIGNER_INFO *si); 73238384Sjkimstatic int TS_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert); 74238384Sjkimstatic int TS_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509_CINF *cinfo); 75296341Sdelphijstatic int int_TS_RESP_verify_token(TS_VERIFY_CTX *ctx, 76296341Sdelphij PKCS7 *token, TS_TST_INFO *tst_info); 77238384Sjkimstatic int TS_check_status_info(TS_RESP *response); 78238384Sjkimstatic char *TS_get_status_text(STACK_OF(ASN1_UTF8STRING) *text); 79238384Sjkimstatic int TS_check_policy(ASN1_OBJECT *req_oid, TS_TST_INFO *tst_info); 80238384Sjkimstatic int TS_compute_imprint(BIO *data, TS_TST_INFO *tst_info, 81296341Sdelphij X509_ALGOR **md_alg, 82296341Sdelphij unsigned char **imprint, unsigned *imprint_len); 83296341Sdelphijstatic int TS_check_imprints(X509_ALGOR *algor_a, 84296341Sdelphij unsigned char *imprint_a, unsigned len_a, 85296341Sdelphij TS_TST_INFO *tst_info); 86238384Sjkimstatic int TS_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info); 87238384Sjkimstatic int TS_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer); 88296341Sdelphijstatic int TS_find_name(STACK_OF(GENERAL_NAME) *gen_names, 89296341Sdelphij GENERAL_NAME *name); 90238384Sjkim 91238384Sjkim/* 92238384Sjkim * Local mapping between response codes and descriptions. 93296341Sdelphij * Don't forget to change TS_STATUS_BUF_SIZE when modifying 94238384Sjkim * the elements of this array. 95238384Sjkim */ 96296341Sdelphijstatic const char *TS_status_text[] = { "granted", 97296341Sdelphij "grantedWithMods", 98296341Sdelphij "rejection", 99296341Sdelphij "waiting", 100296341Sdelphij "revocationWarning", 101296341Sdelphij "revocationNotification" 102296341Sdelphij}; 103238384Sjkim 104296341Sdelphij#define TS_STATUS_TEXT_SIZE (sizeof(TS_status_text)/sizeof(*TS_status_text)) 105238384Sjkim 106238384Sjkim/* 107238384Sjkim * This must be greater or equal to the sum of the strings in TS_status_text 108238384Sjkim * plus the number of its elements. 109238384Sjkim */ 110296341Sdelphij#define TS_STATUS_BUF_SIZE 256 111238384Sjkim 112296341Sdelphijstatic struct { 113296341Sdelphij int code; 114296341Sdelphij const char *text; 115296341Sdelphij} TS_failure_info[] = { 116296341Sdelphij { 117296341Sdelphij TS_INFO_BAD_ALG, "badAlg" 118296341Sdelphij }, 119296341Sdelphij { 120296341Sdelphij TS_INFO_BAD_REQUEST, "badRequest" 121296341Sdelphij }, 122296341Sdelphij { 123296341Sdelphij TS_INFO_BAD_DATA_FORMAT, "badDataFormat" 124296341Sdelphij }, 125296341Sdelphij { 126296341Sdelphij TS_INFO_TIME_NOT_AVAILABLE, "timeNotAvailable" 127296341Sdelphij }, 128296341Sdelphij { 129296341Sdelphij TS_INFO_UNACCEPTED_POLICY, "unacceptedPolicy" 130296341Sdelphij }, 131296341Sdelphij { 132296341Sdelphij TS_INFO_UNACCEPTED_EXTENSION, "unacceptedExtension" 133296341Sdelphij }, 134296341Sdelphij { 135296341Sdelphij TS_INFO_ADD_INFO_NOT_AVAILABLE, "addInfoNotAvailable" 136296341Sdelphij }, 137296341Sdelphij { 138296341Sdelphij TS_INFO_SYSTEM_FAILURE, "systemFailure" 139296341Sdelphij } 140296341Sdelphij}; 141238384Sjkim 142296341Sdelphij#define TS_FAILURE_INFO_SIZE (sizeof(TS_failure_info) / \ 143296341Sdelphij sizeof(*TS_failure_info)) 144238384Sjkim 145238384Sjkim/* Functions for verifying a signed TS_TST_INFO structure. */ 146238384Sjkim 147296341Sdelphij/*- 148238384Sjkim * This function carries out the following tasks: 149296341Sdelphij * - Checks if there is one and only one signer. 150296341Sdelphij * - Search for the signing certificate in 'certs' and in the response. 151296341Sdelphij * - Check the extended key usage and key usage fields of the signer 152296341Sdelphij * certificate (done by the path validation). 153296341Sdelphij * - Build and validate the certificate path. 154296341Sdelphij * - Check if the certificate path meets the requirements of the 155296341Sdelphij * SigningCertificate ESS signed attribute. 156296341Sdelphij * - Verify the signature value. 157296341Sdelphij * - Returns the signer certificate in 'signer', if 'signer' is not NULL. 158238384Sjkim */ 159238384Sjkimint TS_RESP_verify_signature(PKCS7 *token, STACK_OF(X509) *certs, 160296341Sdelphij X509_STORE *store, X509 **signer_out) 161296341Sdelphij{ 162296341Sdelphij STACK_OF(PKCS7_SIGNER_INFO) *sinfos = NULL; 163296341Sdelphij PKCS7_SIGNER_INFO *si; 164296341Sdelphij STACK_OF(X509) *signers = NULL; 165296341Sdelphij X509 *signer; 166296341Sdelphij STACK_OF(X509) *chain = NULL; 167296341Sdelphij char buf[4096]; 168296341Sdelphij int i, j = 0, ret = 0; 169296341Sdelphij BIO *p7bio = NULL; 170238384Sjkim 171296341Sdelphij /* Some sanity checks first. */ 172296341Sdelphij if (!token) { 173296341Sdelphij TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_INVALID_NULL_POINTER); 174296341Sdelphij goto err; 175296341Sdelphij } 176238384Sjkim 177296341Sdelphij /* Check for the correct content type */ 178296341Sdelphij if (!PKCS7_type_is_signed(token)) { 179296341Sdelphij TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_WRONG_CONTENT_TYPE); 180296341Sdelphij goto err; 181296341Sdelphij } 182238384Sjkim 183296341Sdelphij /* Check if there is one and only one signer. */ 184296341Sdelphij sinfos = PKCS7_get_signer_info(token); 185296341Sdelphij if (!sinfos || sk_PKCS7_SIGNER_INFO_num(sinfos) != 1) { 186296341Sdelphij TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_THERE_MUST_BE_ONE_SIGNER); 187296341Sdelphij goto err; 188296341Sdelphij } 189296341Sdelphij si = sk_PKCS7_SIGNER_INFO_value(sinfos, 0); 190238384Sjkim 191296341Sdelphij /* Check for no content: no data to verify signature. */ 192296341Sdelphij if (PKCS7_get_detached(token)) { 193296341Sdelphij TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_NO_CONTENT); 194296341Sdelphij goto err; 195296341Sdelphij } 196238384Sjkim 197296341Sdelphij /* 198296341Sdelphij * Get hold of the signer certificate, search only internal certificates 199296341Sdelphij * if it was requested. 200296341Sdelphij */ 201296341Sdelphij signers = PKCS7_get0_signers(token, certs, 0); 202296341Sdelphij if (!signers || sk_X509_num(signers) != 1) 203296341Sdelphij goto err; 204296341Sdelphij signer = sk_X509_value(signers, 0); 205238384Sjkim 206296341Sdelphij /* Now verify the certificate. */ 207296341Sdelphij if (!TS_verify_cert(store, certs, signer, &chain)) 208296341Sdelphij goto err; 209238384Sjkim 210296341Sdelphij /* 211296341Sdelphij * Check if the signer certificate is consistent with the ESS extension. 212296341Sdelphij */ 213296341Sdelphij if (!TS_check_signing_certs(si, chain)) 214296341Sdelphij goto err; 215238384Sjkim 216296341Sdelphij /* Creating the message digest. */ 217296341Sdelphij p7bio = PKCS7_dataInit(token, NULL); 218238384Sjkim 219296341Sdelphij /* We now have to 'read' from p7bio to calculate digests etc. */ 220296341Sdelphij while ((i = BIO_read(p7bio, buf, sizeof(buf))) > 0) ; 221238384Sjkim 222296341Sdelphij /* Verifying the signature. */ 223296341Sdelphij j = PKCS7_signatureVerify(p7bio, token, si, signer); 224296341Sdelphij if (j <= 0) { 225296341Sdelphij TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_SIGNATURE_FAILURE); 226296341Sdelphij goto err; 227296341Sdelphij } 228238384Sjkim 229296341Sdelphij /* Return the signer certificate if needed. */ 230296341Sdelphij if (signer_out) { 231296341Sdelphij *signer_out = signer; 232296341Sdelphij CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509); 233296341Sdelphij } 234238384Sjkim 235296341Sdelphij ret = 1; 236296341Sdelphij 237238384Sjkim err: 238296341Sdelphij BIO_free_all(p7bio); 239296341Sdelphij sk_X509_pop_free(chain, X509_free); 240296341Sdelphij sk_X509_free(signers); 241238384Sjkim 242296341Sdelphij return ret; 243296341Sdelphij} 244238384Sjkim 245238384Sjkim/* 246238384Sjkim * The certificate chain is returned in chain. Caller is responsible for 247238384Sjkim * freeing the vector. 248238384Sjkim */ 249238384Sjkimstatic int TS_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted, 250296341Sdelphij X509 *signer, STACK_OF(X509) **chain) 251296341Sdelphij{ 252296341Sdelphij X509_STORE_CTX cert_ctx; 253296341Sdelphij int i; 254296341Sdelphij int ret = 1; 255238384Sjkim 256296341Sdelphij /* chain is an out argument. */ 257296341Sdelphij *chain = NULL; 258296341Sdelphij X509_STORE_CTX_init(&cert_ctx, store, signer, untrusted); 259296341Sdelphij X509_STORE_CTX_set_purpose(&cert_ctx, X509_PURPOSE_TIMESTAMP_SIGN); 260296341Sdelphij i = X509_verify_cert(&cert_ctx); 261296341Sdelphij if (i <= 0) { 262296341Sdelphij int j = X509_STORE_CTX_get_error(&cert_ctx); 263296341Sdelphij TSerr(TS_F_TS_VERIFY_CERT, TS_R_CERTIFICATE_VERIFY_ERROR); 264296341Sdelphij ERR_add_error_data(2, "Verify error:", 265296341Sdelphij X509_verify_cert_error_string(j)); 266296341Sdelphij ret = 0; 267296341Sdelphij } else { 268296341Sdelphij /* Get a copy of the certificate chain. */ 269296341Sdelphij *chain = X509_STORE_CTX_get1_chain(&cert_ctx); 270296341Sdelphij } 271238384Sjkim 272296341Sdelphij X509_STORE_CTX_cleanup(&cert_ctx); 273238384Sjkim 274296341Sdelphij return ret; 275296341Sdelphij} 276238384Sjkim 277296341Sdelphijstatic int TS_check_signing_certs(PKCS7_SIGNER_INFO *si, 278296341Sdelphij STACK_OF(X509) *chain) 279296341Sdelphij{ 280296341Sdelphij ESS_SIGNING_CERT *ss = ESS_get_signing_cert(si); 281296341Sdelphij STACK_OF(ESS_CERT_ID) *cert_ids = NULL; 282296341Sdelphij X509 *cert; 283296341Sdelphij int i = 0; 284296341Sdelphij int ret = 0; 285238384Sjkim 286296341Sdelphij if (!ss) 287296341Sdelphij goto err; 288296341Sdelphij cert_ids = ss->cert_ids; 289296341Sdelphij /* The signer certificate must be the first in cert_ids. */ 290296341Sdelphij cert = sk_X509_value(chain, 0); 291296341Sdelphij if (TS_find_cert(cert_ids, cert) != 0) 292296341Sdelphij goto err; 293296341Sdelphij 294296341Sdelphij /* 295296341Sdelphij * Check the other certificates of the chain if there are more than one 296296341Sdelphij * certificate ids in cert_ids. 297296341Sdelphij */ 298296341Sdelphij if (sk_ESS_CERT_ID_num(cert_ids) > 1) { 299296341Sdelphij /* All the certificates of the chain must be in cert_ids. */ 300296341Sdelphij for (i = 1; i < sk_X509_num(chain); ++i) { 301296341Sdelphij cert = sk_X509_value(chain, i); 302296341Sdelphij if (TS_find_cert(cert_ids, cert) < 0) 303296341Sdelphij goto err; 304296341Sdelphij } 305296341Sdelphij } 306296341Sdelphij ret = 1; 307238384Sjkim err: 308296341Sdelphij if (!ret) 309296341Sdelphij TSerr(TS_F_TS_CHECK_SIGNING_CERTS, 310296341Sdelphij TS_R_ESS_SIGNING_CERTIFICATE_ERROR); 311296341Sdelphij ESS_SIGNING_CERT_free(ss); 312296341Sdelphij return ret; 313296341Sdelphij} 314238384Sjkim 315238384Sjkimstatic ESS_SIGNING_CERT *ESS_get_signing_cert(PKCS7_SIGNER_INFO *si) 316296341Sdelphij{ 317296341Sdelphij ASN1_TYPE *attr; 318296341Sdelphij const unsigned char *p; 319296341Sdelphij attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate); 320296341Sdelphij if (!attr) 321296341Sdelphij return NULL; 322296341Sdelphij p = attr->value.sequence->data; 323296341Sdelphij return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length); 324296341Sdelphij} 325238384Sjkim 326238384Sjkim/* Returns < 0 if certificate is not found, certificate index otherwise. */ 327238384Sjkimstatic int TS_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert) 328296341Sdelphij{ 329296341Sdelphij int i; 330238384Sjkim 331296341Sdelphij if (!cert_ids || !cert) 332296341Sdelphij return -1; 333238384Sjkim 334296341Sdelphij /* Recompute SHA1 hash of certificate if necessary (side effect). */ 335296341Sdelphij X509_check_purpose(cert, -1, 0); 336238384Sjkim 337296341Sdelphij /* Look for cert in the cert_ids vector. */ 338296341Sdelphij for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i) { 339296341Sdelphij ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i); 340238384Sjkim 341296341Sdelphij /* Check the SHA-1 hash first. */ 342296341Sdelphij if (cid->hash->length == sizeof(cert->sha1_hash) 343296341Sdelphij && !memcmp(cid->hash->data, cert->sha1_hash, 344296341Sdelphij sizeof(cert->sha1_hash))) { 345296341Sdelphij /* Check the issuer/serial as well if specified. */ 346296341Sdelphij ESS_ISSUER_SERIAL *is = cid->issuer_serial; 347296341Sdelphij if (!is || !TS_issuer_serial_cmp(is, cert->cert_info)) 348296341Sdelphij return i; 349296341Sdelphij } 350296341Sdelphij } 351238384Sjkim 352296341Sdelphij return -1; 353296341Sdelphij} 354296341Sdelphij 355238384Sjkimstatic int TS_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509_CINF *cinfo) 356296341Sdelphij{ 357296341Sdelphij GENERAL_NAME *issuer; 358238384Sjkim 359296341Sdelphij if (!is || !cinfo || sk_GENERAL_NAME_num(is->issuer) != 1) 360296341Sdelphij return -1; 361238384Sjkim 362296341Sdelphij /* Check the issuer first. It must be a directory name. */ 363296341Sdelphij issuer = sk_GENERAL_NAME_value(is->issuer, 0); 364296341Sdelphij if (issuer->type != GEN_DIRNAME 365296341Sdelphij || X509_NAME_cmp(issuer->d.dirn, cinfo->issuer)) 366296341Sdelphij return -1; 367238384Sjkim 368296341Sdelphij /* Check the serial number, too. */ 369296341Sdelphij if (ASN1_INTEGER_cmp(is->serial, cinfo->serialNumber)) 370296341Sdelphij return -1; 371238384Sjkim 372296341Sdelphij return 0; 373296341Sdelphij} 374238384Sjkim 375296341Sdelphij/*- 376296341Sdelphij * Verifies whether 'response' contains a valid response with regards 377238384Sjkim * to the settings of the context: 378296341Sdelphij * - Gives an error message if the TS_TST_INFO is not present. 379296341Sdelphij * - Calls _TS_RESP_verify_token to verify the token content. 380238384Sjkim */ 381238384Sjkimint TS_RESP_verify_response(TS_VERIFY_CTX *ctx, TS_RESP *response) 382296341Sdelphij{ 383296341Sdelphij PKCS7 *token = TS_RESP_get_token(response); 384296341Sdelphij TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response); 385296341Sdelphij int ret = 0; 386238384Sjkim 387296341Sdelphij /* Check if we have a successful TS_TST_INFO object in place. */ 388296341Sdelphij if (!TS_check_status_info(response)) 389296341Sdelphij goto err; 390238384Sjkim 391296341Sdelphij /* Check the contents of the time stamp token. */ 392296341Sdelphij if (!int_TS_RESP_verify_token(ctx, token, tst_info)) 393296341Sdelphij goto err; 394238384Sjkim 395296341Sdelphij ret = 1; 396238384Sjkim err: 397296341Sdelphij return ret; 398296341Sdelphij} 399238384Sjkim 400238384Sjkim/* 401238384Sjkim * Tries to extract a TS_TST_INFO structure from the PKCS7 token and 402238384Sjkim * calls the internal int_TS_RESP_verify_token function for verifying it. 403238384Sjkim */ 404238384Sjkimint TS_RESP_verify_token(TS_VERIFY_CTX *ctx, PKCS7 *token) 405296341Sdelphij{ 406296341Sdelphij TS_TST_INFO *tst_info = PKCS7_to_TS_TST_INFO(token); 407296341Sdelphij int ret = 0; 408296341Sdelphij if (tst_info) { 409296341Sdelphij ret = int_TS_RESP_verify_token(ctx, token, tst_info); 410296341Sdelphij TS_TST_INFO_free(tst_info); 411296341Sdelphij } 412296341Sdelphij return ret; 413296341Sdelphij} 414238384Sjkim 415296341Sdelphij/*- 416296341Sdelphij * Verifies whether the 'token' contains a valid time stamp token 417238384Sjkim * with regards to the settings of the context. Only those checks are 418238384Sjkim * carried out that are specified in the context: 419296341Sdelphij * - Verifies the signature of the TS_TST_INFO. 420296341Sdelphij * - Checks the version number of the response. 421296341Sdelphij * - Check if the requested and returned policies math. 422296341Sdelphij * - Check if the message imprints are the same. 423296341Sdelphij * - Check if the nonces are the same. 424296341Sdelphij * - Check if the TSA name matches the signer. 425296341Sdelphij * - Check if the TSA name is the expected TSA. 426238384Sjkim */ 427296341Sdelphijstatic int int_TS_RESP_verify_token(TS_VERIFY_CTX *ctx, 428296341Sdelphij PKCS7 *token, TS_TST_INFO *tst_info) 429296341Sdelphij{ 430296341Sdelphij X509 *signer = NULL; 431296341Sdelphij GENERAL_NAME *tsa_name = TS_TST_INFO_get_tsa(tst_info); 432296341Sdelphij X509_ALGOR *md_alg = NULL; 433296341Sdelphij unsigned char *imprint = NULL; 434296341Sdelphij unsigned imprint_len = 0; 435296341Sdelphij int ret = 0; 436238384Sjkim 437296341Sdelphij /* Verify the signature. */ 438296341Sdelphij if ((ctx->flags & TS_VFY_SIGNATURE) 439296341Sdelphij && !TS_RESP_verify_signature(token, ctx->certs, ctx->store, &signer)) 440296341Sdelphij goto err; 441238384Sjkim 442296341Sdelphij /* Check version number of response. */ 443296341Sdelphij if ((ctx->flags & TS_VFY_VERSION) 444296341Sdelphij && TS_TST_INFO_get_version(tst_info) != 1) { 445296341Sdelphij TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_UNSUPPORTED_VERSION); 446296341Sdelphij goto err; 447296341Sdelphij } 448238384Sjkim 449296341Sdelphij /* Check policies. */ 450296341Sdelphij if ((ctx->flags & TS_VFY_POLICY) 451296341Sdelphij && !TS_check_policy(ctx->policy, tst_info)) 452296341Sdelphij goto err; 453238384Sjkim 454296341Sdelphij /* Check message imprints. */ 455296341Sdelphij if ((ctx->flags & TS_VFY_IMPRINT) 456296341Sdelphij && !TS_check_imprints(ctx->md_alg, ctx->imprint, ctx->imprint_len, 457296341Sdelphij tst_info)) 458296341Sdelphij goto err; 459238384Sjkim 460296341Sdelphij /* Compute and check message imprints. */ 461296341Sdelphij if ((ctx->flags & TS_VFY_DATA) 462296341Sdelphij && (!TS_compute_imprint(ctx->data, tst_info, 463296341Sdelphij &md_alg, &imprint, &imprint_len) 464296341Sdelphij || !TS_check_imprints(md_alg, imprint, imprint_len, tst_info))) 465296341Sdelphij goto err; 466238384Sjkim 467296341Sdelphij /* Check nonces. */ 468296341Sdelphij if ((ctx->flags & TS_VFY_NONCE) 469296341Sdelphij && !TS_check_nonces(ctx->nonce, tst_info)) 470296341Sdelphij goto err; 471238384Sjkim 472296341Sdelphij /* Check whether TSA name and signer certificate match. */ 473296341Sdelphij if ((ctx->flags & TS_VFY_SIGNER) 474296341Sdelphij && tsa_name && !TS_check_signer_name(tsa_name, signer)) { 475296341Sdelphij TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_TSA_NAME_MISMATCH); 476296341Sdelphij goto err; 477296341Sdelphij } 478296341Sdelphij 479296341Sdelphij /* Check whether the TSA is the expected one. */ 480296341Sdelphij if ((ctx->flags & TS_VFY_TSA_NAME) 481296341Sdelphij && !TS_check_signer_name(ctx->tsa_name, signer)) { 482296341Sdelphij TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_TSA_UNTRUSTED); 483296341Sdelphij goto err; 484296341Sdelphij } 485296341Sdelphij 486296341Sdelphij ret = 1; 487238384Sjkim err: 488296341Sdelphij X509_free(signer); 489296341Sdelphij X509_ALGOR_free(md_alg); 490296341Sdelphij OPENSSL_free(imprint); 491296341Sdelphij return ret; 492296341Sdelphij} 493238384Sjkim 494238384Sjkimstatic int TS_check_status_info(TS_RESP *response) 495296341Sdelphij{ 496296341Sdelphij TS_STATUS_INFO *info = TS_RESP_get_status_info(response); 497296341Sdelphij long status = ASN1_INTEGER_get(info->status); 498296341Sdelphij const char *status_text = NULL; 499296341Sdelphij char *embedded_status_text = NULL; 500296341Sdelphij char failure_text[TS_STATUS_BUF_SIZE] = ""; 501238384Sjkim 502296341Sdelphij /* Check if everything went fine. */ 503296341Sdelphij if (status == 0 || status == 1) 504296341Sdelphij return 1; 505238384Sjkim 506296341Sdelphij /* There was an error, get the description in status_text. */ 507296341Sdelphij if (0 <= status && status < (long)TS_STATUS_TEXT_SIZE) 508296341Sdelphij status_text = TS_status_text[status]; 509296341Sdelphij else 510296341Sdelphij status_text = "unknown code"; 511238384Sjkim 512296341Sdelphij /* Set the embedded_status_text to the returned description. */ 513296341Sdelphij if (sk_ASN1_UTF8STRING_num(info->text) > 0 514296341Sdelphij && !(embedded_status_text = TS_get_status_text(info->text))) 515296341Sdelphij return 0; 516238384Sjkim 517296341Sdelphij /* Filling in failure_text with the failure information. */ 518296341Sdelphij if (info->failure_info) { 519296341Sdelphij int i; 520296341Sdelphij int first = 1; 521296341Sdelphij for (i = 0; i < (int)TS_FAILURE_INFO_SIZE; ++i) { 522296341Sdelphij if (ASN1_BIT_STRING_get_bit(info->failure_info, 523296341Sdelphij TS_failure_info[i].code)) { 524296341Sdelphij if (!first) 525296341Sdelphij strcpy(failure_text, ","); 526296341Sdelphij else 527296341Sdelphij first = 0; 528296341Sdelphij strcat(failure_text, TS_failure_info[i].text); 529296341Sdelphij } 530296341Sdelphij } 531296341Sdelphij } 532296341Sdelphij if (failure_text[0] == '\0') 533296341Sdelphij strcpy(failure_text, "unspecified"); 534238384Sjkim 535296341Sdelphij /* Making up the error string. */ 536296341Sdelphij TSerr(TS_F_TS_CHECK_STATUS_INFO, TS_R_NO_TIME_STAMP_TOKEN); 537296341Sdelphij ERR_add_error_data(6, 538296341Sdelphij "status code: ", status_text, 539296341Sdelphij ", status text: ", embedded_status_text ? 540296341Sdelphij embedded_status_text : "unspecified", 541296341Sdelphij ", failure codes: ", failure_text); 542296341Sdelphij OPENSSL_free(embedded_status_text); 543238384Sjkim 544296341Sdelphij return 0; 545296341Sdelphij} 546296341Sdelphij 547238384Sjkimstatic char *TS_get_status_text(STACK_OF(ASN1_UTF8STRING) *text) 548296341Sdelphij{ 549296341Sdelphij int i; 550296341Sdelphij unsigned int length = 0; 551296341Sdelphij char *result = NULL; 552296341Sdelphij char *p; 553238384Sjkim 554296341Sdelphij /* Determine length first. */ 555296341Sdelphij for (i = 0; i < sk_ASN1_UTF8STRING_num(text); ++i) { 556296341Sdelphij ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i); 557296341Sdelphij length += ASN1_STRING_length(current); 558296341Sdelphij length += 1; /* separator character */ 559296341Sdelphij } 560296341Sdelphij /* Allocate memory (closing '\0' included). */ 561296341Sdelphij if (!(result = OPENSSL_malloc(length))) { 562296341Sdelphij TSerr(TS_F_TS_GET_STATUS_TEXT, ERR_R_MALLOC_FAILURE); 563296341Sdelphij return NULL; 564296341Sdelphij } 565296341Sdelphij /* Concatenate the descriptions. */ 566296341Sdelphij for (i = 0, p = result; i < sk_ASN1_UTF8STRING_num(text); ++i) { 567296341Sdelphij ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i); 568296341Sdelphij length = ASN1_STRING_length(current); 569296341Sdelphij if (i > 0) 570296341Sdelphij *p++ = '/'; 571296341Sdelphij strncpy(p, (const char *)ASN1_STRING_data(current), length); 572296341Sdelphij p += length; 573296341Sdelphij } 574296341Sdelphij /* We do have space for this, too. */ 575296341Sdelphij *p = '\0'; 576238384Sjkim 577296341Sdelphij return result; 578296341Sdelphij} 579296341Sdelphij 580238384Sjkimstatic int TS_check_policy(ASN1_OBJECT *req_oid, TS_TST_INFO *tst_info) 581296341Sdelphij{ 582296341Sdelphij ASN1_OBJECT *resp_oid = TS_TST_INFO_get_policy_id(tst_info); 583238384Sjkim 584296341Sdelphij if (OBJ_cmp(req_oid, resp_oid) != 0) { 585296341Sdelphij TSerr(TS_F_TS_CHECK_POLICY, TS_R_POLICY_MISMATCH); 586296341Sdelphij return 0; 587296341Sdelphij } 588238384Sjkim 589296341Sdelphij return 1; 590296341Sdelphij} 591238384Sjkim 592238384Sjkimstatic int TS_compute_imprint(BIO *data, TS_TST_INFO *tst_info, 593296341Sdelphij X509_ALGOR **md_alg, 594296341Sdelphij unsigned char **imprint, unsigned *imprint_len) 595296341Sdelphij{ 596296341Sdelphij TS_MSG_IMPRINT *msg_imprint = TS_TST_INFO_get_msg_imprint(tst_info); 597296341Sdelphij X509_ALGOR *md_alg_resp = TS_MSG_IMPRINT_get_algo(msg_imprint); 598296341Sdelphij const EVP_MD *md; 599296341Sdelphij EVP_MD_CTX md_ctx; 600296341Sdelphij unsigned char buffer[4096]; 601296341Sdelphij int length; 602238384Sjkim 603296341Sdelphij *md_alg = NULL; 604296341Sdelphij *imprint = NULL; 605238384Sjkim 606296341Sdelphij /* Return the MD algorithm of the response. */ 607296341Sdelphij if (!(*md_alg = X509_ALGOR_dup(md_alg_resp))) 608296341Sdelphij goto err; 609238384Sjkim 610296341Sdelphij /* Getting the MD object. */ 611296341Sdelphij if (!(md = EVP_get_digestbyobj((*md_alg)->algorithm))) { 612296341Sdelphij TSerr(TS_F_TS_COMPUTE_IMPRINT, TS_R_UNSUPPORTED_MD_ALGORITHM); 613296341Sdelphij goto err; 614296341Sdelphij } 615238384Sjkim 616296341Sdelphij /* Compute message digest. */ 617296341Sdelphij length = EVP_MD_size(md); 618296341Sdelphij if (length < 0) 619296341Sdelphij goto err; 620296341Sdelphij *imprint_len = length; 621296341Sdelphij if (!(*imprint = OPENSSL_malloc(*imprint_len))) { 622296341Sdelphij TSerr(TS_F_TS_COMPUTE_IMPRINT, ERR_R_MALLOC_FAILURE); 623296341Sdelphij goto err; 624296341Sdelphij } 625238384Sjkim 626296341Sdelphij if (!EVP_DigestInit(&md_ctx, md)) 627296341Sdelphij goto err; 628296341Sdelphij while ((length = BIO_read(data, buffer, sizeof(buffer))) > 0) { 629296341Sdelphij if (!EVP_DigestUpdate(&md_ctx, buffer, length)) 630296341Sdelphij goto err; 631296341Sdelphij } 632296341Sdelphij if (!EVP_DigestFinal(&md_ctx, *imprint, NULL)) 633296341Sdelphij goto err; 634238384Sjkim 635296341Sdelphij return 1; 636238384Sjkim err: 637296341Sdelphij X509_ALGOR_free(*md_alg); 638296341Sdelphij OPENSSL_free(*imprint); 639296341Sdelphij *imprint_len = 0; 640296341Sdelphij *imprint = NULL; 641296341Sdelphij return 0; 642296341Sdelphij} 643238384Sjkim 644296341Sdelphijstatic int TS_check_imprints(X509_ALGOR *algor_a, 645296341Sdelphij unsigned char *imprint_a, unsigned len_a, 646296341Sdelphij TS_TST_INFO *tst_info) 647296341Sdelphij{ 648296341Sdelphij TS_MSG_IMPRINT *b = TS_TST_INFO_get_msg_imprint(tst_info); 649296341Sdelphij X509_ALGOR *algor_b = TS_MSG_IMPRINT_get_algo(b); 650296341Sdelphij int ret = 0; 651238384Sjkim 652296341Sdelphij /* algor_a is optional. */ 653296341Sdelphij if (algor_a) { 654296341Sdelphij /* Compare algorithm OIDs. */ 655296341Sdelphij if (OBJ_cmp(algor_a->algorithm, algor_b->algorithm)) 656296341Sdelphij goto err; 657238384Sjkim 658296341Sdelphij /* The parameter must be NULL in both. */ 659296341Sdelphij if ((algor_a->parameter 660296341Sdelphij && ASN1_TYPE_get(algor_a->parameter) != V_ASN1_NULL) 661296341Sdelphij || (algor_b->parameter 662296341Sdelphij && ASN1_TYPE_get(algor_b->parameter) != V_ASN1_NULL)) 663296341Sdelphij goto err; 664296341Sdelphij } 665238384Sjkim 666296341Sdelphij /* Compare octet strings. */ 667296341Sdelphij ret = len_a == (unsigned)ASN1_STRING_length(b->hashed_msg) && 668296341Sdelphij memcmp(imprint_a, ASN1_STRING_data(b->hashed_msg), len_a) == 0; 669238384Sjkim err: 670296341Sdelphij if (!ret) 671296341Sdelphij TSerr(TS_F_TS_CHECK_IMPRINTS, TS_R_MESSAGE_IMPRINT_MISMATCH); 672296341Sdelphij return ret; 673296341Sdelphij} 674238384Sjkim 675238384Sjkimstatic int TS_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info) 676296341Sdelphij{ 677296341Sdelphij const ASN1_INTEGER *b = TS_TST_INFO_get_nonce(tst_info); 678238384Sjkim 679296341Sdelphij /* Error if nonce is missing. */ 680296341Sdelphij if (!b) { 681296341Sdelphij TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_NOT_RETURNED); 682296341Sdelphij return 0; 683296341Sdelphij } 684238384Sjkim 685296341Sdelphij /* No error if a nonce is returned without being requested. */ 686296341Sdelphij if (ASN1_INTEGER_cmp(a, b) != 0) { 687296341Sdelphij TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_MISMATCH); 688296341Sdelphij return 0; 689296341Sdelphij } 690238384Sjkim 691296341Sdelphij return 1; 692296341Sdelphij} 693238384Sjkim 694296341Sdelphij/* 695296341Sdelphij * Check if the specified TSA name matches either the subject or one of the 696296341Sdelphij * subject alternative names of the TSA certificate. 697296341Sdelphij */ 698238384Sjkimstatic int TS_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer) 699296341Sdelphij{ 700296341Sdelphij STACK_OF(GENERAL_NAME) *gen_names = NULL; 701296341Sdelphij int idx = -1; 702296341Sdelphij int found = 0; 703238384Sjkim 704296341Sdelphij /* Check the subject name first. */ 705296341Sdelphij if (tsa_name->type == GEN_DIRNAME 706296341Sdelphij && X509_name_cmp(tsa_name->d.dirn, signer->cert_info->subject) == 0) 707296341Sdelphij return 1; 708238384Sjkim 709296341Sdelphij /* Check all the alternative names. */ 710296341Sdelphij gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name, NULL, &idx); 711296341Sdelphij while (gen_names != NULL 712296341Sdelphij && !(found = TS_find_name(gen_names, tsa_name) >= 0)) { 713296341Sdelphij /* 714296341Sdelphij * Get the next subject alternative name, although there should be no 715296341Sdelphij * more than one. 716296341Sdelphij */ 717296341Sdelphij GENERAL_NAMES_free(gen_names); 718296341Sdelphij gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name, 719296341Sdelphij NULL, &idx); 720296341Sdelphij } 721296341Sdelphij if (gen_names) 722296341Sdelphij GENERAL_NAMES_free(gen_names); 723238384Sjkim 724296341Sdelphij return found; 725296341Sdelphij} 726296341Sdelphij 727238384Sjkim/* Returns 1 if name is in gen_names, 0 otherwise. */ 728238384Sjkimstatic int TS_find_name(STACK_OF(GENERAL_NAME) *gen_names, GENERAL_NAME *name) 729296341Sdelphij{ 730296341Sdelphij int i, found; 731296341Sdelphij for (i = 0, found = 0; !found && i < sk_GENERAL_NAME_num(gen_names); ++i) { 732296341Sdelphij GENERAL_NAME *current = sk_GENERAL_NAME_value(gen_names, i); 733296341Sdelphij found = GENERAL_NAME_cmp(current, name) == 0; 734296341Sdelphij } 735296341Sdelphij return found ? i - 1 : -1; 736296341Sdelphij} 737