crypto/cms: add CAdES-BES signed attributes validation

for signing certificate V2 and signing certificate extensions.

CAdES: lowercase name for now internal methods.

crypto/cms: generated file changes.

Add some CHANGES entries.

[extended tests]

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/8098)
This commit is contained in:
FdaSilvaYY 2019-06-12 19:52:39 +02:00 committed by Tomas Mraz
parent f7f53d7d61
commit 9e3c510bde
19 changed files with 461 additions and 149 deletions

View File

@ -23,6 +23,15 @@ OpenSSL 3.0
### Changes between 1.1.1 and 3.0 [xx XXX xxxx] ### Changes between 1.1.1 and 3.0 [xx XXX xxxx]
* Add CAdES-BES signature verification support, mostly derived
from ESSCertIDv2 TS (RFC 5816) contribution by Marek Klein.
*Filipe Raimundo da Silva*
* Add CAdES-BES signature scheme and attributes support (RFC 5126) to CMS API.
*Antonio Iacono*
* Deprecated EC_POINT_make_affine() and EC_POINTs_make_affine(). These * Deprecated EC_POINT_make_affine() and EC_POINTs_make_affine(). These
functions are not widely used and now OpenSSL automatically perform this functions are not widely used and now OpenSSL automatically perform this
conversion when needed. conversion when needed.

View File

@ -670,12 +670,18 @@ int cms_main(int argc, char **argv)
goto opthelp; goto opthelp;
} }
if (flags & CMS_CADES) { if ((flags & CMS_CADES) != 0) {
if (flags & CMS_NOATTR) { if ((flags & CMS_NOATTR) != 0) {
BIO_puts(bio_err, "Incompatible options: " BIO_puts(bio_err, "Incompatible options: "
"CAdES required signed attributes\n"); "CAdES required signed attributes\n");
goto opthelp; goto opthelp;
} }
if (operation == SMIME_VERIFY
&& (flags & (CMS_NO_SIGNER_CERT_VERIFY | CMS_NO_ATTR_VERIFY)) != 0) {
BIO_puts(bio_err, "Incompatible options: CAdES validation require"
" certs and signed attributes validations\n");
goto opthelp;
}
} }
if (operation & SMIME_SIGNERS) { if (operation & SMIME_SIGNERS) {
@ -1115,7 +1121,8 @@ int cms_main(int argc, char **argv)
goto end; goto end;
} else if (operation == SMIME_VERIFY) { } else if (operation == SMIME_VERIFY) {
if (CMS_verify(cms, other, store, indata, out, flags) > 0) { if (CMS_verify(cms, other, store, indata, out, flags) > 0) {
BIO_printf(bio_err, "Verification successful\n"); BIO_printf(bio_err, "%s Verification successful\n",
(flags & CMS_CADES) ? "CAdES" : "CMS");
} else { } else {
BIO_printf(bio_err, "Verification failure\n"); BIO_printf(bio_err, "Verification failure\n");
if (verify_retcode) if (verify_retcode)

View File

@ -52,6 +52,10 @@ static const ERR_STRING_DATA CMS_str_reasons[] = {
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ERROR_SETTING_KEY), "error setting key"}, {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ERROR_SETTING_KEY), "error setting key"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ERROR_SETTING_RECIPIENTINFO), {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ERROR_SETTING_RECIPIENTINFO),
"error setting recipientinfo"}, "error setting recipientinfo"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE),
"ess no signing certid attribute"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR),
"ess signing certid mismatch error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_INVALID_ENCRYPTED_KEY_LENGTH), {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_INVALID_ENCRYPTED_KEY_LENGTH),
"invalid encrypted key length"}, "invalid encrypted key length"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER), {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER),

View File

@ -21,6 +21,9 @@
DEFINE_STACK_OF(GENERAL_NAMES) DEFINE_STACK_OF(GENERAL_NAMES)
DEFINE_STACK_OF(CMS_SignerInfo) DEFINE_STACK_OF(CMS_SignerInfo)
DEFINE_STACK_OF(ESS_CERT_ID)
DEFINE_STACK_OF(ESS_CERT_ID_V2)
DEFINE_STACK_OF(X509)
IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest) IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
@ -29,33 +32,100 @@ IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr) int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
{ {
ASN1_STRING *str; ASN1_STRING *str;
CMS_ReceiptRequest *rr = NULL; CMS_ReceiptRequest *rr;
if (prr) ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_receiptRequest);
if (prr != NULL)
*prr = NULL; *prr = NULL;
str = CMS_signed_get0_data_by_OBJ(si, str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE);
OBJ_nid2obj if (str == NULL)
(NID_id_smime_aa_receiptRequest), -3,
V_ASN1_SEQUENCE);
if (!str)
return 0; return 0;
rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest)); rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest));
if (!rr) if (rr == NULL)
return -1; return -1;
if (prr) if (prr != NULL)
*prr = rr; *prr = rr;
else else
CMS_ReceiptRequest_free(rr); CMS_ReceiptRequest_free(rr);
return 1; return 1;
} }
/*
First, get the ESS_SIGNING_CERT(V2) signed attribute from |si|.
Then check matching of each cert of trust |chain| with one of
the |cert_ids|(Hash+IssuerID) list from this ESS_SIGNING_CERT.
Derived from ts_check_signing_certs()
*/
int ess_check_signing_certs(CMS_SignerInfo *si, STACK_OF(X509) *chain)
{
ESS_SIGNING_CERT *ss = NULL;
ESS_SIGNING_CERT_V2 *ssv2 = NULL;
X509 *cert;
int i = 0, ret = 0;
if (cms_signerinfo_get_signing_cert(si, &ss) > 0 && ss->cert_ids != NULL) {
STACK_OF(ESS_CERT_ID) *cert_ids = ss->cert_ids;
cert = sk_X509_value(chain, 0);
if (ess_find_cert(cert_ids, cert) != 0)
goto err;
/*
* Check the other certificates of the chain.
* Fail if no signing certificate ids found for each certificate.
*/
if (sk_ESS_CERT_ID_num(cert_ids) > 1) {
/* for each chain cert, try to find its cert id */
for (i = 1; i < sk_X509_num(chain); ++i) {
cert = sk_X509_value(chain, i);
if (ess_find_cert(cert_ids, cert) < 0)
goto err;
}
}
} else if (cms_signerinfo_get_signing_cert_v2(si, &ssv2) > 0
&& ssv2->cert_ids!= NULL) {
STACK_OF(ESS_CERT_ID_V2) *cert_ids_v2 = ssv2->cert_ids;
cert = sk_X509_value(chain, 0);
if (ess_find_cert_v2(cert_ids_v2, cert) != 0)
goto err;
/*
* Check the other certificates of the chain.
* Fail if no signing certificate ids found for each certificate.
*/
if (sk_ESS_CERT_ID_V2_num(cert_ids_v2) > 1) {
/* for each chain cert, try to find its cert id */
for (i = 1; i < sk_X509_num(chain); ++i) {
cert = sk_X509_value(chain, i);
if (ess_find_cert_v2(cert_ids_v2, cert) < 0)
goto err;
}
}
} else {
CMSerr(CMS_F_ESS_CHECK_SIGNING_CERTS,
CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE);
return 0;
}
ret = 1;
err:
if (!ret)
CMSerr(CMS_F_ESS_CHECK_SIGNING_CERTS,
CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR);
ESS_SIGNING_CERT_free(ss);
ESS_SIGNING_CERT_V2_free(ssv2);
return ret;
}
CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen, CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen,
int allorfirst, int allorfirst,
STACK_OF(GENERAL_NAMES) STACK_OF(GENERAL_NAMES)
*receiptList, STACK_OF(GENERAL_NAMES) *receiptList, STACK_OF(GENERAL_NAMES)
*receiptsTo) *receiptsTo)
{ {
CMS_ReceiptRequest *rr = NULL; CMS_ReceiptRequest *rr;
rr = CMS_ReceiptRequest_new(); rr = CMS_ReceiptRequest_new();
if (rr == NULL) if (rr == NULL)
@ -145,6 +215,7 @@ static int cms_msgSigDigest(CMS_SignerInfo *si,
unsigned char *dig, unsigned int *diglen) unsigned char *dig, unsigned int *diglen)
{ {
const EVP_MD *md; const EVP_MD *md;
md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm); md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
if (md == NULL) if (md == NULL)
return 0; return 0;
@ -160,6 +231,7 @@ int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
{ {
unsigned char dig[EVP_MAX_MD_SIZE]; unsigned char dig[EVP_MAX_MD_SIZE];
unsigned int diglen; unsigned int diglen;
if (!cms_msgSigDigest(src, dig, &diglen)) { if (!cms_msgSigDigest(src, dig, &diglen)) {
CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR); CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR);
return 0; return 0;

View File

@ -421,6 +421,9 @@ int cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, CMS_RecipientInfo *
/* SignerInfo routines */ /* SignerInfo routines */
int CMS_si_check_attributes(const CMS_SignerInfo *si); int CMS_si_check_attributes(const CMS_SignerInfo *si);
/* ESS routines */
int ess_check_signing_certs(CMS_SignerInfo *si, STACK_OF(X509) *chain);
DECLARE_ASN1_ITEM(CMS_CertificateChoices) DECLARE_ASN1_ITEM(CMS_CertificateChoices)
DECLARE_ASN1_ITEM(CMS_DigestedData) DECLARE_ASN1_ITEM(CMS_DigestedData)
DECLARE_ASN1_ITEM(CMS_EncryptedData) DECLARE_ASN1_ITEM(CMS_EncryptedData)

View File

@ -233,7 +233,8 @@ CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
static int cms_signerinfo_verify_cert(CMS_SignerInfo *si, static int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
X509_STORE *store, X509_STORE *store,
STACK_OF(X509) *certs, STACK_OF(X509) *certs,
STACK_OF(X509_CRL) *crls) STACK_OF(X509_CRL) *crls,
STACK_OF(X509) **chain)
{ {
X509_STORE_CTX *ctx = X509_STORE_CTX_new(); X509_STORE_CTX *ctx = X509_STORE_CTX_new();
X509 *signer; X509 *signer;
@ -262,6 +263,10 @@ static int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
goto err; goto err;
} }
r = 1; r = 1;
/* also send back the trust chain when required */
if (chain != NULL)
*chain = X509_STORE_CTX_get1_chain(ctx);
err: err:
X509_STORE_CTX_free(ctx); X509_STORE_CTX_free(ctx);
return r; return r;
@ -275,9 +280,11 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
STACK_OF(CMS_SignerInfo) *sinfos; STACK_OF(CMS_SignerInfo) *sinfos;
STACK_OF(X509) *cms_certs = NULL; STACK_OF(X509) *cms_certs = NULL;
STACK_OF(X509_CRL) *crls = NULL; STACK_OF(X509_CRL) *crls = NULL;
STACK_OF(X509) **si_chains = NULL;
X509 *signer; X509 *signer;
int i, scount = 0, ret = 0; int i, scount = 0, ret = 0;
BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL; BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL;
int cadesVerify = (flags & CMS_CADES) != 0;
if (!dcont && !check_content(cms)) if (!dcont && !check_content(cms))
return 0; return 0;
@ -312,27 +319,44 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
} }
/* Attempt to verify all signers certs */ /* Attempt to verify all signers certs */
/* at this point scount == sk_CMS_SignerInfo_num(sinfos) */
if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) { if ((flags & CMS_NO_SIGNER_CERT_VERIFY) == 0 || cadesVerify) {
if (cadesVerify) {
/* Certificate trust chain is required to check CAdES signature */
si_chains = OPENSSL_zalloc(scount * sizeof(si_chains[0]));
if (si_chains == NULL) {
CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE);
goto err;
}
}
cms_certs = CMS_get1_certs(cms); cms_certs = CMS_get1_certs(cms);
if (!(flags & CMS_NOCRL)) if (!(flags & CMS_NOCRL))
crls = CMS_get1_crls(cms); crls = CMS_get1_crls(cms);
for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { for (i = 0; i < scount; i++) {
si = sk_CMS_SignerInfo_value(sinfos, i); si = sk_CMS_SignerInfo_value(sinfos, i);
if (!cms_signerinfo_verify_cert(si, store, cms_certs, crls))
if (!cms_signerinfo_verify_cert(si, store, cms_certs, crls,
si_chains ? &si_chains[i] : NULL))
goto err; goto err;
} }
} }
/* Attempt to verify all SignerInfo signed attribute signatures */ /* Attempt to verify all SignerInfo signed attribute signatures */
if (!(flags & CMS_NO_ATTR_VERIFY)) { if ((flags & CMS_NO_ATTR_VERIFY) == 0 || cadesVerify) {
for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { for (i = 0; i < scount; i++) {
si = sk_CMS_SignerInfo_value(sinfos, i); si = sk_CMS_SignerInfo_value(sinfos, i);
if (CMS_signed_get_attr_count(si) < 0) if (CMS_signed_get_attr_count(si) < 0)
continue; continue;
if (CMS_SignerInfo_verify(si) <= 0) if (CMS_SignerInfo_verify(si) <= 0)
goto err; goto err;
if (cadesVerify) {
STACK_OF(X509) *si_chain = si_chains ? si_chains[i] : NULL;
if (ess_check_signing_certs(si, si_chain) <= 0)
goto err;
}
} }
} }
@ -420,6 +444,11 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
BIO_free_all(tmpout); BIO_free_all(tmpout);
err2: err2:
if (si_chains != NULL) {
for (i = 0; i < scount; ++i)
sk_X509_pop_free(si_chains[i], X509_free);
OPENSSL_free(si_chains);
}
sk_X509_pop_free(cms_certs, X509_free); sk_X509_pop_free(cms_certs, X509_free);
sk_X509_CRL_pop_free(crls, X509_CRL_free); sk_X509_CRL_pop_free(crls, X509_CRL_free);

View File

@ -320,6 +320,7 @@ CMS_F_CMS_SET_DETACHED:147:CMS_set_detached
CMS_F_CMS_SIGN:148:CMS_sign CMS_F_CMS_SIGN:148:CMS_sign
CMS_F_CMS_SIGNED_DATA_INIT:149:cms_signed_data_init CMS_F_CMS_SIGNED_DATA_INIT:149:cms_signed_data_init
CMS_F_CMS_SIGNERINFO_CONTENT_SIGN:150:cms_SignerInfo_content_sign CMS_F_CMS_SIGNERINFO_CONTENT_SIGN:150:cms_SignerInfo_content_sign
CMS_F_CMS_SIGNERINFO_GET_CHAIN:184:cms_signerinfo_get_chain
CMS_F_CMS_SIGNERINFO_SIGN:151:CMS_SignerInfo_sign CMS_F_CMS_SIGNERINFO_SIGN:151:CMS_SignerInfo_sign
CMS_F_CMS_SIGNERINFO_VERIFY:152:CMS_SignerInfo_verify CMS_F_CMS_SIGNERINFO_VERIFY:152:CMS_SignerInfo_verify
CMS_F_CMS_SIGNERINFO_VERIFY_CERT:153:cms_signerinfo_verify_cert CMS_F_CMS_SIGNERINFO_VERIFY_CERT:153:cms_signerinfo_verify_cert
@ -329,6 +330,7 @@ CMS_F_CMS_SI_CHECK_ATTRIBUTES:183:CMS_si_check_attributes
CMS_F_CMS_STREAM:155:CMS_stream CMS_F_CMS_STREAM:155:CMS_stream
CMS_F_CMS_UNCOMPRESS:156:CMS_uncompress CMS_F_CMS_UNCOMPRESS:156:CMS_uncompress
CMS_F_CMS_VERIFY:157:CMS_verify CMS_F_CMS_VERIFY:157:CMS_verify
CMS_F_ESS_CHECK_SIGNING_CERTS:185:ess_check_signing_certs
CMS_F_KEK_UNWRAP_KEY:180:kek_unwrap_key CMS_F_KEK_UNWRAP_KEY:180:kek_unwrap_key
COMP_F_BIO_ZLIB_FLUSH:99:bio_zlib_flush COMP_F_BIO_ZLIB_FLUSH:99:bio_zlib_flush
COMP_F_BIO_ZLIB_NEW:100:bio_zlib_new COMP_F_BIO_ZLIB_NEW:100:bio_zlib_new
@ -2188,6 +2190,8 @@ CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE:114:\
error reading messagedigest attribute error reading messagedigest attribute
CMS_R_ERROR_SETTING_KEY:115:error setting key CMS_R_ERROR_SETTING_KEY:115:error setting key
CMS_R_ERROR_SETTING_RECIPIENTINFO:116:error setting recipientinfo CMS_R_ERROR_SETTING_RECIPIENTINFO:116:error setting recipientinfo
CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE:182:ess no signing certid attribute
CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR:183:ess signing certid mismatch error
CMS_R_INVALID_ENCRYPTED_KEY_LENGTH:117:invalid encrypted key length CMS_R_INVALID_ENCRYPTED_KEY_LENGTH:117:invalid encrypted key length
CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER:176:invalid key encryption parameter CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER:176:invalid key encryption parameter
CMS_R_INVALID_KEY_LENGTH:118:invalid key length CMS_R_INVALID_KEY_LENGTH:118:invalid key length

View File

@ -1,3 +1,8 @@
LIBS=../../libcrypto LIBS=../../libcrypto
SOURCE[../../libcrypto]= \
ess_lib.c ess_asn1.c ess_err.c IF[{- !$disabled{'cms'} and !$disabled{'ts'} -}]
SOURCE[../../libcrypto]= ess_lib.c
ENDIF
SOURCE[../../libcrypto]= ess_asn1.c ess_err.c

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
* *
* Licensed under the Apache License 2.0 (the "License"). You may not use * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy * this file except in compliance with the License. You can obtain a copy
@ -9,9 +9,11 @@
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/asn1t.h> #include <openssl/asn1t.h>
#include <openssl/cms.h>
#include <openssl/ess.h> #include <openssl/ess.h>
#include <openssl/x509v3.h> #include <openssl/x509v3.h>
#include "crypto/ess.h" #include "crypto/ess.h"
#include "crypto/cms.h"
/* ASN1 stuff for ESS Structure */ /* ASN1 stuff for ESS Structure */
@ -55,3 +57,61 @@ ASN1_SEQUENCE(ESS_SIGNING_CERT_V2) = {
IMPLEMENT_ASN1_FUNCTIONS(ESS_SIGNING_CERT_V2) IMPLEMENT_ASN1_FUNCTIONS(ESS_SIGNING_CERT_V2)
IMPLEMENT_ASN1_DUP_FUNCTION(ESS_SIGNING_CERT_V2) IMPLEMENT_ASN1_DUP_FUNCTION(ESS_SIGNING_CERT_V2)
/* No cms support means no CMS_SignerInfo* definitions */
#ifndef OPENSSL_NO_CMS
/*
* Returns < 0 if attribute is not found, 1 if found, or
* -1 on attribute parsing failure.
*/
int cms_signerinfo_get_signing_cert_v2(CMS_SignerInfo *si,
ESS_SIGNING_CERT_V2 **psc)
{
ASN1_STRING *str;
ESS_SIGNING_CERT_V2 *sc;
ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_signingCertificateV2);
if (psc != NULL)
*psc = NULL;
str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE);
if (str == NULL)
return 0;
sc = ASN1_item_unpack(str, ASN1_ITEM_rptr(ESS_SIGNING_CERT_V2));
if (sc == NULL)
return -1;
if (psc != NULL)
*psc = sc;
else
ESS_SIGNING_CERT_V2_free(sc);
return 1;
}
/*
* Returns < 0 if attribute is not found, 1 if found, or
* -1 on attribute parsing failure.
*/
int cms_signerinfo_get_signing_cert(CMS_SignerInfo *si,
ESS_SIGNING_CERT **psc)
{
ASN1_STRING *str;
ESS_SIGNING_CERT *sc;
ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_signingCertificate);
if (psc != NULL)
*psc = NULL;
str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE);
if (str == NULL)
return 0;
sc = ASN1_item_unpack(str, ASN1_ITEM_rptr(ESS_SIGNING_CERT));
if (sc == NULL)
return -1;
if (psc != NULL)
*psc = sc;
else
ESS_SIGNING_CERT_free(sc);
return 1;
}
#endif /* !OPENSSL_NO_CMS */

View File

@ -1,6 +1,6 @@
/* /*
* Generated by util/mkerr.pl DO NOT EDIT * Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
* *
* Licensed under the Apache License 2.0 (the "License"). You may not use * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy * this file except in compliance with the License. You can obtain a copy

View File

@ -15,8 +15,8 @@
DEFINE_STACK_OF(ESS_CERT_ID) DEFINE_STACK_OF(ESS_CERT_ID)
DEFINE_STACK_OF(ESS_CERT_ID_V2) DEFINE_STACK_OF(ESS_CERT_ID_V2)
DEFINE_STACK_OF(X509)
DEFINE_STACK_OF(GENERAL_NAME) DEFINE_STACK_OF(GENERAL_NAME)
DEFINE_STACK_OF(X509)
static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed); static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed);
static ESS_CERT_ID_V2 *ESS_CERT_ID_V2_new_init(const EVP_MD *hash_alg, static ESS_CERT_ID_V2 *ESS_CERT_ID_V2_new_init(const EVP_MD *hash_alg,
@ -61,9 +61,12 @@ static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed)
unsigned char cert_sha1[SHA_DIGEST_LENGTH]; unsigned char cert_sha1[SHA_DIGEST_LENGTH];
/* Call for side-effect of computing hash and caching extensions */ /* Call for side-effect of computing hash and caching extensions */
X509_check_purpose(cert, -1, 0); if (!X509v3_cache_extensions(cert, NULL, NULL))
return NULL;
if ((cid = ESS_CERT_ID_new()) == NULL) if ((cid = ESS_CERT_ID_new()) == NULL)
goto err; goto err;
/* TODO(3.0): fetch sha1 algorithm from providers */
if (!X509_digest(cert, EVP_sha1(), cert_sha1, NULL)) if (!X509_digest(cert, EVP_sha1(), cert_sha1, NULL))
goto err; goto err;
if (!ASN1_OCTET_STRING_set(cid->hash, cert_sha1, SHA_DIGEST_LENGTH)) if (!ASN1_OCTET_STRING_set(cid->hash, cert_sha1, SHA_DIGEST_LENGTH))
@ -85,8 +88,8 @@ static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed)
goto err; goto err;
name = NULL; /* Ownership is lost. */ name = NULL; /* Ownership is lost. */
ASN1_INTEGER_free(cid->issuer_serial->serial); ASN1_INTEGER_free(cid->issuer_serial->serial);
if (!(cid->issuer_serial->serial = if ((cid->issuer_serial->serial =
ASN1_INTEGER_dup(X509_get_serialNumber(cert)))) ASN1_INTEGER_dup(X509_get_serialNumber(cert))) == NULL)
goto err; goto err;
return cid; return cid;
@ -159,6 +162,7 @@ static ESS_CERT_ID_V2 *ESS_CERT_ID_V2_new_init(const EVP_MD *hash_alg,
cid->hash_alg = NULL; cid->hash_alg = NULL;
} }
/* TODO(3.0): fetch sha1 algorithm from providers */
if (!X509_digest(cert, hash_alg, hash, &hash_len)) if (!X509_digest(cert, hash_alg, hash, &hash_len))
goto err; goto err;
@ -196,8 +200,9 @@ ESS_SIGNING_CERT *ESS_SIGNING_CERT_get(PKCS7_SIGNER_INFO *si)
{ {
ASN1_TYPE *attr; ASN1_TYPE *attr;
const unsigned char *p; const unsigned char *p;
attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate); attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate);
if (!attr) if (attr == NULL)
return NULL; return NULL;
p = attr->value.sequence->data; p = attr->value.sequence->data;
return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length); return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length);
@ -273,3 +278,86 @@ int ESS_SIGNING_CERT_V2_add(PKCS7_SIGNER_INFO *si,
OPENSSL_free(pp); OPENSSL_free(pp);
return 0; return 0;
} }
static int ess_issuer_serial_cmp(const ESS_ISSUER_SERIAL *is, const X509 *cert)
{
GENERAL_NAME *issuer;
if (is == NULL || cert == NULL || sk_GENERAL_NAME_num(is->issuer) != 1)
return -1;
issuer = sk_GENERAL_NAME_value(is->issuer, 0);
if (issuer->type != GEN_DIRNAME
|| X509_NAME_cmp(issuer->d.dirn, X509_get_issuer_name(cert)) != 0)
return -1;
return ASN1_INTEGER_cmp(is->serial, X509_get0_serialNumber(cert));
}
/* Returns < 0 if certificate is not found, certificate index otherwise. */
int ess_find_cert(const STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert)
{
int i;
unsigned char cert_sha1[SHA_DIGEST_LENGTH];
if (cert_ids == NULL || cert == NULL)
return -1;
/* Recompute SHA1 hash of certificate if necessary (side effect). */
if (!X509v3_cache_extensions(cert, NULL, NULL))
return -1;
/* TODO(3.0): fetch sha1 algorithm from providers */
if (!X509_digest(cert, EVP_sha1(), cert_sha1, NULL))
return -1;
/* Look for cert in the cert_ids vector. */
for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i) {
const ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i);
if (cid->hash->length == SHA_DIGEST_LENGTH
&& memcmp(cid->hash->data, cert_sha1, SHA_DIGEST_LENGTH) == 0) {
const ESS_ISSUER_SERIAL *is = cid->issuer_serial;
if (is == NULL || ess_issuer_serial_cmp(is, cert) == 0)
return i;
}
}
return -1;
}
/* Returns < 0 if certificate is not found, certificate index otherwise. */
int ess_find_cert_v2(const STACK_OF(ESS_CERT_ID_V2) *cert_ids, const X509 *cert)
{
int i;
unsigned char cert_digest[EVP_MAX_MD_SIZE];
unsigned int len;
/* Look for cert in the cert_ids vector. */
for (i = 0; i < sk_ESS_CERT_ID_V2_num(cert_ids); ++i) {
const ESS_CERT_ID_V2 *cid = sk_ESS_CERT_ID_V2_value(cert_ids, i);
const EVP_MD *md;
if (cid != NULL && cid->hash_alg != NULL)
md = EVP_get_digestbyobj(cid->hash_alg->algorithm);
else
md = EVP_sha256();
/* TODO(3.0): fetch sha1 algorithm from providers */
if (!X509_digest(cert, md, cert_digest, &len))
return -1;
if (cid->hash->length != (int)len)
return -1;
if (memcmp(cid->hash->data, cert_digest, cid->hash->length) == 0) {
const ESS_ISSUER_SERIAL *is = cid->issuer_serial;
if (is == NULL || ess_issuer_serial_cmp(is, cert) == 0)
return i;
}
}
return -1;
}

View File

@ -26,8 +26,7 @@ static int ts_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
X509 *signer, STACK_OF(X509) **chain); X509 *signer, STACK_OF(X509) **chain);
static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si, static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
STACK_OF(X509) *chain); STACK_OF(X509) *chain);
static int ts_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert);
static int ts_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509 *cert);
static int int_ts_RESP_verify_token(TS_VERIFY_CTX *ctx, static int int_ts_RESP_verify_token(TS_VERIFY_CTX *ctx,
PKCS7 *token, TS_TST_INFO *tst_info); PKCS7 *token, TS_TST_INFO *tst_info);
static int ts_check_status_info(TS_RESP *response); static int ts_check_status_info(TS_RESP *response);
@ -44,7 +43,6 @@ static int ts_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info);
static int ts_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer); static int ts_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer);
static int ts_find_name(STACK_OF(GENERAL_NAME) *gen_names, static int ts_find_name(STACK_OF(GENERAL_NAME) *gen_names,
GENERAL_NAME *name); GENERAL_NAME *name);
static int ts_find_cert_v2(STACK_OF(ESS_CERT_ID_V2) *cert_ids, X509 *cert);
/* /*
* This must be large enough to hold all values in ts_status_text (with * This must be large enough to hold all values in ts_status_text (with
@ -218,7 +216,7 @@ static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
if (ss != NULL) { if (ss != NULL) {
cert_ids = ss->cert_ids; cert_ids = ss->cert_ids;
cert = sk_X509_value(chain, 0); cert = sk_X509_value(chain, 0);
if (ts_find_cert(cert_ids, cert) != 0) if (ess_find_cert(cert_ids, cert) != 0)
goto err; goto err;
/* /*
@ -228,14 +226,14 @@ static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
if (sk_ESS_CERT_ID_num(cert_ids) > 1) { if (sk_ESS_CERT_ID_num(cert_ids) > 1) {
for (i = 1; i < sk_X509_num(chain); ++i) { for (i = 1; i < sk_X509_num(chain); ++i) {
cert = sk_X509_value(chain, i); cert = sk_X509_value(chain, i);
if (ts_find_cert(cert_ids, cert) < 0) if (ess_find_cert(cert_ids, cert) < 0)
goto err; goto err;
} }
} }
} else if (ssv2 != NULL) { } else if (ssv2 != NULL) {
cert_ids_v2 = ssv2->cert_ids; cert_ids_v2 = ssv2->cert_ids;
cert = sk_X509_value(chain, 0); cert = sk_X509_value(chain, 0);
if (ts_find_cert_v2(cert_ids_v2, cert) != 0) if (ess_find_cert_v2(cert_ids_v2, cert) != 0)
goto err; goto err;
/* /*
@ -245,7 +243,7 @@ static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
if (sk_ESS_CERT_ID_V2_num(cert_ids_v2) > 1) { if (sk_ESS_CERT_ID_V2_num(cert_ids_v2) > 1) {
for (i = 1; i < sk_X509_num(chain); ++i) { for (i = 1; i < sk_X509_num(chain); ++i) {
cert = sk_X509_value(chain, i); cert = sk_X509_value(chain, i);
if (ts_find_cert_v2(cert_ids_v2, cert) < 0) if (ess_find_cert_v2(cert_ids_v2, cert) < 0)
goto err; goto err;
} }
} }
@ -263,87 +261,6 @@ static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
return ret; return ret;
} }
/* Returns < 0 if certificate is not found, certificate index otherwise. */
static int ts_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert)
{
int i;
unsigned char cert_sha1[SHA_DIGEST_LENGTH];
if (!cert_ids || !cert)
return -1;
/* Recompute SHA1 hash of certificate if necessary (side effect). */
X509_check_purpose(cert, -1, 0);
if (!X509_digest(cert, EVP_sha1(), cert_sha1, NULL))
return -1;
/* Look for cert in the cert_ids vector. */
for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i) {
ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i);
if (cid->hash->length == SHA_DIGEST_LENGTH
&& memcmp(cid->hash->data, cert_sha1, SHA_DIGEST_LENGTH) == 0) {
ESS_ISSUER_SERIAL *is = cid->issuer_serial;
if (!is || !ts_issuer_serial_cmp(is, cert))
return i;
}
}
return -1;
}
/* Returns < 0 if certificate is not found, certificate index otherwise. */
static int ts_find_cert_v2(STACK_OF(ESS_CERT_ID_V2) *cert_ids, X509 *cert)
{
int i;
unsigned char cert_digest[EVP_MAX_MD_SIZE];
unsigned int len;
/* Look for cert in the cert_ids vector. */
for (i = 0; i < sk_ESS_CERT_ID_V2_num(cert_ids); ++i) {
ESS_CERT_ID_V2 *cid = sk_ESS_CERT_ID_V2_value(cert_ids, i);
const EVP_MD *md;
if (cid->hash_alg != NULL)
md = EVP_get_digestbyobj(cid->hash_alg->algorithm);
else
md = EVP_sha256();
if (!X509_digest(cert, md, cert_digest, &len))
return -1;
if (cid->hash->length != (int)len)
return -1;
if (memcmp(cid->hash->data, cert_digest, cid->hash->length) == 0) {
ESS_ISSUER_SERIAL *is = cid->issuer_serial;
if (is == NULL || !ts_issuer_serial_cmp(is, cert))
return i;
}
}
return -1;
}
static int ts_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509 *cert)
{
GENERAL_NAME *issuer;
if (!is || !cert || sk_GENERAL_NAME_num(is->issuer) != 1)
return -1;
issuer = sk_GENERAL_NAME_value(is->issuer, 0);
if (issuer->type != GEN_DIRNAME
|| X509_NAME_cmp(issuer->d.dirn, X509_get_issuer_name(cert)))
return -1;
if (ASN1_INTEGER_cmp(is->serial, X509_get_serialNumber(cert)))
return -1;
return 0;
}
/*- /*-
* Verifies whether 'response' contains a valid response with regards * Verifies whether 'response' contains a valid response with regards
* to the settings of the context: * to the settings of the context:

View File

@ -569,7 +569,8 @@ Message-digest of the eContent OCTET STRING within encapContentInfo being signed
=item * =item *
An ESS signing-certificate or ESS signing-certificate-v2 attribute, as defined in Enhanced Security Services (ESS), RFC 2634 and RFC 5035. An ESS signing-certificate or ESS signing-certificate-v2 attribute, as defined
in Enhanced Security Services (ESS), RFC 2634 and RFC 5035.
An ESS signing-certificate attribute only allows for the use of SHA-1 as a digest algorithm. An ESS signing-certificate attribute only allows for the use of SHA-1 as a digest algorithm.
An ESS signing-certificate-v2 attribute allows for the use of any digest algorithm. An ESS signing-certificate-v2 attribute allows for the use of any digest algorithm.
@ -577,9 +578,10 @@ An ESS signing-certificate-v2 attribute allows for the use of any digest algorit
The digital signature value computed on the user data and, when present, on the signed attributes. The digital signature value computed on the user data and, when present, on the signed attributes.
Note that currently the B<-cades> option applies only to the B<-sign> operation and is ignored during NOTE that the B<-cades> option applies to the B<-sign> or B<-verify> operations.
the B<-verify> operation, i.e. the signing certification is not checked during the verification process. With this option, the B<-verify> operation also checks that the signing-certificates
This feature might be added in a future version. attribute is present, and its value matches the verification trust chain built
during the verification process.
=back =back

View File

@ -66,10 +66,14 @@ from the content. If the content is not of type B<text/plain> then an error is
returned. returned.
If B<CMS_NO_SIGNER_CERT_VERIFY> is set the signing certificates are not If B<CMS_NO_SIGNER_CERT_VERIFY> is set the signing certificates are not
verified. verified, unless CMS_CADES flag is also set.
If B<CMS_NO_ATTR_VERIFY> is set the signed attributes signature is not If B<CMS_NO_ATTR_VERIFY> is set the signed attributes signature is not
verified. verified, unless CMS_CADES flag is also set.
If B<CMS_CADES> is set, each signer certificate is checked against the
"ESS signing-certificate" extension added in the signed attributes of the
signature.
If B<CMS_NO_CONTENT_VERIFY> is set then the content digest is not checked. If B<CMS_NO_CONTENT_VERIFY> is set then the content digest is not checked.
@ -122,7 +126,7 @@ L<ERR_get_error(3)>, L<CMS_sign(3)>
=head1 COPYRIGHT =head1 COPYRIGHT
Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved. Copyright 2008-2020 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy this file except in compliance with the License. You can obtain a copy

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
* *
* Licensed under the Apache License 2.0 (the "License"). You may not use * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy * this file except in compliance with the License. You can obtain a copy
@ -7,7 +7,15 @@
* https://www.openssl.org/source/license.html * https://www.openssl.org/source/license.html
*/ */
#ifndef OPENSSL_NO_CMS
/* internal CMS-ESS related stuff */ /* internal CMS-ESS related stuff */
int cms_add1_signing_cert(CMS_SignerInfo *si, ESS_SIGNING_CERT *sc); int cms_add1_signing_cert(CMS_SignerInfo *si, ESS_SIGNING_CERT *sc);
int cms_add1_signing_cert_v2(CMS_SignerInfo *si, ESS_SIGNING_CERT_V2 *sc); int cms_add1_signing_cert_v2(CMS_SignerInfo *si, ESS_SIGNING_CERT_V2 *sc);
int cms_signerinfo_get_signing_cert_v2(CMS_SignerInfo *si,
ESS_SIGNING_CERT_V2 **psc);
int cms_signerinfo_get_signing_cert(CMS_SignerInfo *si,
ESS_SIGNING_CERT **psc);
#endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
* *
* Licensed under the Apache License 2.0 (the "License"). You may not use * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy * this file except in compliance with the License. You can obtain a copy
@ -24,6 +24,10 @@ ESS_SIGNING_CERT_V2 *ESS_SIGNING_CERT_V2_new_init(const EVP_MD *hash_alg,
STACK_OF(X509) *certs, STACK_OF(X509) *certs,
int issuer_needed); int issuer_needed);
/* Returns < 0 if certificate is not found, certificate index otherwise. */
int ess_find_cert_v2(const STACK_OF(ESS_CERT_ID_V2) *cert_ids, const X509 *cert);
int ess_find_cert(const STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert);
/*- /*-
* IssuerSerial ::= SEQUENCE { * IssuerSerial ::= SEQUENCE {
* issuer GeneralNames, * issuer GeneralNames,

View File

@ -109,6 +109,7 @@ int ERR_load_CMS_strings(void);
# define CMS_F_CMS_SIGN 0 # define CMS_F_CMS_SIGN 0
# define CMS_F_CMS_SIGNED_DATA_INIT 0 # define CMS_F_CMS_SIGNED_DATA_INIT 0
# define CMS_F_CMS_SIGNERINFO_CONTENT_SIGN 0 # define CMS_F_CMS_SIGNERINFO_CONTENT_SIGN 0
# define CMS_F_CMS_SIGNERINFO_GET_CHAIN 0
# define CMS_F_CMS_SIGNERINFO_SIGN 0 # define CMS_F_CMS_SIGNERINFO_SIGN 0
# define CMS_F_CMS_SIGNERINFO_VERIFY 0 # define CMS_F_CMS_SIGNERINFO_VERIFY 0
# define CMS_F_CMS_SIGNERINFO_VERIFY_CERT 0 # define CMS_F_CMS_SIGNERINFO_VERIFY_CERT 0
@ -118,6 +119,7 @@ int ERR_load_CMS_strings(void);
# define CMS_F_CMS_STREAM 0 # define CMS_F_CMS_STREAM 0
# define CMS_F_CMS_UNCOMPRESS 0 # define CMS_F_CMS_UNCOMPRESS 0
# define CMS_F_CMS_VERIFY 0 # define CMS_F_CMS_VERIFY 0
# define CMS_F_ESS_CHECK_SIGNING_CERTS 0
# define CMS_F_KEK_UNWRAP_KEY 0 # define CMS_F_KEK_UNWRAP_KEY 0
# endif # endif
@ -147,6 +149,8 @@ int ERR_load_CMS_strings(void);
# define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE 114 # define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE 114
# define CMS_R_ERROR_SETTING_KEY 115 # define CMS_R_ERROR_SETTING_KEY 115
# define CMS_R_ERROR_SETTING_RECIPIENTINFO 116 # define CMS_R_ERROR_SETTING_RECIPIENTINFO 116
# define CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE 182
# define CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR 183
# define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH 117 # define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH 117
# define CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER 176 # define CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER 176
# define CMS_R_INVALID_KEY_LENGTH 118 # define CMS_R_INVALID_KEY_LENGTH 118

View File

@ -1,6 +1,6 @@
/* /*
* Generated by util/mkerr.pl DO NOT EDIT * Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
* *
* Licensed under the Apache License 2.0 (the "License"). You may not use * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy * this file except in compliance with the License. You can obtain a copy
@ -10,6 +10,7 @@
#ifndef OPENSSL_ESSERR_H #ifndef OPENSSL_ESSERR_H
# define OPENSSL_ESSERR_H # define OPENSSL_ESSERR_H
# pragma once
# include <openssl/opensslconf.h> # include <openssl/opensslconf.h>
# include <openssl/symhacks.h> # include <openssl/symhacks.h>

View File

@ -30,7 +30,7 @@ my $smcont = srctop_file("test", "smcont.txt");
my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib) my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib)
= disabled qw/des dh dsa ec ec2m rc2 zlib/; = disabled qw/des dh dsa ec ec2m rc2 zlib/;
plan tests => 7; plan tests => 10;
my @smime_pkcs7_tests = ( my @smime_pkcs7_tests = (
@ -251,26 +251,6 @@ my @smime_cms_tests = (
"-CAfile", catfile($smdir, "smroot.pem") ] "-CAfile", catfile($smdir, "smroot.pem") ]
], ],
[ "signed content DER format, RSA key, CAdES-BES compatible",
[ "{cmd1}", "-sign", "-cades", "-in", $smcont, "-outform", "DER",
"-nodetach",
"-certfile", catfile($smdir, "smroot.pem"),
"-signer", catfile($smdir, "smrsa1.pem"), "-out", "{output}.cms" ],
[ "{cmd2}", "-verify", "-in", "{output}.cms", "-inform", "DER",
"-CAfile", catfile($smdir, "smroot.pem"), "-out", "{output}.txt" ],
\&final_compare
],
[ "signed content DER format, RSA key, SHA256 md, CAdES-BES compatible",
[ "{cmd1}", "-sign", "-cades", "-md", "sha256", "-in", $smcont,
"-outform", "DER", "-nodetach",
"-certfile", catfile($smdir, "smroot.pem"),
"-signer", catfile($smdir, "smrsa1.pem"), "-out", "{output}.cms" ],
[ "{cmd2}", "-verify", "-in", "{output}.cms", "-inform", "DER",
"-CAfile", catfile($smdir, "smroot.pem"), "-out", "{output}.txt" ],
\&final_compare
],
[ "enveloped content test streaming S/MIME format, DES, 3 recipients, keyid", [ "enveloped content test streaming S/MIME format, DES, 3 recipients, keyid",
[ "{cmd1}", "-encrypt", "-in", $smcont, [ "{cmd1}", "-encrypt", "-in", $smcont,
"-stream", "-out", "{output}.cms", "-keyid", "-stream", "-out", "{output}.cms", "-keyid",
@ -360,6 +340,87 @@ my @smime_cms_tests = (
); );
my @smime_cms_cades_tests = (
[ "signed content DER format, RSA key, CAdES-BES compatible",
[ "{cmd1}", "-sign", "-cades", "-in", $smcont, "-outform", "DER",
"-nodetach",
"-certfile", catfile($smdir, "smroot.pem"),
"-signer", catfile($smdir, "smrsa1.pem"), "-out", "{output}.cms" ],
[ "{cmd2}", "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
"-CAfile", catfile($smdir, "smroot.pem"), "-out", "{output}.txt" ],
\&final_compare
],
[ "signed content DER format, RSA key, SHA256 md, CAdES-BES compatible",
[ "{cmd1}", "-sign", "-cades", "-md", "sha256", "-in", $smcont, "-outform",
"DER", "-nodetach", "-certfile", catfile($smdir, "smroot.pem"),
"-signer", catfile($smdir, "smrsa1.pem"), "-out", "{output}.cms" ],
[ "{cmd2}", "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
"-CAfile", catfile($smdir, "smroot.pem"), "-out", "{output}.txt" ],
\&final_compare
],
[ "signed content DER format, RSA key, SHA512 md, CAdES-BES compatible",
[ "{cmd1}", "-sign", "-cades", "-md", "sha512", "-in", $smcont, "-outform",
"DER", "-nodetach", "-certfile", catfile($smdir, "smroot.pem"),
"-signer", catfile($smdir, "smrsa1.pem"), "-out", "{output}.cms" ],
[ "{cmd2}", "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
"-CAfile", catfile($smdir, "smroot.pem"), "-out", "{output}.txt" ],
\&final_compare
],
[ "signed content DER format, RSA key, SHA256 md, CAdES-BES compatible",
[ "{cmd1}", "-sign", "-cades", "-binary", "-nodetach", "-nosmimecap", "-md", "sha256",
"-in", $smcont, "-outform", "DER",
"-certfile", catfile($smdir, "smroot.pem"),
"-signer", catfile($smdir, "smrsa1.pem"),
"-outform", "DER", "-out", "{output}.cms" ],
[ "{cmd2}", "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
"-CAfile", catfile($smdir, "smroot.pem"), "-out", "{output}.txt" ],
\&final_compare
],
[ "resigned content DER format, RSA key, SHA256 md, CAdES-BES compatible",
[ "{cmd1}", "-sign", "-cades", "-binary", "-nodetach", "-nosmimecap", "-md", "sha256",
"-in", $smcont, "-outform", "DER",
"-certfile", catfile($smdir, "smroot.pem"),
"-signer", catfile($smdir, "smrsa1.pem"),
"-outform", "DER", "-out", "{output}.cms" ],
[ "{cmd1}", "-resign", "-cades", "-binary", "-nodetach", "-nosmimecap", "-md", "sha256",
"-inform", "DER", "-in", "{output}.cms",
"-certfile", catfile($smdir, "smroot.pem"),
"-signer", catfile($smdir, "smrsa2.pem"),
"-outform", "DER", "-out", "{output}2.cms" ],
[ "{cmd2}", "-verify", "-cades", "-in", "{output}2.cms", "-inform", "DER",
"-CAfile", catfile($smdir, "smroot.pem"), "-out", "{output}.txt" ],
\&final_compare
],
);
my @smime_cms_cades_ko_tests = (
[ "signed content DER format, RSA key, but verified as CAdES-BES compatible",
[ "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
"-certfile", catfile($smdir, "smroot.pem"),
"-signer", catfile($smdir, "smrsa1.pem"), "-out", "{output}.cms" ],
[ "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
"-CAfile", catfile($smdir, "smroot.pem"), "-out", "{output}.txt" ],
\&final_compare
]
);
# cades options test - check that some combinations are rejected
my @smime_cms_cades_invalid_option_tests = (
[
[ "-cades", "-noattr" ],
],[
[ "-verify", "-cades", "-noattr" ],
],[
[ "-verify", "-cades", "-noverify" ],
],
);
my @smime_cms_comp_tests = ( my @smime_cms_comp_tests = (
[ "compressed content test streaming PEM format", [ "compressed content test streaming PEM format",
@ -491,7 +552,7 @@ my @smime_cms_param_tests = (
"-in", "{output}.cms", "-out", "{output}.txt" ], "-in", "{output}.cms", "-out", "{output}.txt" ],
\&final_compare \&final_compare
] ]
); );
my @contenttype_cms_test = ( my @contenttype_cms_test = (
[ "signed content test - check that content type is added to additional signerinfo, RSA keys", [ "signed content test - check that content type is added to additional signerinfo, RSA keys",
@ -542,7 +603,7 @@ sub runner_loop {
$x; $x;
} @$_; } @$_;
diag "CMD: openssl", join(" ", @cmd); diag "CMD: openssl ", join(" ", @cmd);
$ok &&= run(app(["openssl", @cmd])); $ok &&= run(app(["openssl", @cmd]));
$opts{input} = $opts{output}; $opts{input} = $opts{output};
} }
@ -654,6 +715,36 @@ subtest "CMS Decrypt message encrypted with OpenSSL 1.1.1\n" => sub {
} }
}; };
subtest "CAdES <=> CAdES consistency tests\n" => sub {
plan tests => (scalar @smime_cms_cades_tests);
runner_loop(prefix => 'cms-cades', cmd1 => 'cms', cmd2 => 'cms',
tests => [ @smime_cms_cades_tests ]);
};
subtest "CAdES; cms incompatible arguments tests\n" => sub {
plan tests => (scalar @smime_cms_cades_invalid_option_tests);
foreach (@smime_cms_cades_invalid_option_tests) {
ok(!run(app(["openssl", "cms", @{$$_[0]} ] )));
}
};
subtest "CAdES ko tests\n" => sub {
plan tests => (scalar @smime_cms_cades_ko_tests);
foreach (@smime_cms_cades_ko_tests) {
SKIP: {
my $skip_reason = check_availability($$_[0]);
skip $skip_reason, 1 if $skip_reason;
ok(run(app(["openssl", "cms", @{$$_[1]}]))
&& !run(app(["openssl", "cms", @{$$_[2]}])),
$$_[0]);
}
}
};
sub check_availability { sub check_availability {
my $tnam = shift; my $tnam = shift;