Skip to content

Commit 68e8845

Browse files
olszomalmtrojnar
authored andcommitted
Improve PKCS#7 verification with OpenSSL 3.5
Enhanced verification logic for PKCS#7 signedData structures by introducing a dedicated `verify_pkcs7_data()` function. This update addresses compatibility with older OpenSSL versions (< 3.0.5) and ensures correct handling of detached signed content using a BIO buffer. The change enables support for PKCS#7 inner content (RFC 2315, section 7), as per OpenSSL PR#22575. Refactored timestamp and authenticode verification functions to reduce duplication and properly manage X509_STORE and X509_CRL structures.
1 parent 475ea95 commit 68e8845

File tree

1 file changed

+62
-54
lines changed

1 file changed

+62
-54
lines changed

osslsigncode.c

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,16 +2216,15 @@ static int verify_timestamp_token(PKCS7 *p7, CMS_ContentInfo *timestamp)
22162216
*/
22172217
static int verify_timestamp(FILE_FORMAT_CTX *ctx, PKCS7 *p7, CMS_ContentInfo *timestamp, time_t time)
22182218
{
2219-
X509_STORE *store;
22202219
STACK_OF(CMS_SignerInfo) *sinfos;
22212220
CMS_SignerInfo *cmssi;
22222221
X509 *signer;
22232222
X509_CRL *crl = NULL;
22242223
STACK_OF(X509_CRL) *crls = NULL;
22252224
char *url = NULL;
22262225
int verok = 0;
2226+
X509_STORE *store = X509_STORE_new();
22272227

2228-
store = X509_STORE_new();
22292228
if (!store)
22302229
goto out;
22312230
if (x509_store_load_file(store, ctx->options->tsa_cafile)) {
@@ -2240,12 +2239,10 @@ static int verify_timestamp(FILE_FORMAT_CTX *ctx, PKCS7 *p7, CMS_ContentInfo *ti
22402239
*/
22412240
if (!x509_store_set_time(store, time)) {
22422241
fprintf(stderr, "Failed to set store time\n");
2243-
X509_STORE_free(store);
22442242
goto out;
22452243
}
22462244
} else {
22472245
printf("Use the \"-TSA-CAfile\" option to add the Time-Stamp Authority certificates bundle to verify the Timestamp Server.\n");
2248-
X509_STORE_free(store);
22492246
goto out;
22502247
}
22512248

@@ -2255,14 +2252,12 @@ static int verify_timestamp(FILE_FORMAT_CTX *ctx, PKCS7 *p7, CMS_ContentInfo *ti
22552252
STACK_OF(X509) *cms_certs;
22562253

22572254
printf("CMS_verify error\n");
2258-
X509_STORE_free(store);
22592255
printf("\nFailed timestamp certificate chain retrieved from the signature:\n");
22602256
cms_certs = CMS_get1_certs(timestamp);
22612257
print_certs_chain(cms_certs);
22622258
sk_X509_pop_free(cms_certs, X509_free);
22632259
goto out;
22642260
}
2265-
X509_STORE_free(store);
22662261

22672262
sinfos = CMS_get0_SignerInfos(timestamp);
22682263
cmssi = sk_CMS_SignerInfo_value(sinfos, 0);
@@ -2299,7 +2294,6 @@ static int verify_timestamp(FILE_FORMAT_CTX *ctx, PKCS7 *p7, CMS_ContentInfo *ti
22992294
int crlok = verify_crl(ctx->options->tsa_cafile, ctx->options->tsa_crlfile,
23002295
crls, signer, chain);
23012296
sk_X509_pop_free(chain, X509_free);
2302-
sk_X509_CRL_pop_free(crls, X509_CRL_free);
23032297
printf("Timestamp Server Signature CRL verification: %s\n", crlok ? "ok" : "failed");
23042298
if (!crlok)
23052299
goto out;
@@ -2317,6 +2311,8 @@ static int verify_timestamp(FILE_FORMAT_CTX *ctx, PKCS7 *p7, CMS_ContentInfo *ti
23172311
}
23182312
verok = 1; /* OK */
23192313
out:
2314+
X509_STORE_free(store);
2315+
sk_X509_CRL_pop_free(crls, X509_CRL_free);
23202316
if (!verok)
23212317
ERR_print_errors_fp(stderr);
23222318
return verok;
@@ -2344,6 +2340,60 @@ static int PKCS7_type_is_other(PKCS7 *p7)
23442340
}
23452341
#endif /* OPENSSL_VERSION_NUMBER<0x30000000L */
23462342

2343+
/*
2344+
* [in] p7: PKCS#7 signature
2345+
* [in] store: X509_STORE
2346+
* [returns] 1 on error or 0 on success
2347+
*/
2348+
static int verify_pkcs7_data(PKCS7 *p7, X509_STORE *store)
2349+
{
2350+
int verok = 0;
2351+
#if OPENSSL_VERSION_NUMBER<0x30500000L
2352+
BIO *bio = NULL;
2353+
PKCS7 *contents = p7->d.sign->contents;
2354+
2355+
/*
2356+
* In the PKCS7_verify() function, the BIO *indata parameter refers to
2357+
* the signed data if the content is detached from p7.
2358+
* Otherwise, indata should be NULL, and then the signed data must be in p7.
2359+
* The OpenSSL error workaround is to put the inner content into BIO *indata parameter
2360+
* https://github.com/openssl/openssl/pull/22575
2361+
*/
2362+
if (PKCS7_type_is_other(contents) && (contents->d.other != NULL)
2363+
&& (contents->d.other->value.sequence != NULL)
2364+
&& (contents->d.other->value.sequence->length > 0)) {
2365+
if (contents->d.other->type == V_ASN1_SEQUENCE) {
2366+
/* only verify the content of the sequence */
2367+
const unsigned char *data = contents->d.other->value.sequence->data;
2368+
long len;
2369+
int inf, tag, class;
2370+
2371+
inf = ASN1_get_object(&data, &len, &tag, &class,
2372+
contents->d.other->value.sequence->length);
2373+
if (inf != V_ASN1_CONSTRUCTED || tag != V_ASN1_SEQUENCE) {
2374+
fprintf(stderr, "Corrupted data content\n");
2375+
X509_STORE_free(store);
2376+
return 0; /* FAILED */
2377+
}
2378+
bio = BIO_new_mem_buf(data, (int)len);
2379+
} else {
2380+
/* verify the entire value */
2381+
bio = BIO_new_mem_buf(contents->d.other->value.sequence->data,
2382+
contents->d.other->value.sequence->length);
2383+
}
2384+
} else {
2385+
fprintf(stderr, "Corrupted data content\n");
2386+
X509_STORE_free(store);
2387+
return 0; /* FAILED */
2388+
}
2389+
verok = PKCS7_verify(p7, NULL, store, bio, NULL, 0);
2390+
BIO_free(bio);
2391+
#else /* OPENSSL_VERSION_NUMBER<0x30500000L */
2392+
verok = PKCS7_verify(p7, NULL, store, NULL, NULL, 0);
2393+
#endif /* OPENSSL_VERSION_NUMBER<0x30500000L */
2394+
return verok;
2395+
}
2396+
23472397
/*
23482398
* [in] ctx: structure holds input and output data
23492399
* [in] p7: PKCS#7 signature
@@ -2353,86 +2403,42 @@ static int PKCS7_type_is_other(PKCS7 *p7)
23532403
*/
23542404
static int verify_authenticode(FILE_FORMAT_CTX *ctx, PKCS7 *p7, time_t time, X509 *signer)
23552405
{
2356-
X509_STORE *store;
23572406
X509_CRL *crl = NULL;
23582407
STACK_OF(X509_CRL) *crls = NULL;
2359-
BIO *bio = NULL;
23602408
int verok = 0;
23612409
char *url = NULL;
2362-
PKCS7 *contents = p7->d.sign->contents;
2410+
X509_STORE *store = X509_STORE_new();
23632411

2364-
store = X509_STORE_new();
23652412
if (!store)
23662413
goto out;
23672414

23682415
if (!x509_store_load_file(store, ctx->options->cafile)) {
23692416
fprintf(stderr, "Failed to add store lookup file\n");
2370-
X509_STORE_free(store);
23712417
goto out;
23722418
}
23732419
if (time != INVALID_TIME) {
23742420
printf("Signature verification time: ");
23752421
print_time_t(time);
23762422
if (!x509_store_set_time(store, time)) {
23772423
fprintf(stderr, "Failed to set signature time\n");
2378-
X509_STORE_free(store);
23792424
goto out;
23802425
}
23812426
} else if (ctx->options->time != INVALID_TIME) {
23822427
printf("Signature verification time: ");
23832428
print_time_t(ctx->options->time);
23842429
if (!x509_store_set_time(store, ctx->options->time)) {
23852430
fprintf(stderr, "Failed to set verifying time\n");
2386-
X509_STORE_free(store);
23872431
goto out;
23882432
}
23892433
}
23902434
/* verify a PKCS#7 signedData structure */
2391-
if (PKCS7_type_is_other(contents) && (contents->d.other != NULL)
2392-
&& (contents->d.other->value.sequence != NULL)
2393-
&& (contents->d.other->value.sequence->length > 0)) {
2394-
if (contents->d.other->type == V_ASN1_SEQUENCE) {
2395-
/* only verify the content of the sequence */
2396-
const unsigned char *data = contents->d.other->value.sequence->data;
2397-
long len;
2398-
int inf, tag, class;
2399-
2400-
inf = ASN1_get_object(&data, &len, &tag, &class,
2401-
contents->d.other->value.sequence->length);
2402-
if (inf != V_ASN1_CONSTRUCTED || tag != V_ASN1_SEQUENCE) {
2403-
fprintf(stderr, "Corrupted data content\n");
2404-
X509_STORE_free(store);
2405-
goto out;
2406-
}
2407-
bio = BIO_new_mem_buf(data, (int)len);
2408-
} else {
2409-
/* verify the entire value */
2410-
bio = BIO_new_mem_buf(contents->d.other->value.sequence->data,
2411-
contents->d.other->value.sequence->length);
2412-
}
2413-
} else {
2414-
fprintf(stderr, "Corrupted data content\n");
2415-
X509_STORE_free(store);
2416-
goto out;
2417-
}
24182435
printf("Signing certificate chain verified using:\n");
2419-
/*
2420-
* In the PKCS7_verify() function, the BIO *indata parameter refers to
2421-
* the signed data if the content is detached from p7.
2422-
* Otherwise, indata should be NULL, and then the signed data must be in p7.
2423-
* The OpenSSL error workaround is to put the inner content into BIO *indata parameter
2424-
* https://github.com/openssl/openssl/pull/22575
2425-
*/
2426-
if (!PKCS7_verify(p7, NULL, store, bio, NULL, 0)) {
2436+
if (!verify_pkcs7_data(p7, store)) {
24272437
printf("PKCS7_verify error\n");
2428-
X509_STORE_free(store);
2429-
BIO_free(bio);
24302438
printf("Failed signing certificate chain retrieved from the signature:\n");
24312439
print_certs_chain(p7->d.sign->cert);
24322440
goto out;
24332441
}
2434-
X509_STORE_free(store);
2435-
BIO_free(bio);
24362442

24372443
/* verify a Certificate Revocation List */
24382444
if (!ctx->options->ignore_crl) {
@@ -2464,7 +2470,7 @@ static int verify_authenticode(FILE_FORMAT_CTX *ctx, PKCS7 *p7, time_t time, X50
24642470
STACK_OF(X509) *chain = p7->d.sign->cert;
24652471
int crlok = verify_crl(ctx->options->cafile, ctx->options->crlfile,
24662472
crls, signer, chain);
2467-
sk_X509_CRL_pop_free(crls, X509_CRL_free);
2473+
24682474
printf("Signature CRL verification: %s\n", crlok ? "ok" : "failed");
24692475
if (!crlok)
24702476
goto out;
@@ -2477,6 +2483,8 @@ static int verify_authenticode(FILE_FORMAT_CTX *ctx, PKCS7 *p7, time_t time, X50
24772483

24782484
verok = 1; /* OK */
24792485
out:
2486+
X509_STORE_free(store);
2487+
sk_X509_CRL_pop_free(crls, X509_CRL_free);
24802488
if (!verok)
24812489
ERR_print_errors_fp(stderr);
24822490
return verok;

0 commit comments

Comments
 (0)