From 847865d0f9810a2f9c0eb7a5dc5d0c29f50b84ba Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 12 Feb 2014 15:15:55 +0000 Subject: [PATCH] Add suppot for ASCII with CRLF canonicalisation. --- apps/cms.c | 2 ++ crypto/asn1/asn_mime.c | 28 +++++++++++++++++++++++----- crypto/cms/cms.h | 1 + crypto/cms/cms_smime.c | 8 ++++++++ crypto/pkcs7/pkcs7.h | 3 +++ doc/apps/cms.pod | 10 ++++++++++ 6 files changed, 47 insertions(+), 5 deletions(-) diff --git a/apps/cms.c b/apps/cms.c index d15e203f9c..ddc3d5ec17 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -258,6 +258,8 @@ int MAIN(int argc, char **argv) flags |= CMS_DEBUG_DECRYPT; else if (!strcmp (*args, "-text")) flags |= CMS_TEXT; + else if (!strcmp (*args, "-asciicrlf")) + flags |= CMS_ASCIICRLF; else if (!strcmp (*args, "-nointern")) flags |= CMS_NOINTERN; else if (!strcmp (*args, "-noverify") diff --git a/crypto/asn1/asn_mime.c b/crypto/asn1/asn_mime.c index 54a704a969..120889350c 100644 --- a/crypto/asn1/asn_mime.c +++ b/crypto/asn1/asn_mime.c @@ -102,7 +102,7 @@ static int mime_param_cmp(const MIME_PARAM * const *a, static void mime_param_free(MIME_PARAM *param); static int mime_bound_check(char *line, int linelen, char *bound, int blen); static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret); -static int strip_eol(char *linebuf, int *plen); +static int strip_eol(char *linebuf, int *plen, int flags); static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, char *name); static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name); static void mime_hdr_free(MIME_HEADER *hdr); @@ -554,14 +554,30 @@ int SMIME_crlf_copy(BIO *in, BIO *out, int flags) } else { + int eolcnt = 0; if(flags & SMIME_TEXT) 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); + eol = strip_eol(linebuf, &len, flags); if (len) + { + /* Not EOF: write out all CRLF */ + if (flags & SMIME_ASCIICRLF) + { + int i; + for(i = 0; i < eolcnt; i++) + BIO_write(out, "\r\n", 2); + eolcnt = 0; + } BIO_write(out, linebuf, len); - if(eol) BIO_write(out, "\r\n", 2); + if(eol) + BIO_write(out, "\r\n", 2); + } + else if (flags & SMIME_ASCIICRLF) + eolcnt++; + else if(eol) + BIO_write(out, "\r\n", 2); } } (void)BIO_flush(out); @@ -630,7 +646,7 @@ static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret) return 1; } else if(part) { /* Strip CR+LF from linebuf */ - next_eol = strip_eol(linebuf, &len); + next_eol = strip_eol(linebuf, &len, 0); if(first) { first = 0; if(bpart) sk_BIO_push(parts, bpart); @@ -932,7 +948,7 @@ static int mime_bound_check(char *line, int linelen, char *bound, int blen) return 0; } -static int strip_eol(char *linebuf, int *plen) +static int strip_eol(char *linebuf, int *plen, int flags) { int len = *plen; char *p, c; @@ -943,6 +959,8 @@ static int strip_eol(char *linebuf, int *plen) c = *p; if (c == '\n') is_eol = 1; + else if (is_eol && flags & SMIME_ASCIICRLF && c < 33) + continue; else if (c != '\r') break; } diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h index 4b36a69c4f..0d1649ab21 100644 --- a/crypto/cms/cms.h +++ b/crypto/cms/cms.h @@ -117,6 +117,7 @@ DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo) #define CMS_USE_KEYID 0x10000 #define CMS_DEBUG_DECRYPT 0x20000 #define CMS_KEY_PARAM 0x40000 +#define CMS_ASCIICRLF 0x80000 const ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms); diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index 8f1aa38ccc..e907b279ea 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -334,6 +334,12 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, if (!dcont && !check_content(cms)) return 0; + if (dcont && !(flags & CMS_BINARY)) + { + const ASN1_OBJECT *coid = CMS_get0_eContentType(cms); + if (OBJ_obj2nid(coid) == NID_id_ct_asciiTextWithCRLF) + flags |= CMS_ASCIICRLF; + } /* Attempt to find all signer certificates */ @@ -519,6 +525,8 @@ CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, cms = CMS_ContentInfo_new(); if (!cms || !CMS_SignedData_init(cms)) goto merr; + if (flags & CMS_ASCIICRLF && !CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_ct_asciiTextWithCRLF))) + goto err; if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) { diff --git a/crypto/pkcs7/pkcs7.h b/crypto/pkcs7/pkcs7.h index e4d443193c..267a64685a 100644 --- a/crypto/pkcs7/pkcs7.h +++ b/crypto/pkcs7/pkcs7.h @@ -276,6 +276,9 @@ DECLARE_PKCS12_STACK_OF(PKCS7) #define SMIME_BINARY PKCS7_BINARY #define SMIME_NOATTR PKCS7_NOATTR +/* CRLF ASCII canonicalisation */ +#define SMIME_ASCIICRLF 0x80000 + DECLARE_ASN1_FUNCTIONS(PKCS7_ISSUER_AND_SERIAL) int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data,const EVP_MD *type, diff --git a/doc/apps/cms.pod b/doc/apps/cms.pod index 29720a87f9..cfdc4cb134 100644 --- a/doc/apps/cms.pod +++ b/doc/apps/cms.pod @@ -43,6 +43,7 @@ B B [B<-noattr>] [B<-nosmimecap>] [B<-binary>] +[B<-asciicrlf>] [B<-nodetach>] [B<-certfile file>] [B<-certsout file>] @@ -291,6 +292,15 @@ effectively using CR and LF as end of line: as required by the S/MIME specification. When this option is present no translation occurs. This is useful when handling binary data which may not be in MIME format. +=item B<-asciicrlf> + +when signing use ASCII CRLF format canonicalisation. This strips trailing +whitespace from all lines, deletes trailing blank lines at EOF and sets +the encapsulated content type. This option is normally used with detached +content and an output signature format of DER. This option is not normally +needed when verifying as it is enabled automatically if the encapsulated +content format is detected. + =item B<-nodetach> when signing a message use opaque signing: this form is more resistant -- 2.34.1