[openssl] master update

dev at ddvo.net dev at ddvo.net
Wed May 19 07:24:24 UTC 2021


The branch master has been updated
       via  8a734d3aaf4e4784581b87cdf2a4b3e2c2403b97 (commit)
       via  1b96cc70eb466f12b5abd9d90900e875a2236509 (commit)
       via  6b83d032a64848a66b60ca54729bcd79493f36ef (commit)
       via  7c701c590d4b368fedf5dad222b4f3b8103b2381 (commit)
       via  184238794fe52353f5e042fa9b943fbc59a5b9cb (commit)
      from  c4fca3f705a220fba8e15354d57d258e69a2d9b4 (commit)


- Log -----------------------------------------------------------------
commit 8a734d3aaf4e4784581b87cdf2a4b3e2c2403b97
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Mon May 3 21:58:02 2021 +0200

    CMS_get0_SignerInfos(): Prevent spurious error on cms_get0_signed() failure
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/12959)

commit 1b96cc70eb466f12b5abd9d90900e875a2236509
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Mon Sep 28 08:29:59 2020 +0200

    apps/cms.c: Simplify make_receipt_request() and load_content_info(()
    
    Also improve adherence to code formatting rules.
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/12959)

commit 6b83d032a64848a66b60ca54729bcd79493f36ef
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Wed Sep 23 10:19:50 2020 +0200

    apps/cms.c: Make -sign and -verify handle binary input
    
    Fixes #8940
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/12959)

commit 7c701c590d4b368fedf5dad222b4f3b8103b2381
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Wed Sep 23 10:17:58 2020 +0200

    Make SMIME_read_CMS_ex() and SMIME_read_ASN1_ex() support binary input
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/12959)

commit 184238794fe52353f5e042fa9b943fbc59a5b9cb
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Wed Sep 23 10:11:53 2020 +0200

    bio_lib: Add BIO_get_line, correct doc of BIO_gets
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/12959)

-----------------------------------------------------------------------

Summary of changes:
 apps/cms.c                   | 104 ++++++++++++++++++++++++++-----------------
 crypto/asn1/asn_mime.c       |  82 +++++++++++++++++++++++-----------
 crypto/bio/bio_lib.c         |  31 +++++++++++++
 crypto/cms/cms_io.c          |   6 +--
 crypto/cms/cms_sd.c          |   6 ++-
 crypto/pkcs7/pk7_mime.c      |   2 +-
 doc/man3/BIO_read.pod        |  35 ++++++++++++---
 doc/man3/SMIME_read_ASN1.pod |  13 ++++--
 doc/man3/SMIME_read_CMS.pod  |  12 +++--
 include/openssl/asn1.h.in    |   2 +-
 include/openssl/bio.h.in     |   1 +
 include/openssl/cms.h.in     |   2 +-
 test/recipes/80-test_cms.t   |  47 +++++++++++++++++--
 test/smcont.bin              | Bin 0 -> 8000 bytes
 util/libcrypto.num           |   1 +
 15 files changed, 250 insertions(+), 94 deletions(-)
 create mode 100644 test/smcont.bin

diff --git a/apps/cms.c b/apps/cms.c
index f40049edac..d2225d51af 100644
--- a/apps/cms.c
+++ b/apps/cms.c
@@ -24,9 +24,9 @@
 static int save_certs(char *signerfile, STACK_OF(X509) *signers);
 static int cms_cb(int ok, X509_STORE_CTX *ctx);
 static void receipt_request_print(CMS_ContentInfo *cms);
-static CMS_ReceiptRequest *make_receipt_request(
-    STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst,
-    STACK_OF(OPENSSL_STRING) *rr_from, OSSL_LIB_CTX *libctx);
+static CMS_ReceiptRequest
+*make_receipt_request(STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst,
+                      STACK_OF(OPENSSL_STRING) *rr_from);
 static int cms_set_pkey_param(EVP_PKEY_CTX *pctx,
                               STACK_OF(OPENSSL_STRING) *param);
 
@@ -159,7 +159,7 @@ const OPTIONS cms_options[] = {
     {"nodetach", OPT_NODETACH, '-', "Use opaque signing"},
     {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"},
     {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"},
-    {"binary", OPT_BINARY, '-', "Don't translate message to text"},
+    {"binary", OPT_BINARY, '-', "Treat input as binary: do not translate to canonical form"},
     {"keyid", OPT_KEYID, '-', "Use subject key identifier"},
     {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"},
     {"nocerts", OPT_NOCERTS, '-',
@@ -227,21 +227,19 @@ const OPTIONS cms_options[] = {
     {NULL}
 };
 
-static CMS_ContentInfo *load_content_info(int informat, BIO *in, BIO **indata,
-                                          const char *name,
-                                          OSSL_LIB_CTX *libctx,
-                                          const char *propq)
+static CMS_ContentInfo *load_content_info(int informat, BIO *in, int flags,
+                                          BIO **indata, const char *name)
 {
     CMS_ContentInfo *ret, *ci;
 
-    ret = CMS_ContentInfo_new_ex(libctx, propq);
+    ret = CMS_ContentInfo_new_ex(app_get0_libctx(), app_get0_propq());
     if (ret == NULL) {
         BIO_printf(bio_err, "Error allocating CMS_contentinfo\n");
         return NULL;
     }
     switch (informat) {
     case FORMAT_SMIME:
-        ci = SMIME_read_CMS_ex(in, indata, &ret);
+        ci = SMIME_read_CMS_ex(in, flags, indata, &ret);
         break;
     case FORMAT_PEM:
         ci = PEM_read_bio_CMS(in, &ret, NULL, NULL);
@@ -258,11 +256,33 @@ static CMS_ContentInfo *load_content_info(int informat, BIO *in, BIO **indata,
         goto err;
     }
     return ret;
-err:
+ err:
     CMS_ContentInfo_free(ret);
     return NULL;
 }
 
+static void warn_binary(const char *file)
+{
+    BIO *bio;
+    unsigned char linebuf[1024], *cur, *end;
+    int len;
+
+    if ((bio = bio_open_default(file, 'r', FORMAT_BINARY)) == NULL)
+        return; /* cannot give a proper warning since there is an error */
+    while ((len = BIO_read(bio, linebuf, sizeof(linebuf))) > 0) {
+        end = linebuf + len;
+        for (cur = linebuf; cur < end; cur++) {
+            if (*cur == '\0' || *cur >= 0x80) {
+                BIO_printf(bio_err, "Warning: input file '%s' contains %s"
+                           " character; better use -binary option\n",
+                           file, *cur == '\0' ? "NUL" : "8-bit");
+                break;
+            }
+        }
+    }
+    BIO_free(bio);
+}
+
 int cms_main(int argc, char **argv)
 {
     CONF *conf = NULL;
@@ -452,8 +472,7 @@ int cms_main(int argc, char **argv)
                                 OPT_FMT_PEMDER | OPT_FMT_SMIME, &rctformat))
                     goto opthelp;
             } else {
-                rcms = load_content_info(rctformat, rctin, NULL, "recipient",
-                                         libctx, app_get0_propq());
+                rcms = load_content_info(rctformat, rctin, 0, NULL, "recipient");
             }
             break;
         case OPT_CERTFILE:
@@ -582,8 +601,8 @@ int cms_main(int argc, char **argv)
             signerfile = opt_arg();
             break;
         case OPT_ORIGINATOR:
-             originatorfile = opt_arg();
-             break;
+            originatorfile = opt_arg();
+            break;
         case OPT_INKEY:
             /* If previous -inkey argument add signer to list */
             if (keyfile != NULL) {
@@ -784,13 +803,12 @@ int cms_main(int argc, char **argv)
     if (!(operation & SMIME_SIGNERS))
         flags &= ~CMS_DETACHED;
 
-    if (!(operation & SMIME_OP))
-        if (flags & CMS_BINARY)
+    if ((flags & CMS_BINARY) != 0) {
+        if (!(operation & SMIME_OP))
             outformat = FORMAT_BINARY;
-
-    if (!(operation & SMIME_IP))
-        if (flags & CMS_BINARY)
+        if (!(operation & SMIME_IP))
             informat = FORMAT_BINARY;
+    }
 
     if (operation == SMIME_ENCRYPT) {
         if (!cipher) {
@@ -838,8 +856,8 @@ int cms_main(int argc, char **argv)
     if (originatorfile != NULL) {
         if ((originator = load_cert(originatorfile, FORMAT_UNDEF,
                                     "originator certificate file")) == NULL) {
-             ERR_print_errors(bio_err);
-             goto end;
+            ERR_print_errors(bio_err);
+            goto end;
         }
     }
 
@@ -867,16 +885,21 @@ int cms_main(int argc, char **argv)
             goto end;
     }
 
-    in = bio_open_default(infile, 'r', informat);
+    if ((flags & CMS_BINARY) == 0)
+        warn_binary(infile);
+    in = bio_open_default(infile, 'r',
+                          (flags & CMS_BINARY) != 0 ? FORMAT_BINARY : informat);
     if (in == NULL)
         goto end;
 
     if (operation & SMIME_IP) {
-        cms = load_content_info(informat, in, &indata, "SMIME", libctx, app_get0_propq());
+        cms = load_content_info(informat, in, flags, &indata, "SMIME");
         if (cms == NULL)
             goto end;
         if (contfile != NULL) {
             BIO_free(indata);
+            if ((flags & CMS_BINARY) == 0)
+                warn_binary(contfile);
             if ((indata = BIO_new_file(contfile, "rb")) == NULL) {
                 BIO_printf(bio_err, "Can't read content file %s\n", contfile);
                 goto end;
@@ -897,13 +920,13 @@ int cms_main(int argc, char **argv)
 
     if (rctfile != NULL) {
         char *rctmode = (rctformat == FORMAT_ASN1) ? "rb" : "r";
+
         if ((rctin = BIO_new_file(rctfile, rctmode)) == NULL) {
             BIO_printf(bio_err, "Can't open receipt file %s\n", rctfile);
             goto end;
         }
 
-        rcms = load_content_info(rctformat, rctin, NULL, "recipient", libctx,
-                                 app_get0_propq());
+        rcms = load_content_info(rctformat, rctin, 0, NULL, "recipient");
         if (rcms == NULL)
             goto end;
     }
@@ -938,7 +961,8 @@ int cms_main(int argc, char **argv)
         for (i = 0; i < sk_X509_num(encerts); i++) {
             CMS_RecipientInfo *ri;
             cms_key_param *kparam;
-            int tflags = flags | CMS_KEY_PARAM; /* This flag enforces allocating the EVP_PKEY_CTX for the recipient here */
+            int tflags = flags | CMS_KEY_PARAM;
+            /* This flag enforces allocating the EVP_PKEY_CTX for the recipient here */
             EVP_PKEY_CTX *pctx;
             X509 *x = sk_X509_value(encerts, i);
             int res;
@@ -1032,13 +1056,11 @@ int cms_main(int argc, char **argv)
             if (econtent_type != NULL)
                 CMS_set1_eContentType(cms, econtent_type);
 
-            if (rr_to != NULL) {
-                rr = make_receipt_request(rr_to, rr_allorfirst, rr_from, libctx);
-                if (rr == NULL) {
-                    BIO_puts(bio_err,
-                             "Signed Receipt Request Creation Error\n");
-                    goto end;
-                }
+            if (rr_to != NULL
+                && ((rr = make_receipt_request(rr_to, rr_allorfirst, rr_from))
+                    == NULL)) {
+                BIO_puts(bio_err, "Signed Receipt Request Creation Error\n");
+                goto end;
             }
         } else {
             flags |= CMS_REUSE_DIGEST;
@@ -1390,13 +1412,12 @@ static STACK_OF(GENERAL_NAMES) *make_names_stack(STACK_OF(OPENSSL_STRING) *ns)
     return NULL;
 }
 
-static CMS_ReceiptRequest *make_receipt_request(
-   STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst,
-   STACK_OF(OPENSSL_STRING) *rr_from,
-   OSSL_LIB_CTX *libctx)
+static CMS_ReceiptRequest
+*make_receipt_request(STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst,
+                      STACK_OF(OPENSSL_STRING) *rr_from)
 {
     STACK_OF(GENERAL_NAMES) *rct_to = NULL, *rct_from = NULL;
-    CMS_ReceiptRequest *rr;
+
     rct_to = make_names_stack(rr_to);
     if (rct_to == NULL)
         goto err;
@@ -1407,9 +1428,8 @@ static CMS_ReceiptRequest *make_receipt_request(
     } else {
         rct_from = NULL;
     }
-    rr = CMS_ReceiptRequest_create0_ex(NULL, -1, rr_allorfirst, rct_from,
-                                       rct_to, libctx);
-    return rr;
+    return CMS_ReceiptRequest_create0_ex(NULL, -1, rr_allorfirst, rct_from,
+                                         rct_to, app_get0_libctx());
  err:
     sk_GENERAL_NAMES_pop_free(rct_to, GENERAL_NAMES_free);
     return NULL;
diff --git a/crypto/asn1/asn_mime.c b/crypto/asn1/asn_mime.c
index 8ee0970dc6..68e0c5affd 100644
--- a/crypto/asn1/asn_mime.c
+++ b/crypto/asn1/asn_mime.c
@@ -54,7 +54,7 @@ static int mime_param_cmp(const MIME_PARAM *const *a,
                           const MIME_PARAM *const *b);
 static void mime_param_free(MIME_PARAM *param);
 static int mime_bound_check(char *line, int linelen, const char *bound, int blen);
-static int multi_split(BIO *bio, const char *bound, STACK_OF(BIO) **ret);
+static int multi_split(BIO *bio, int flags, const char *bound, STACK_OF(BIO) **ret);
 static int strip_eol(char *linebuf, int *plen, int flags);
 static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, const char *name);
 static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, const char *name);
@@ -209,9 +209,9 @@ static int asn1_write_micalg(BIO *out, STACK_OF(X509_ALGOR) *mdalgs)
             goto err;
 
         default:
-            if (have_unknown)
+            if (have_unknown) {
                 write_comma = 0;
-            else {
+            } else {
                 BIO_puts(out, "unknown");
                 have_unknown = 1;
             }
@@ -292,9 +292,9 @@ int SMIME_write_ASN1_ex(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
 
     /* Determine smime-type header */
 
-    if (ctype_nid == NID_pkcs7_enveloped)
+    if (ctype_nid == NID_pkcs7_enveloped) {
         msg_type = "enveloped-data";
-    else if (ctype_nid == NID_pkcs7_signed) {
+    } else if (ctype_nid == NID_pkcs7_signed) {
         if (econt_nid == NID_id_smime_ct_receipt)
             msg_type = "signed-receipt";
         else if (sk_X509_ALGOR_num(mdalgs) >= 0)
@@ -388,7 +388,7 @@ static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags,
  * opaque this is set to NULL
  */
 
-ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, BIO **bcont, const ASN1_ITEM *it,
+ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont, const ASN1_ITEM *it,
                                ASN1_VALUE **x)
 {
     BIO *asnin;
@@ -424,7 +424,7 @@ ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, BIO **bcont, const ASN1_ITEM *it,
             ERR_raise(ERR_LIB_ASN1, ASN1_R_NO_MULTIPART_BOUNDARY);
             return NULL;
         }
-        ret = multi_split(bio, prm->param_value, &parts);
+        ret = multi_split(bio, flags, prm->param_value, &parts);
         sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
         if (!ret || (sk_BIO_num(parts) != 2)) {
             ERR_raise(ERR_LIB_ASN1, ASN1_R_NO_MULTIPART_BODY_FAILURE);
@@ -471,8 +471,9 @@ ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, BIO **bcont, const ASN1_ITEM *it,
             *bcont = sk_BIO_value(parts, 0);
             BIO_free(asnin);
             sk_BIO_free(parts);
-        } else
+        } else {
             sk_BIO_pop_free(parts, BIO_vfree);
+        }
         return val;
     }
 
@@ -497,7 +498,7 @@ ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, BIO **bcont, const ASN1_ITEM *it,
 
 ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it)
 {
-    return SMIME_read_ASN1_ex(bio, bcont, it, NULL);
+    return SMIME_read_ASN1_ex(bio, 0, bcont, it, NULL);
 }
 
 /* Copy text from one BIO to another making the output CRLF at EOL */
@@ -524,7 +525,7 @@ int SMIME_crlf_copy(BIO *in, BIO *out, int flags)
             BIO_printf(out, "Content-Type: text/plain\r\n\r\n");
         while ((len = BIO_gets(in, linebuf, MAX_SMLEN)) > 0) {
             eol = strip_eol(linebuf, &len, flags);
-            if (len) {
+            if (len > 0) {
                 /* Not EOF: write out all CRLF */
                 if (flags & SMIME_ASCIICRLF) {
                     int i;
@@ -535,10 +536,11 @@ int SMIME_crlf_copy(BIO *in, BIO *out, int flags)
                 BIO_write(out, linebuf, len);
                 if (eol)
                     BIO_write(out, "\r\n", 2);
-            } else if (flags & SMIME_ASCIICRLF)
+            } else if (flags & SMIME_ASCIICRLF) {
                 eolcnt++;
-            else if (eol)
+            } else if (eol) {
                 BIO_write(out, "\r\n", 2);
+            }
         }
     }
     (void)BIO_flush(out);
@@ -584,7 +586,7 @@ int SMIME_text(BIO *in, BIO *out)
  * canonical parts in a STACK of bios
  */
 
-static int multi_split(BIO *bio, const char *bound, STACK_OF(BIO) **ret)
+static int multi_split(BIO *bio, int flags, const char *bound, STACK_OF(BIO) **ret)
 {
     char linebuf[MAX_SMLEN];
     int len, blen;
@@ -601,7 +603,7 @@ static int multi_split(BIO *bio, const char *bound, STACK_OF(BIO) **ret)
     *ret = parts;
     if (*ret == NULL)
         return 0;
-    while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
+    while ((len = BIO_get_line(bio, linebuf, MAX_SMLEN)) > 0) {
         state = mime_bound_check(linebuf, len, bound, blen);
         if (state == 1) {
             first = 1;
@@ -612,9 +614,9 @@ static int multi_split(BIO *bio, const char *bound, STACK_OF(BIO) **ret)
                 return 0;
             }
             return 1;
-        } else if (part) {
-            /* Strip CR+LF from linebuf */
-            next_eol = strip_eol(linebuf, &len, 0);
+        } else if (part != 0) {
+            /* Strip (possibly CR +) LF from linebuf */
+            next_eol = strip_eol(linebuf, &len, flags);
             if (first) {
                 first = 0;
                 if (bpart)
@@ -626,10 +628,20 @@ static int multi_split(BIO *bio, const char *bound, STACK_OF(BIO) **ret)
                 if (bpart == NULL)
                     return 0;
                 BIO_set_mem_eof_return(bpart, 0);
-            } else if (eol)
-                BIO_write(bpart, "\r\n", 2);
+            } else if (eol) {
+                if (
+#ifndef OPENSSL_NO_CMS
+                    (flags & CMS_BINARY) == 0
+#else
+                    1
+#endif
+                        || (flags & SMIME_CRLFEOL) != 0)
+                    BIO_write(bpart, "\r\n", 2);
+                else
+                    BIO_write(bpart, "\n", 1);
+            }
             eol = next_eol;
-            if (len)
+            if (len > 0)
                 BIO_write(bpart, linebuf, len);
         }
     }
@@ -753,15 +765,16 @@ static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio)
                 goto err;
             mhdr = new_hdr;
             new_hdr = NULL;
-        } else if (state == MIME_VALUE)
+        } else if (state == MIME_VALUE) {
             mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
+        }
         if (p == linebuf)
             break;              /* Blank line means end of headers */
     }
 
     return headers;
 
-err:
+ err:
     mime_hdr_free(new_hdr);
     sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
     return NULL;
@@ -883,8 +896,8 @@ static int mime_hdr_addparam(MIME_HEADER *mhdr, const char *name, const char *va
 static int mime_hdr_cmp(const MIME_HEADER *const *a,
                         const MIME_HEADER *const *b)
 {
-    if (!(*a)->name || !(*b)->name)
-        return ! !(*a)->name - ! !(*b)->name;
+    if ((*a)->name == NULL || (*b)->name == NULL)
+        return ((*a)->name != NULL) - ((*b)->name != NULL);
 
     return strcmp((*a)->name, (*b)->name);
 }
@@ -892,8 +905,8 @@ static int mime_hdr_cmp(const MIME_HEADER *const *a,
 static int mime_param_cmp(const MIME_PARAM *const *a,
                           const MIME_PARAM *const *b)
 {
-    if (!(*a)->param_name || !(*b)->param_name)
-        return ! !(*a)->param_name - ! !(*b)->param_name;
+    if ((*a)->param_name == NULL || (*b)->param_name == NULL)
+        return ((*a)->param_name != NULL) - ((*b)->param_name != NULL);
     return strcmp((*a)->param_name, (*b)->param_name);
 }
 
@@ -973,11 +986,26 @@ static int strip_eol(char *linebuf, int *plen, int flags)
     char *p, c;
     int is_eol = 0;
 
+#ifndef OPENSSL_NO_CMS
+    if ((flags & CMS_BINARY) != 0) {
+        if (len <= 0 || linebuf[len - 1] != '\n')
+            return 0;
+        if ((flags & SMIME_CRLFEOL) != 0) {
+            if (len <= 1 || linebuf[len - 2] != '\r')
+                return 0;
+            len--;
+        }
+        len--;
+        *plen = len;
+        return 1;
+    }
+#endif
+
     for (p = linebuf + len - 1; len > 0; len--, p--) {
         c = *p;
         if (c == '\n') {
             is_eol = 1;
-        } else if (is_eol && flags & SMIME_ASCIICRLF && c == 32) {
+        } else if (is_eol && (flags & SMIME_ASCIICRLF) != 0 && c == 32) {
             /* Strip trailing space on a line; 32 == ASCII for ' ' */
             continue;
         } else if (c != '\r') {
diff --git a/crypto/bio/bio_lib.c b/crypto/bio/bio_lib.c
index 3fa8ff4f16..9f25376e95 100644
--- a/crypto/bio/bio_lib.c
+++ b/crypto/bio/bio_lib.c
@@ -477,6 +477,37 @@ int BIO_gets(BIO *b, char *buf, int size)
     return ret;
 }
 
+int BIO_get_line(BIO *bio, char *buf, int size)
+{
+    int ret = 0;
+    char *ptr = buf;
+
+    if (buf == NULL) {
+        ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+        return -1;
+    }
+    if (size <= 0) {
+        ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
+        return -1;
+    }
+    *buf = '\0';
+
+    if (bio == NULL) {
+        ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+        return -1;
+    }
+    if (!bio->init) {
+        ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
+        return -1;
+    }
+
+    while (size-- > 1 && (ret = BIO_read(bio, ptr, 1)) > 0)
+        if (*ptr++ == '\n')
+            break;
+    *ptr = '\0';
+    return ret > 0 || BIO_eof(bio) ? ptr - buf : ret;
+}
+
 int BIO_indent(BIO *b, int indent, int max)
 {
     if (indent < 0)
diff --git a/crypto/cms/cms_io.c b/crypto/cms/cms_io.c
index 6b71ddfa90..9c260d0904 100644
--- a/crypto/cms/cms_io.c
+++ b/crypto/cms/cms_io.c
@@ -90,11 +90,11 @@ int SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags)
                                ossl_cms_ctx_get0_propq(ctx));
 }
 
-CMS_ContentInfo *SMIME_read_CMS_ex(BIO *bio, BIO **bcont, CMS_ContentInfo **cms)
+CMS_ContentInfo *SMIME_read_CMS_ex(BIO *bio, int flags, BIO **bcont, CMS_ContentInfo **cms)
 {
     CMS_ContentInfo *ci;
 
-    ci = (CMS_ContentInfo *)SMIME_read_ASN1_ex(bio, bcont,
+    ci = (CMS_ContentInfo *)SMIME_read_ASN1_ex(bio, flags, bcont,
                                                ASN1_ITEM_rptr(CMS_ContentInfo),
                                                (ASN1_VALUE **)cms);
     if (ci != NULL)
@@ -104,5 +104,5 @@ CMS_ContentInfo *SMIME_read_CMS_ex(BIO *bio, BIO **bcont, CMS_ContentInfo **cms)
 
 CMS_ContentInfo *SMIME_read_CMS(BIO *bio, BIO **bcont)
 {
-    return SMIME_read_CMS_ex(bio, bcont, NULL);
+    return SMIME_read_CMS_ex(bio, 0, bcont, NULL);
 }
diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c
index d208822c4b..c0235b6962 100644
--- a/crypto/cms/cms_sd.c
+++ b/crypto/cms/cms_sd.c
@@ -496,9 +496,13 @@ void ossl_cms_SignerInfos_set_cmsctx(CMS_ContentInfo *cms)
 {
     int i;
     CMS_SignerInfo *si;
-    STACK_OF(CMS_SignerInfo) *sinfos = CMS_get0_SignerInfos(cms);
+    STACK_OF(CMS_SignerInfo) *sinfos;
     const CMS_CTX *ctx = ossl_cms_get0_cmsctx(cms);
 
+    ERR_set_mark();
+    sinfos = CMS_get0_SignerInfos(cms);
+    ERR_pop_to_mark(); /* removes error in case sinfos == NULL */
+
     for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
         si = sk_CMS_SignerInfo_value(sinfos, i);
         if (si != NULL)
diff --git a/crypto/pkcs7/pk7_mime.c b/crypto/pkcs7/pk7_mime.c
index e191e4e3b8..b446423384 100644
--- a/crypto/pkcs7/pk7_mime.c
+++ b/crypto/pkcs7/pk7_mime.c
@@ -50,7 +50,7 @@ PKCS7 *SMIME_read_PKCS7_ex(BIO *bio, BIO **bcont, PKCS7 **p7)
 {
     PKCS7 *ret;
 
-    ret = (PKCS7 *)SMIME_read_ASN1_ex(bio, bcont, ASN1_ITEM_rptr(PKCS7),
+    ret = (PKCS7 *)SMIME_read_ASN1_ex(bio, 0, bcont, ASN1_ITEM_rptr(PKCS7),
                                       (ASN1_VALUE **)p7);
     if (ret != NULL)
         ossl_pkcs7_resolve_libctx(ret);
diff --git a/doc/man3/BIO_read.pod b/doc/man3/BIO_read.pod
index abaf4cb6a4..3b89b25a34 100644
--- a/doc/man3/BIO_read.pod
+++ b/doc/man3/BIO_read.pod
@@ -2,7 +2,8 @@
 
 =head1 NAME
 
-BIO_read_ex, BIO_write_ex, BIO_read, BIO_write, BIO_gets, BIO_puts
+BIO_read_ex, BIO_write_ex, BIO_read, BIO_write,
+BIO_gets, BIO_get_line, BIO_puts
 - BIO I/O functions
 
 =head1 SYNOPSIS
@@ -14,6 +15,7 @@ BIO_read_ex, BIO_write_ex, BIO_read, BIO_write, BIO_gets, BIO_puts
 
  int BIO_read(BIO *b, void *data, int dlen);
  int BIO_gets(BIO *b, char *buf, int size);
+ int BIO_get_line(BIO *b, char *buf, int size);
  int BIO_write(BIO *b, const void *data, int dlen);
  int BIO_puts(BIO *b, const char *buf);
 
@@ -36,6 +38,16 @@ however; for example, BIO_gets() on a digest BIO will calculate and
 return the digest and other BIOs may not support BIO_gets() at all.
 The returned string is always NUL-terminated and the '\n' is preserved
 if present in the input data.
+On binary input there may be NUL characters within the string;
+in this case the return value (if nonnegative) may give an incorrect length.
+
+BIO_get_line() attempts to read from BIO <b> a line of data up to the next '\n'
+or the maximum length B<size-1> is reached and places the data in B<buf>.
+The returned string is always NUL-terminated and the '\n' is preserved
+if present in the input data.
+On binary input there may be NUL characters within the string;
+in this case the return value (if nonnegative) gives the actual length read.
+For implementing this, unfortunately the data needs to be read byte-by-byte.
 
 BIO_write() attempts to write B<len> bytes from B<buf> to BIO B<b>.
 
@@ -46,11 +58,18 @@ BIO_puts() attempts to write a NUL-terminated string B<buf> to BIO B<b>.
 BIO_read_ex() and BIO_write_ex() return 1 if data was successfully read or
 written, and 0 otherwise.
 
+BIO_gets() returns -2 if the "gets" operation is not implemented by the BIO
+or -1 on other errors.
+Otherwise it typically returns the amount of data read,
+but depending on the implementation it may return only the length up to
+the first NUL character contained in the data read.
+In any case the trailing NUL that is added after the data read
+is not included in the length returned.
+
 All other functions return either the amount of data successfully read or
 written (if the return value is positive) or that no data was successfully
 read or written if the result is 0 or -1. If the return value is -2 then
-the operation is not implemented in the specific BIO type.  The trailing
-NUL is not included in the length returned by BIO_gets().
+the operation is not implemented in the specific BIO type.
 
 =head1 NOTES
 
@@ -72,9 +91,9 @@ a retry instead of blocking.
 See L<BIO_should_retry(3)> for details of how to
 determine the cause of a retry and other I/O issues.
 
-If the BIO_gets() function is not supported by a BIO then it possible to
-work around this by adding a buffering BIO L<BIO_f_buffer(3)>
-to the chain.
+If the "gets" method is not supported by a BIO then BIO_get_line() can be used.
+It is also possible to make BIO_gets() usable even if the "gets" method is not
+supported by adding a buffering BIO L<BIO_f_buffer(3)> to the chain.
 
 =head1 SEE ALSO
 
@@ -82,9 +101,11 @@ L<BIO_should_retry(3)>
 
 =head1 HISTORY
 
-BIO_gets() on 1.1.0 and older when called on BIO_fd() based BIO does not
+BIO_gets() on 1.1.0 and older when called on BIO_fd() based BIO did not
 keep the '\n' at the end of the line in the buffer.
 
+BIO_get_line() was added in OpenSSL 3.0.
+
 =head1 COPYRIGHT
 
 Copyright 2000-2020 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man3/SMIME_read_ASN1.pod b/doc/man3/SMIME_read_ASN1.pod
index 189c1ef5e4..cb4a2ac9f9 100644
--- a/doc/man3/SMIME_read_ASN1.pod
+++ b/doc/man3/SMIME_read_ASN1.pod
@@ -9,15 +9,20 @@ SMIME_read_ASN1_ex, SMIME_read_ASN1
 
  #include <openssl/asn1.h>
 
- ASN1_VALUE *SMIME_read_ASN1_ex(BIO *in, BIO **bcont, const ASN1_ITEM *it,
-                                ASN1_VALUE **x);
+ ASN1_VALUE *SMIME_read_ASN1_ex(BIO *in, int flags, BIO **bcont,
+                                const ASN1_ITEM *it, ASN1_VALUE **x);
  ASN1_VALUE *SMIME_read_ASN1(BIO *in, BIO **bcont, const ASN1_ITEM *it);
 
 =head1 DESCRIPTION
 
 SMIME_read_ASN1_ex() parses a message in S/MIME format.
 
-I<in> is a BIO to read the message from. I<x> can be used to optionally supply
+I<in> is a BIO to read the message from.
+If the I<flags> argument contains B<CMS_BINARY> then the input is assumed to be
+in binary format and is not translated to canonical form.
+If in addition B<SMIME_ASCIICRLF> is set then the binary input is assumed
+to be followed by B<CR> and B<LF> characters, else only by an B<LF> character.
+I<x> can be used to optionally supply
 a previously created I<it> ASN1_VALUE object (such as CMS_ContentInfo or PKCS7),
 it can be set to NULL. Valid values that can be used by ASN.1 structure I<it>
 are ASN1_ITEM_rptr(PKCS7) or ASN1_ITEM_rptr(CMS_ContentInfo).
@@ -28,7 +33,7 @@ written to I<*bcont>, otherwise I<*bcont> is set to NULL.
 The parsed ASN1_VALUE structure is returned or NULL if an error occurred.
 
 SMIME_read_ASN1() is similar to SMIME_read_ASN1_ex() but sets the value of I<x>
-to NULL.
+to NULL and the value of I<flags> to 0.
 
 =head1 NOTES
 
diff --git a/doc/man3/SMIME_read_CMS.pod b/doc/man3/SMIME_read_CMS.pod
index 36ef6dc846..9f0c855263 100644
--- a/doc/man3/SMIME_read_CMS.pod
+++ b/doc/man3/SMIME_read_CMS.pod
@@ -8,7 +8,7 @@ SMIME_read_CMS_ex, SMIME_read_CMS - parse S/MIME message
 
  #include <openssl/cms.h>
 
- CMS_ContentInfo *SMIME_read_CMS_ex(BIO *bio, BIO **bcont,
+ CMS_ContentInfo *SMIME_read_CMS_ex(BIO *bio, int flags, BIO **bcont,
                                     CMS_ContentInfo **cms);
  CMS_ContentInfo *SMIME_read_CMS(BIO *in, BIO **bcont);
 
@@ -24,10 +24,14 @@ written to B<*bcont>, otherwise B<*bcont> is set to NULL.
 The parsed CMS_ContentInfo structure is returned or NULL if an
 error occurred.
 
-SMIME_read_CMS_ex() is similar to SMIME_read_CMS() but can optionally supply a
-previously created I<cms> CMS_ContentInfo object. If I<cms> is NULL then it is
-identical to SMIME_read_CMS().
+SMIME_read_CMS_ex() is similar to SMIME_read_CMS() but optionally a previously
+created I<cms> CMS_ContentInfo object can be supplied as well as some I<flags>.
 To create a I<cms> object use L<CMS_ContentInfo_new_ex(3)>.
+If the I<flags> argument contains B<CMS_BINARY> then the input is assumed to be
+in binary format and is not translated to canonical form.
+If in addition B<SMIME_ASCIICRLF> is set then the binary input is assumed
+to be followed by B<CR> and B<LF> characters, else only by an B<LF> character.
+If I<flags> is 0 and I<cms> is NULL then it is identical to SMIME_read_CMS().
 
 =head1 NOTES
 
diff --git a/include/openssl/asn1.h.in b/include/openssl/asn1.h.in
index 0ee82e7d58..36abcff28c 100644
--- a/include/openssl/asn1.h.in
+++ b/include/openssl/asn1.h.in
@@ -919,7 +919,7 @@ int SMIME_write_ASN1_ex(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
                         STACK_OF(X509_ALGOR) *mdalgs, const ASN1_ITEM *it,
                         OSSL_LIB_CTX *libctx, const char *propq);
 ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it);
-ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, BIO **bcont, const ASN1_ITEM *it,
+ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont, const ASN1_ITEM *it,
                                ASN1_VALUE **x);
 int SMIME_crlf_copy(BIO *in, BIO *out, int flags);
 int SMIME_text(BIO *in, BIO *out);
diff --git a/include/openssl/bio.h.in b/include/openssl/bio.h.in
index 66ebfc5c7e..4e2fbb5f07 100644
--- a/include/openssl/bio.h.in
+++ b/include/openssl/bio.h.in
@@ -609,6 +609,7 @@ int BIO_up_ref(BIO *a);
 int BIO_read(BIO *b, void *data, int dlen);
 int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes);
 int BIO_gets(BIO *bp, char *buf, int size);
+int BIO_get_line(BIO *bio, char *buf, int size);
 int BIO_write(BIO *b, const void *data, int dlen);
 int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written);
 int BIO_puts(BIO *bp, const char *buf);
diff --git a/include/openssl/cms.h.in b/include/openssl/cms.h.in
index 451191b796..da20ddf2f4 100644
--- a/include/openssl/cms.h.in
+++ b/include/openssl/cms.h.in
@@ -114,7 +114,7 @@ int i2d_CMS_bio_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags);
 int PEM_write_bio_CMS_stream(BIO *out, CMS_ContentInfo *cms, BIO *in,
                              int flags);
 CMS_ContentInfo *SMIME_read_CMS(BIO *bio, BIO **bcont);
-CMS_ContentInfo *SMIME_read_CMS_ex(BIO *bio, BIO **bcont, CMS_ContentInfo **ci);
+CMS_ContentInfo *SMIME_read_CMS_ex(BIO *bio, int flags, BIO **bcont, CMS_ContentInfo **ci);
 int SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags);
 
 int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont,
diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t
index a371f21ad8..0e20b807c8 100644
--- a/test/recipes/80-test_cms.t
+++ b/test/recipes/80-test_cms.t
@@ -12,7 +12,7 @@ use warnings;
 
 use POSIX;
 use File::Spec::Functions qw/catfile/;
-use File::Compare qw/compare_text/;
+use File::Compare qw/compare_text compare/;
 use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file bldtop_dir bldtop_file/;
 
 use OpenSSL::Test::Utils;
@@ -50,8 +50,7 @@ my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib)
 
 $no_rc2 = 1 if disabled("legacy");
 
-plan tests =>
-    + 10;
+plan tests => 11;
 
 unless ($no_fips) {
     @config = ( "-config", srctop_file("test", "fips-and-base.cnf") );
@@ -812,6 +811,48 @@ subtest "CAdES ko tests\n" => sub {
     }
 };
 
+subtest "CMS binary input tests\n" => sub {
+    my $input = srctop_file("test", "smcont.bin");
+    my $signed = "smcont.signed";
+    my $verified = "smcont.verified";
+    my $cert = srctop_file("test", "certs", "ee-self-signed.pem");
+    my $key = srctop_file("test", "certs", "ee-key.pem");
+
+    plan tests => 11;
+
+    ok(run(app(["openssl", "cms", "-sign", "-md", "sha256",
+                "-signer", $cert, "-inkey", $key,
+                "-binary", "-in", $input, "-out", $signed])),
+       "sign binary input with -binary");
+    ok(run(app(["openssl", "cms", "-verify", "-CAfile", $cert,
+                "-binary", "-in", $signed, "-out", $verified])),
+       "verify binary input with -binary");
+    is(compare($input, $verified), 0, "binary input retained with -binary");
+    ok(run(app(["openssl", "cms", "-sign", "-md", "sha256",
+                "-signer", $cert, "-inkey", $key,
+                "-in", $input, "-out", $signed])),
+       "sign binary input without -binary");
+    ok(run(app(["openssl", "cms", "-verify", "-CAfile", $cert,
+                "-in", $signed, "-out", $verified])),
+       "verify binary input without -binary");
+    is(compare($input, $verified), 1, "binary input not retained without -binary");
+    ok(!run(app(["openssl", "cms", "-verify", "-CAfile", $cert, "-crlfeol",
+                "-binary", "-in", $signed, "-out", $verified])),
+       "verify binary input wrong crlfeol");
+
+    ok(run(app(["openssl", "cms", "-sign", "-md", "sha256", "-crlfeol",
+                "-signer", $cert, "-inkey", $key,
+                "-binary", "-in", $input, "-out", $signed.".crlf"])),
+       "sign binary input crlfeol");
+    ok(run(app(["openssl", "cms", "-verify", "-CAfile", $cert, "-crlfeol",
+                "-binary", "-in", $signed.".crlf", "-out", $verified.".crlf"])),
+       "verify binary input crlfeol");
+    is(compare($input, $verified.".crlf"), 0);
+    ok(!run(app(["openssl", "cms", "-verify", "-CAfile", $cert,
+                "-binary", "-in", $signed.".crlf", "-out", $verified.".crlf"])),
+       "verify binary input missing crlfeol");
+};
+
 sub check_availability {
     my $tnam = shift;
 
diff --git a/test/smcont.bin b/test/smcont.bin
new file mode 100644
index 0000000000..2a5ce10224
Binary files /dev/null and b/test/smcont.bin differ
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 67bf50af4d..f83bb186e2 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5409,6 +5409,7 @@ PKCS5_pbkdf2_set_ex                     ?	3_0_0	EXIST::FUNCTION:
 BIO_new_from_core_bio                   ?	3_0_0	EXIST::FUNCTION:
 BIO_new_ex                              ?	3_0_0	EXIST::FUNCTION:
 BIO_s_core                              ?	3_0_0	EXIST::FUNCTION:
+BIO_get_line                            ?	3_0_0	EXIST::FUNCTION:
 OSSL_LIB_CTX_new_from_dispatch          ?	3_0_0	EXIST::FUNCTION:
 OSSL_LIB_CTX_new_child                  ?	3_0_0	EXIST::FUNCTION:
 OSSL_PROVIDER_get0_dispatch             ?	3_0_0	EXIST::FUNCTION:


More information about the openssl-commits mailing list