]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add CMS_NO_SIGNING_TIME flag to CMS_sign(), CMS_add1_signer()
authorPeter Juhasz <juhasz.peter@uhusystems.com>
Tue, 15 Jun 2021 23:23:27 +0000 (01:23 +0200)
committerTomas Mraz <tomas@openssl.org>
Thu, 26 Dec 2024 18:33:42 +0000 (19:33 +0100)
Previously there was no way to create a CMS SignedData signature without a
signing time attribute, because CMS_SignerInfo_sign added it unconditionally.
However, there is a use case (PAdES signatures) where this attribute is not
allowed, so this commit introduces a new flag to the CMS API that causes this
attribute to be omitted at signing time.

Also add -no_signing_time option to cms command.

Fixes #15777

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15783)

CHANGES.md
apps/cms.c
crypto/cms/cms_local.h
crypto/cms/cms_sd.c
doc/man1/openssl-cms.pod.in
doc/man3/CMS_add1_signer.pod
doc/man3/CMS_sign.pod
include/openssl/cms.h.in
test/recipes/80-test_cms.t

index d3e5f18ffda303f900b9c729302ce2c7f3bed7c2..5745c4f2b86743c1d49bf7f75527b23daf4b43f1 100644 (file)
@@ -95,6 +95,18 @@ OpenSSL 3.5
 
    *Ramkumar*
 
+ * Add CMS_NO_SIGNING_TIME flag to CMS_sign(), CMS_add1_signer()
+
+   Previously there was no way to create a CMS SignedData signature without a
+   signing time attribute, because CMS_SignerInfo_sign added it unconditionally.
+   However, there is a use case (PAdES signatures [ETSI EN 319 142-1](https://www.etsi.org/deliver/etsi_en/319100_319199/31914201/01.01.01_60/en_31914201v010101p.pdf) )
+   where this attribute is not allowed, so a new flag was added to the CMS API
+   that causes this attribute to be omitted at signing time.
+
+   The new `-no_signing_time` option of the `cms` command enables this flag.
+
+   *Juhász Péter*
+
 OpenSSL 3.4
 -----------
 
index d280b25d43329b43629f12bf04612afe244f8d48..11b7b923b3ed1bcaabe480df43d6e23429a087f3 100644 (file)
@@ -69,7 +69,8 @@ typedef enum OPTION_choice {
     OPT_DIGEST, OPT_DIGEST_CREATE, OPT_COMPRESS, OPT_UNCOMPRESS,
     OPT_ED_DECRYPT, OPT_ED_ENCRYPT, OPT_DEBUG_DECRYPT, OPT_TEXT,
     OPT_ASCIICRLF, OPT_NOINTERN, OPT_NOVERIFY, OPT_NOCERTS,
-    OPT_NOATTR, OPT_NODETACH, OPT_NOSMIMECAP, OPT_BINARY, OPT_KEYID,
+    OPT_NOATTR, OPT_NODETACH, OPT_NOSMIMECAP, OPT_NO_SIGNING_TIME,
+    OPT_BINARY, OPT_KEYID,
     OPT_NOSIGS, OPT_NO_CONTENT_VERIFY, OPT_NO_ATTR_VERIFY, OPT_INDEF,
     OPT_NOINDEF, OPT_CRLFEOL, OPT_NOOUT, OPT_RR_PRINT,
     OPT_RR_ALL, OPT_RR_FIRST, OPT_RCTFORM, OPT_CERTFILE, OPT_CAFILE,
@@ -186,6 +187,8 @@ const OPTIONS cms_options[] = {
      "Don't include signer's certificate when signing"},
     {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"},
     {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"},
+    {"no_signing_time", OPT_NO_SIGNING_TIME, '-',
+     "Omit the signing time attribute"},
     {"receipt_request_all", OPT_RR_ALL, '-',
      "When signing, create a receipt request for all recipients"},
     {"receipt_request_first", OPT_RR_FIRST, '-',
@@ -429,6 +432,9 @@ int cms_main(int argc, char **argv)
         case OPT_NOSMIMECAP:
             flags |= CMS_NOSMIMECAP;
             break;
+        case OPT_NO_SIGNING_TIME:
+            flags |= CMS_NO_SIGNING_TIME;
+            break;
         case OPT_BINARY:
             flags |= CMS_BINARY;
             break;
index 1d03fd7d7e2244de53cad7811cec679f36e2b1e4..8ed67f5c19f47f4f6ebd95dffaefb826eaad3c15 100644 (file)
@@ -100,6 +100,8 @@ struct CMS_SignerInfo_st {
     EVP_MD_CTX *mctx;
     EVP_PKEY_CTX *pctx;
     const CMS_CTX *cms_ctx;
+    /* Set to 1 if signing time attribute is to be omitted */
+    int omit_signing_time;
 };
 
 struct CMS_SignerIdentifier_st {
index 19c82567d1c9d0d22acabb48335757adb83c0b6d..aa83c7eaf880c0542e117a9219c3e14f97d50d57 100644 (file)
@@ -364,6 +364,7 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
     si->signer = signer;
     si->mctx = EVP_MD_CTX_new();
     si->pctx = NULL;
+    si->omit_signing_time = 0;
 
     if (si->mctx == NULL) {
         ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
@@ -456,6 +457,14 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
                 goto err;
             }
         }
+        if ((flags & CMS_NO_SIGNING_TIME) != 0) {
+            /*
+             * The signing-time signed attribute (NID_pkcs9_signingTime)
+             * would normally be added later, in CMS_SignerInfo_sign(),
+             * unless we set this flag here
+             */
+            si->omit_signing_time = 1;
+        }
         if (flags & CMS_CADES) {
             ESS_SIGNING_CERT *sc = NULL;
             ESS_SIGNING_CERT_V2 *sc2 = NULL;
@@ -839,7 +848,8 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si)
                     si->digestAlgorithm->algorithm, 0) <= 0)
         return 0;
 
-    if (CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1) < 0) {
+    if (!si->omit_signing_time
+        && CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1) < 0) {
         if (!cms_add1_signingTime(si, NULL))
             goto err;
     }
index db8517f94cd880bf8a4fca5fb095d4d0423b6f75..9b6fd2a134f1d9c018285ba2a2ab9dcef23fee25 100644 (file)
@@ -83,6 +83,7 @@ Signing options:
 [B<-nocerts>]
 [B<-noattr>]
 [B<-nosmimecap>]
+[B<-no_signing_time>]
 [B<-receipt_request_all>]
 [B<-receipt_request_first>]
 [B<-receipt_request_from> I<emailaddress>]
@@ -492,7 +493,12 @@ option they are not included.
 =item B<-nosmimecap>
 
 Exclude the list of supported algorithms from signed attributes, other options
-such as signing time and content type are still included.
+such as content type and (optionally) signing time are still included.
+
+=item B<-no_signing_time>
+
+Exclude the signing time from signed attributes, other options
+such as content type are still included.
 
 =item B<-receipt_request_all>, B<-receipt_request_first>
 
index 11afecb9050ee3c993883a514c641674f5eb77ce..3d994889aaaba7c521703c4f73198440cacaf5fa 100644 (file)
@@ -67,7 +67,8 @@ previously signed message.
 The SignedData structure includes several CMS signedAttributes including the
 signing time, the CMS content type and the supported list of ciphers in an
 SMIMECapabilities attribute. If B<CMS_NOATTR> is set then no signedAttributes
-will be used. If B<CMS_NOSMIMECAP> is set then just the SMIMECapabilities are
+will be used at all. If B<CMS_NOSMIMECAP> is set then the SMIMECapabilities
+will be omitted. If B<CMS_NO_SIGNING_TIME> is set then the signing time will be
 omitted.
 
 OpenSSL will by default identify signing certificates using issuer name
index 933f89a84bc44b4727afaaebb80d48bfa8e4066c..3380b1a1dd957dac0c81a8d0a55a1284d5b8e189 100644 (file)
@@ -60,7 +60,8 @@ otherwise the translation will corrupt it.
 The SignedData structure includes several CMS signedAttributes including the
 signing time, the CMS content type and the supported list of ciphers in an
 SMIMECapabilities attribute. If B<CMS_NOATTR> is set then no signedAttributes
-will be used. If B<CMS_NOSMIMECAP> is set then just the SMIMECapabilities are
+will be used at all. If B<CMS_NOSMIMECAP> is set then the SMIMECapabilities
+will be omitted. If B<CMS_NO_SIGNING_TIME> is set then the signing time will be
 omitted.
 
 If present the SMIMECapabilities attribute indicates support for the following
index 239667700aacd235576db484430853559bdb31c4..15e21aa5c50a1b65007c806e3eea395b6ba0b713 100644 (file)
@@ -96,6 +96,7 @@ CMS_ContentInfo *CMS_ContentInfo_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
 # define CMS_ASCIICRLF                   0x80000
 # define CMS_CADES                       0x100000
 # define CMS_USE_ORIGINATOR_KEYID        0x200000
+# define CMS_NO_SIGNING_TIME             0x400000
 
 const ASN1_OBJECT *CMS_get0_type(const CMS_ContentInfo *cms);
 
index 9ee474fd807bc615dd4844704d5bc928cfa01e8d..182460cd12e5eea2678ebb1b4a441b1933a14c26 100644 (file)
@@ -52,7 +52,7 @@ my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib)
 
 $no_rc2 = 1 if disabled("legacy");
 
-plan tests => 25;
+plan tests => 26;
 
 ok(run(test(["pkcs7_test"])), "test pkcs7");
 
@@ -1065,6 +1065,46 @@ subtest "CMS signed digest, DER format" => sub {
        "Verify CMS signed digest, DER format");
 };
 
+subtest "CMS signed digest, DER format, no signing time" => sub {
+    # This test also enables CAdES mode and disables S/MIME capabilities
+    # to approximate the kind of signature required for a PAdES-compliant
+    # PDF signature.
+    plan tests => 4;
+
+    # Pre-computed SHA256 digest of $smcont in hexadecimal form
+    my $digest = "ff236ef61b396355f75a4cc6e1c306d4c309084ae271a9e2ad6888f10a101b32";
+
+    my $sig_file = "signature.der";
+    ok(run(app(["openssl", "cms", @prov, "-sign", "-digest", $digest,
+                    "-outform", "DER",
+                    "-no_signing_time",
+                    "-nosmimecap",
+                    "-cades",
+                    "-certfile", catfile($smdir, "smroot.pem"),
+                    "-signer", catfile($smdir, "smrsa1.pem"),
+                    "-out", $sig_file])),
+        "CMS sign pre-computed digest, DER format, no signing time");
+
+    my $exit = 0;
+    my $dump = join "\n",
+               run(app(["openssl", "cms", @prov, "-cmsout", "-noout", "-print",
+                            "-in", $sig_file,
+                            "-inform", "DER"]),
+                   capture => 1,
+                   statusvar => $exit);
+
+    is($exit, 0, "Parse CMS signed digest, DER format, no signing time");
+    is(index($dump, 'signingTime'), -1,
+        "Check that CMS signed digest does not contain signing time");
+
+    ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
+                    "-inform", "DER",
+                    "-CAfile", catfile($smdir, "smroot.pem"),
+                    "-content", $smcont])),
+       "Verify CMS signed digest, DER format, no signing time");
+};
+
+
 subtest "CMS signed digest, S/MIME format" => sub {
     plan tests => 2;