Coverage Report

Created: 2025-04-22 06:18

/src/openssl/crypto/ts/ts_rsp_verify.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2006-2021 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 <openssl/objects.h>
12
#include <openssl/ts.h>
13
#include <openssl/pkcs7.h>
14
#include "internal/cryptlib.h"
15
#include "internal/sizes.h"
16
#include "crypto/ess.h"
17
#include "ts_local.h"
18
19
static int ts_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
20
                          X509 *signer, STACK_OF(X509) **chain);
21
static int ts_check_signing_certs(const PKCS7_SIGNER_INFO *si,
22
                                  const STACK_OF(X509) *chain);
23
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
41
/*
42
 * This must be large enough to hold all values in ts_status_text (with
43
 * comma separator) or all text fields in ts_failure_info (also with comma).
44
 */
45
#define TS_STATUS_BUF_SIZE      256
46
47
/*
48
 * Local mapping between response codes and descriptions.
49
 */
50
static const char *ts_status_text[] = {
51
    "granted",
52
    "grantedWithMods",
53
    "rejection",
54
    "waiting",
55
    "revocationWarning",
56
    "revocationNotification"
57
};
58
59
#define TS_STATUS_TEXT_SIZE     OSSL_NELEM(ts_status_text)
60
61
static struct {
62
    int code;
63
    const char *text;
64
} ts_failure_info[] = {
65
    {TS_INFO_BAD_ALG, "badAlg"},
66
    {TS_INFO_BAD_REQUEST, "badRequest"},
67
    {TS_INFO_BAD_DATA_FORMAT, "badDataFormat"},
68
    {TS_INFO_TIME_NOT_AVAILABLE, "timeNotAvailable"},
69
    {TS_INFO_UNACCEPTED_POLICY, "unacceptedPolicy"},
70
    {TS_INFO_UNACCEPTED_EXTENSION, "unacceptedExtension"},
71
    {TS_INFO_ADD_INFO_NOT_AVAILABLE, "addInfoNotAvailable"},
72
    {TS_INFO_SYSTEM_FAILURE, "systemFailure"}
73
};
74
75
76
/*-
77
 * This function carries out the following tasks:
78
 *      - Checks if there is one and only one signer.
79
 *      - Search for the signing certificate in 'certs' and in the response.
80
 *      - Check the extended key usage and key usage fields of the signer
81
 *      certificate (done by the path validation).
82
 *      - Build and validate the certificate path.
83
 *      - Check if the certificate path meets the requirements of the
84
 *      SigningCertificate ESS signed attribute.
85
 *      - Verify the signature value.
86
 *      - Returns the signer certificate in 'signer', if 'signer' is not NULL.
87
 */
88
int TS_RESP_verify_signature(PKCS7 *token, STACK_OF(X509) *certs,
89
                             X509_STORE *store, X509 **signer_out)
90
0
{
91
0
    STACK_OF(PKCS7_SIGNER_INFO) *sinfos = NULL;
92
0
    PKCS7_SIGNER_INFO *si;
93
0
    STACK_OF(X509) *untrusted = NULL;
94
0
    STACK_OF(X509) *signers = NULL;
95
0
    X509 *signer;
96
0
    STACK_OF(X509) *chain = NULL;
97
0
    char buf[4096];
98
0
    int i, j = 0, ret = 0;
99
0
    BIO *p7bio = NULL;
100
101
    /* Some sanity checks first. */
102
0
    if (!token) {
103
0
        ERR_raise(ERR_LIB_TS, TS_R_INVALID_NULL_POINTER);
104
0
        goto err;
105
0
    }
106
0
    if (!PKCS7_type_is_signed(token)) {
107
0
        ERR_raise(ERR_LIB_TS, TS_R_WRONG_CONTENT_TYPE);
108
0
        goto err;
109
0
    }
110
0
    sinfos = PKCS7_get_signer_info(token);
111
0
    if (!sinfos || sk_PKCS7_SIGNER_INFO_num(sinfos) != 1) {
112
0
        ERR_raise(ERR_LIB_TS, TS_R_THERE_MUST_BE_ONE_SIGNER);
113
0
        goto err;
114
0
    }
115
0
    si = sk_PKCS7_SIGNER_INFO_value(sinfos, 0);
116
0
    if (PKCS7_get_detached(token)) {
117
0
        ERR_raise(ERR_LIB_TS, TS_R_NO_CONTENT);
118
0
        goto err;
119
0
    }
120
121
    /*
122
     * Get hold of the signer certificate, search only internal certificates
123
     * if it was requested.
124
     */
125
0
    signers = PKCS7_get0_signers(token, certs, 0);
126
0
    if (!signers || sk_X509_num(signers) != 1)
127
0
        goto err;
128
0
    signer = sk_X509_value(signers, 0);
129
130
0
    untrusted = sk_X509_new_reserve(NULL, sk_X509_num(certs)
131
0
                                    + sk_X509_num(token->d.sign->cert));
132
0
    if (untrusted == NULL
133
0
            || !X509_add_certs(untrusted, certs, 0)
134
0
            || !X509_add_certs(untrusted, token->d.sign->cert, 0))
135
0
        goto err;
136
0
    if (!ts_verify_cert(store, untrusted, signer, &chain))
137
0
        goto err;
138
0
    if (!ts_check_signing_certs(si, chain))
139
0
        goto err;
140
0
    p7bio = PKCS7_dataInit(token, NULL);
141
142
    /* We now have to 'read' from p7bio to calculate digests etc. */
143
0
    while ((i = BIO_read(p7bio, buf, sizeof(buf))) > 0)
144
0
        continue;
145
146
0
    j = PKCS7_signatureVerify(p7bio, token, si, signer);
147
0
    if (j <= 0) {
148
0
        ERR_raise(ERR_LIB_TS, TS_R_SIGNATURE_FAILURE);
149
0
        goto err;
150
0
    }
151
152
0
    if (signer_out) {
153
0
        *signer_out = signer;
154
0
        X509_up_ref(signer);
155
0
    }
156
0
    ret = 1;
157
158
0
 err:
159
0
    BIO_free_all(p7bio);
160
0
    sk_X509_free(untrusted);
161
0
    sk_X509_pop_free(chain, X509_free);
162
0
    sk_X509_free(signers);
163
164
0
    return ret;
165
0
}
166
167
/*
168
 * The certificate chain is returned in chain. Caller is responsible for
169
 * freeing the vector.
170
 */
171
static int ts_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
172
                          X509 *signer, STACK_OF(X509) **chain)
173
0
{
174
0
    X509_STORE_CTX *cert_ctx = NULL;
175
0
    int i;
176
0
    int ret = 0;
177
178
0
    *chain = NULL;
179
0
    cert_ctx = X509_STORE_CTX_new();
180
0
    if (cert_ctx == NULL) {
181
0
        ERR_raise(ERR_LIB_TS, ERR_R_MALLOC_FAILURE);
182
0
        goto err;
183
0
    }
184
0
    if (!X509_STORE_CTX_init(cert_ctx, store, signer, untrusted))
185
0
        goto end;
186
0
    X509_STORE_CTX_set_purpose(cert_ctx, X509_PURPOSE_TIMESTAMP_SIGN);
187
0
    i = X509_verify_cert(cert_ctx);
188
0
    if (i <= 0) {
189
0
        int j = X509_STORE_CTX_get_error(cert_ctx);
190
0
        ERR_raise_data(ERR_LIB_TS, TS_R_CERTIFICATE_VERIFY_ERROR,
191
0
                       "Verify error:%s", X509_verify_cert_error_string(j));
192
0
        goto err;
193
0
    }
194
0
    *chain = X509_STORE_CTX_get1_chain(cert_ctx);
195
0
    ret = 1;
196
0
    goto end;
197
198
0
err:
199
0
    ret = 0;
200
201
0
end:
202
0
    X509_STORE_CTX_free(cert_ctx);
203
0
    return ret;
204
0
}
205
206
static ESS_SIGNING_CERT *ossl_ess_get_signing_cert(const PKCS7_SIGNER_INFO *si)
207
0
{
208
0
    ASN1_TYPE *attr;
209
0
    const unsigned char *p;
210
211
0
    attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate);
212
0
    if (attr == NULL)
213
0
        return NULL;
214
0
    p = attr->value.sequence->data;
215
0
    return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length);
216
0
}
217
218
static
219
ESS_SIGNING_CERT_V2 *ossl_ess_get_signing_cert_v2(const PKCS7_SIGNER_INFO *si)
220
0
{
221
0
    ASN1_TYPE *attr;
222
0
    const unsigned char *p;
223
224
0
    attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificateV2);
225
0
    if (attr == NULL)
226
0
        return NULL;
227
0
    p = attr->value.sequence->data;
228
0
    return d2i_ESS_SIGNING_CERT_V2(NULL, &p, attr->value.sequence->length);
229
0
}
230
231
static int ts_check_signing_certs(const PKCS7_SIGNER_INFO *si,
232
                                  const STACK_OF(X509) *chain)
233
0
{
234
0
    ESS_SIGNING_CERT *ss = ossl_ess_get_signing_cert(si);
235
0
    ESS_SIGNING_CERT_V2 *ssv2 = ossl_ess_get_signing_cert_v2(si);
236
0
    int ret = OSSL_ESS_check_signing_certs(ss, ssv2, chain, 1) > 0;
237
238
0
    ESS_SIGNING_CERT_free(ss);
239
0
    ESS_SIGNING_CERT_V2_free(ssv2);
240
0
    return ret;
241
0
}
242
243
/*-
244
 * Verifies whether 'response' contains a valid response with regards
245
 * to the settings of the context:
246
 *      - Gives an error message if the TS_TST_INFO is not present.
247
 *      - Calls _TS_RESP_verify_token to verify the token content.
248
 */
249
int TS_RESP_verify_response(TS_VERIFY_CTX *ctx, TS_RESP *response)
250
0
{
251
0
    PKCS7 *token = response->token;
252
0
    TS_TST_INFO *tst_info = response->tst_info;
253
0
    int ret = 0;
254
255
0
    if (!ts_check_status_info(response))
256
0
        goto err;
257
0
    if (!int_ts_RESP_verify_token(ctx, token, tst_info))
258
0
        goto err;
259
0
    ret = 1;
260
261
0
 err:
262
0
    return ret;
263
0
}
264
265
/*
266
 * Tries to extract a TS_TST_INFO structure from the PKCS7 token and
267
 * calls the internal int_TS_RESP_verify_token function for verifying it.
268
 */
269
int TS_RESP_verify_token(TS_VERIFY_CTX *ctx, PKCS7 *token)
270
0
{
271
0
    TS_TST_INFO *tst_info = PKCS7_to_TS_TST_INFO(token);
272
0
    int ret = 0;
273
0
    if (tst_info) {
274
0
        ret = int_ts_RESP_verify_token(ctx, token, tst_info);
275
0
        TS_TST_INFO_free(tst_info);
276
0
    }
277
0
    return ret;
278
0
}
279
280
/*-
281
 * Verifies whether the 'token' contains a valid time stamp token
282
 * with regards to the settings of the context. Only those checks are
283
 * carried out that are specified in the context:
284
 *      - Verifies the signature of the TS_TST_INFO.
285
 *      - Checks the version number of the response.
286
 *      - Check if the requested and returned policies math.
287
 *      - Check if the message imprints are the same.
288
 *      - Check if the nonces are the same.
289
 *      - Check if the TSA name matches the signer.
290
 *      - Check if the TSA name is the expected TSA.
291
 */
292
static int int_ts_RESP_verify_token(TS_VERIFY_CTX *ctx,
293
                                    PKCS7 *token, TS_TST_INFO *tst_info)
294
0
{
295
0
    X509 *signer = NULL;
296
0
    GENERAL_NAME *tsa_name = tst_info->tsa;
297
0
    X509_ALGOR *md_alg = NULL;
298
0
    unsigned char *imprint = NULL;
299
0
    unsigned imprint_len = 0;
300
0
    int ret = 0;
301
0
    int flags = ctx->flags;
302
303
    /* Some options require us to also check the signature */
304
0
    if (((flags & TS_VFY_SIGNER) && tsa_name != NULL)
305
0
            || (flags & TS_VFY_TSA_NAME)) {
306
0
        flags |= TS_VFY_SIGNATURE;
307
0
    }
308
309
0
    if ((flags & TS_VFY_SIGNATURE)
310
0
        && !TS_RESP_verify_signature(token, ctx->certs, ctx->store, &signer))
311
0
        goto err;
312
0
    if ((flags & TS_VFY_VERSION)
313
0
        && TS_TST_INFO_get_version(tst_info) != 1) {
314
0
        ERR_raise(ERR_LIB_TS, TS_R_UNSUPPORTED_VERSION);
315
0
        goto err;
316
0
    }
317
0
    if ((flags & TS_VFY_POLICY)
318
0
        && !ts_check_policy(ctx->policy, tst_info))
319
0
        goto err;
320
0
    if ((flags & TS_VFY_IMPRINT)
321
0
        && !ts_check_imprints(ctx->md_alg, ctx->imprint, ctx->imprint_len,
322
0
                              tst_info))
323
0
        goto err;
324
0
    if ((flags & TS_VFY_DATA)
325
0
        && (!ts_compute_imprint(ctx->data, tst_info,
326
0
                                &md_alg, &imprint, &imprint_len)
327
0
            || !ts_check_imprints(md_alg, imprint, imprint_len, tst_info)))
328
0
        goto err;
329
0
    if ((flags & TS_VFY_NONCE)
330
0
        && !ts_check_nonces(ctx->nonce, tst_info))
331
0
        goto err;
332
0
    if ((flags & TS_VFY_SIGNER)
333
0
        && tsa_name && !ts_check_signer_name(tsa_name, signer)) {
334
0
        ERR_raise(ERR_LIB_TS, TS_R_TSA_NAME_MISMATCH);
335
0
        goto err;
336
0
    }
337
0
    if ((flags & TS_VFY_TSA_NAME)
338
0
        && !ts_check_signer_name(ctx->tsa_name, signer)) {
339
0
        ERR_raise(ERR_LIB_TS, TS_R_TSA_UNTRUSTED);
340
0
        goto err;
341
0
    }
342
0
    ret = 1;
343
344
0
 err:
345
0
    X509_free(signer);
346
0
    X509_ALGOR_free(md_alg);
347
0
    OPENSSL_free(imprint);
348
0
    return ret;
349
0
}
350
351
static int ts_check_status_info(TS_RESP *response)
352
0
{
353
0
    TS_STATUS_INFO *info = response->status_info;
354
0
    long status = ASN1_INTEGER_get(info->status);
355
0
    const char *status_text = NULL;
356
0
    char *embedded_status_text = NULL;
357
0
    char failure_text[TS_STATUS_BUF_SIZE] = "";
358
359
0
    if (status == 0 || status == 1)
360
0
        return 1;
361
362
    /* There was an error, get the description in status_text. */
363
0
    if (0 <= status && status < (long) OSSL_NELEM(ts_status_text))
364
0
        status_text = ts_status_text[status];
365
0
    else
366
0
        status_text = "unknown code";
367
368
0
    if (sk_ASN1_UTF8STRING_num(info->text) > 0
369
0
        && (embedded_status_text = ts_get_status_text(info->text)) == NULL)
370
0
        return 0;
371
372
    /* Fill in failure_text with the failure information. */
373
0
    if (info->failure_info) {
374
0
        int i;
375
0
        int first = 1;
376
0
        for (i = 0; i < (int)OSSL_NELEM(ts_failure_info); ++i) {
377
0
            if (ASN1_BIT_STRING_get_bit(info->failure_info,
378
0
                                        ts_failure_info[i].code)) {
379
0
                if (!first)
380
0
                    strcat(failure_text, ",");
381
0
                else
382
0
                    first = 0;
383
0
                strcat(failure_text, ts_failure_info[i].text);
384
0
            }
385
0
        }
386
0
    }
387
0
    if (failure_text[0] == '\0')
388
0
        strcpy(failure_text, "unspecified");
389
390
0
    ERR_raise_data(ERR_LIB_TS, TS_R_NO_TIME_STAMP_TOKEN,
391
0
                   "status code: %s, status text: %s, failure codes: %s",
392
0
                   status_text,
393
0
                   embedded_status_text ? embedded_status_text : "unspecified",
394
0
                   failure_text);
395
0
    OPENSSL_free(embedded_status_text);
396
397
0
    return 0;
398
0
}
399
400
static char *ts_get_status_text(STACK_OF(ASN1_UTF8STRING) *text)
401
0
{
402
0
    return ossl_sk_ASN1_UTF8STRING2text(text, "/", TS_MAX_STATUS_LENGTH);
403
0
}
404
405
static int ts_check_policy(const ASN1_OBJECT *req_oid,
406
                           const TS_TST_INFO *tst_info)
407
0
{
408
0
    const ASN1_OBJECT *resp_oid = tst_info->policy_id;
409
410
0
    if (OBJ_cmp(req_oid, resp_oid) != 0) {
411
0
        ERR_raise(ERR_LIB_TS, TS_R_POLICY_MISMATCH);
412
0
        return 0;
413
0
    }
414
415
0
    return 1;
416
0
}
417
418
static int ts_compute_imprint(BIO *data, TS_TST_INFO *tst_info,
419
                              X509_ALGOR **md_alg,
420
                              unsigned char **imprint, unsigned *imprint_len)
421
0
{
422
0
    TS_MSG_IMPRINT *msg_imprint = tst_info->msg_imprint;
423
0
    X509_ALGOR *md_alg_resp = msg_imprint->hash_algo;
424
0
    EVP_MD *md = NULL;
425
0
    EVP_MD_CTX *md_ctx = NULL;
426
0
    unsigned char buffer[4096];
427
0
    char name[OSSL_MAX_NAME_SIZE];
428
0
    int length;
429
430
0
    *md_alg = NULL;
431
0
    *imprint = NULL;
432
433
0
    if ((*md_alg = X509_ALGOR_dup(md_alg_resp)) == NULL)
434
0
        goto err;
435
436
0
    OBJ_obj2txt(name, sizeof(name), md_alg_resp->algorithm, 0);
437
438
0
    (void)ERR_set_mark();
439
0
    md = EVP_MD_fetch(NULL, name, NULL);
440
441
0
    if (md == NULL)
442
0
        md = (EVP_MD *)EVP_get_digestbyname(name);
443
444
0
    if (md == NULL) {
445
0
        (void)ERR_clear_last_mark();
446
0
        goto err;
447
0
    }
448
0
    (void)ERR_pop_to_mark();
449
450
0
    length = EVP_MD_get_size(md);
451
0
    if (length < 0)
452
0
        goto err;
453
0
    *imprint_len = length;
454
0
    if ((*imprint = OPENSSL_malloc(*imprint_len)) == NULL) {
455
0
        ERR_raise(ERR_LIB_TS, ERR_R_MALLOC_FAILURE);
456
0
        goto err;
457
0
    }
458
459
0
    md_ctx = EVP_MD_CTX_new();
460
0
    if (md_ctx == NULL) {
461
0
        ERR_raise(ERR_LIB_TS, ERR_R_MALLOC_FAILURE);
462
0
        goto err;
463
0
    }
464
0
    if (!EVP_DigestInit(md_ctx, md))
465
0
        goto err;
466
0
    EVP_MD_free(md);
467
0
    md = NULL;
468
0
    while ((length = BIO_read(data, buffer, sizeof(buffer))) > 0) {
469
0
        if (!EVP_DigestUpdate(md_ctx, buffer, length))
470
0
            goto err;
471
0
    }
472
0
    if (!EVP_DigestFinal(md_ctx, *imprint, NULL))
473
0
        goto err;
474
0
    EVP_MD_CTX_free(md_ctx);
475
476
0
    return 1;
477
0
 err:
478
0
    EVP_MD_CTX_free(md_ctx);
479
0
    EVP_MD_free(md);
480
0
    X509_ALGOR_free(*md_alg);
481
0
    *md_alg = NULL;
482
0
    OPENSSL_free(*imprint);
483
0
    *imprint_len = 0;
484
0
    *imprint = 0;
485
0
    return 0;
486
0
}
487
488
static int ts_check_imprints(X509_ALGOR *algor_a,
489
                             const unsigned char *imprint_a, unsigned len_a,
490
                             TS_TST_INFO *tst_info)
491
0
{
492
0
    TS_MSG_IMPRINT *b = tst_info->msg_imprint;
493
0
    X509_ALGOR *algor_b = b->hash_algo;
494
0
    int ret = 0;
495
496
0
    if (algor_a) {
497
0
        if (OBJ_cmp(algor_a->algorithm, algor_b->algorithm))
498
0
            goto err;
499
500
        /* The parameter must be NULL in both. */
501
0
        if ((algor_a->parameter
502
0
             && ASN1_TYPE_get(algor_a->parameter) != V_ASN1_NULL)
503
0
            || (algor_b->parameter
504
0
                && ASN1_TYPE_get(algor_b->parameter) != V_ASN1_NULL))
505
0
            goto err;
506
0
    }
507
508
0
    ret = len_a == (unsigned)ASN1_STRING_length(b->hashed_msg) &&
509
0
        memcmp(imprint_a, ASN1_STRING_get0_data(b->hashed_msg), len_a) == 0;
510
0
 err:
511
0
    if (!ret)
512
0
        ERR_raise(ERR_LIB_TS, TS_R_MESSAGE_IMPRINT_MISMATCH);
513
0
    return ret;
514
0
}
515
516
static int ts_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info)
517
0
{
518
0
    const ASN1_INTEGER *b = tst_info->nonce;
519
520
0
    if (!b) {
521
0
        ERR_raise(ERR_LIB_TS, TS_R_NONCE_NOT_RETURNED);
522
0
        return 0;
523
0
    }
524
525
    /* No error if a nonce is returned without being requested. */
526
0
    if (ASN1_INTEGER_cmp(a, b) != 0) {
527
0
        ERR_raise(ERR_LIB_TS, TS_R_NONCE_MISMATCH);
528
0
        return 0;
529
0
    }
530
531
0
    return 1;
532
0
}
533
534
/*
535
 * Check if the specified TSA name matches either the subject or one of the
536
 * subject alternative names of the TSA certificate.
537
 */
538
static int ts_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer)
539
0
{
540
0
    STACK_OF(GENERAL_NAME) *gen_names = NULL;
541
0
    int idx = -1;
542
0
    int found = 0;
543
544
0
    if (tsa_name->type == GEN_DIRNAME
545
0
        && X509_name_cmp(tsa_name->d.dirn, X509_get_subject_name(signer)) == 0)
546
0
        return 1;
547
0
    gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name, NULL, &idx);
548
0
    while (gen_names != NULL) {
549
0
        found = ts_find_name(gen_names, tsa_name) >= 0;
550
0
        if (found)
551
0
            break;
552
        /*
553
         * Get the next subject alternative name, although there should be no
554
         * more than one.
555
         */
556
0
        GENERAL_NAMES_free(gen_names);
557
0
        gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name, NULL, &idx);
558
0
    }
559
0
    GENERAL_NAMES_free(gen_names);
560
561
0
    return found;
562
0
}
563
564
/* Returns 1 if name is in gen_names, 0 otherwise. */
565
static int ts_find_name(STACK_OF(GENERAL_NAME) *gen_names, GENERAL_NAME *name)
566
0
{
567
0
    int i, found;
568
0
    for (i = 0, found = 0; !found && i < sk_GENERAL_NAME_num(gen_names); ++i) {
569
0
        GENERAL_NAME *current = sk_GENERAL_NAME_value(gen_names, i);
570
0
        found = GENERAL_NAME_cmp(current, name) == 0;
571
0
    }
572
0
    return found ? i - 1 : -1;
573
0
}