View Issue Details

IDProjectCategoryView StatusLast Update
0005450SOGoBackend Mailpublic2022-01-21 21:28
Reporterschmirl Assigned Tofrancis  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version5.4.0 
Fixed in Version5.5.1 
Summary0005450: Migrate S/MIME from openssl pkcs7 to openssl cms (patch)
Description

The current SOGo S/MIME code uses the openssl pkcs7 interface that corresponds to S/MIME 2.0 (RFC2311) and RFC2315 for CMS.
The openssl cms interface supports newer versions of S/MIME and CMS in a backwards compatible way (up to S/MIME 4.0 (RFC8551) and RFC5652 for CMS).

The attached patch migrates to the openssl cms interface and is pretty straightforward. The patch also fixes several warnings (uninitialized vars, missing header files).

Additional Information

I'd like to vamp up the SOGo S/MIME code in three consecutive steps:

  1. migrate to cms (this ticket)
  2. detection of S/MIME capabilities of peer (#4891)
  3. add support for authEnveloped-data to mitigate Efail vulnerability (requires OpenSSL 3.0)
TagsNo tags attached.

Activities

schmirl

schmirl

2021-12-21 13:32

reporter  

sogo-5.4.0-cms.patch (12,641 bytes)   
diff -ur SOGo-5.4.0.orig/SoObjects/Mailer/NSData+SMIME.h SOGo-5.4.0/SoObjects/Mailer/NSData+SMIME.h
--- SOGo-5.4.0.orig/SoObjects/Mailer/NSData+SMIME.h	2021-12-16 18:03:37.000000000 +0100
+++ SOGo-5.4.0/SoObjects/Mailer/NSData+SMIME.h	2021-12-21 13:56:22.304396539 +0100
@@ -34,7 +34,7 @@
 - (NSData *) embeddedContent;
 - (NGMimeMessage *) messageFromOpaqueSignedData;
 - (NSData *) convertPKCS12ToPEMUsingPassword: (NSString *) thePassword;
-- (NSData *) signersFromPKCS7;
+- (NSData *) signersFromCMS;
 - (NSDictionary *) certificateDescription;
 
 @end
diff -ur SOGo-5.4.0.orig/SoObjects/Mailer/NSData+SMIME.m SOGo-5.4.0/SoObjects/Mailer/NSData+SMIME.m
--- SOGo-5.4.0.orig/SoObjects/Mailer/NSData+SMIME.m	2021-12-16 18:03:37.000000000 +0100
+++ SOGo-5.4.0/SoObjects/Mailer/NSData+SMIME.m	2021-12-21 13:56:22.304396539 +0100
@@ -27,12 +27,13 @@
 #import <NGExtensions/NSString+Encoding.h>
 #import <NGExtensions/NSObject+Logs.h>
 
+#import <NGMime/NGMimeType.h>
 #import <NGMail/NGMimeMessageParser.h>
 
 #if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
 #include <openssl/bio.h>
 #include <openssl/err.h>
-#include <openssl/pkcs7.h>
+#include <openssl/cms.h>
 #include <openssl/pkcs12.h>
 #include <openssl/pem.h>
 #endif
@@ -54,14 +55,14 @@
   X509 *link = NULL;
   STACK_OF(X509) *chain = NULL;
   EVP_PKEY *skey = NULL;
-  PKCS7 *p7 = NULL;
+  CMS_ContentInfo *cms = NULL;
   BUF_MEM *bptr;
   
   unsigned int len, slen;
   const char* bytes;
   const char* sbytes;
 
-  int flags = PKCS7_STREAM | PKCS7_DETACHED | PKCS7_CRLFEOL;
+  int flags = CMS_STREAM | CMS_DETACHED | CMS_CRLFEOL;
   
   OpenSSL_add_all_algorithms();
   ERR_load_crypto_strings();
@@ -96,9 +97,9 @@
   sbytes = [self bytes];
   slen = [self length];
   sbio = BIO_new_mem_buf((void *)sbytes, slen);
-  p7 = PKCS7_sign(scert, skey, (sk_X509_num(chain) > 0) ? chain : NULL, sbio, flags);
+  cms = CMS_sign(scert, skey, (sk_X509_num(chain) > 0) ? chain : NULL, sbio, flags);
 
-  if (!p7)
+  if (!cms)
     {
       NSLog(@"FATAL: failed to sign message.");
       goto cleanup;
@@ -106,13 +107,13 @@
   
   // We output
   obio = BIO_new(BIO_s_mem());
-  SMIME_write_PKCS7(obio, p7, sbio, flags);
+  SMIME_write_CMS(obio, cms, sbio, flags);
   BIO_get_mem_ptr(obio, &bptr);
 
   output = [NSData dataWithBytes: bptr->data  length: bptr->length];
 
  cleanup:
-  PKCS7_free(p7);
+  CMS_ContentInfo_free(cms);
   sk_X509_pop_free(chain, X509_free);
   X509_free(scert);     
   BIO_free(tbio);
@@ -132,14 +133,14 @@
   BUF_MEM *bptr = NULL;
   BIO *tbio = NULL, *sbio = NULL, *obio = NULL;
   X509 *rcert = NULL;
-  PKCS7 *p7 = NULL;
+  CMS_ContentInfo *cms = NULL;
   STACK_OF(X509) *recips = NULL;
   
   unsigned int len, slen;
   const char* bytes;
   const char* sbytes;
 
-  int flags = PKCS7_STREAM;
+  int flags = CMS_STREAM;
   
   OpenSSL_add_all_algorithms();
   ERR_load_crypto_strings();
@@ -179,9 +180,9 @@
   sbio = BIO_new_mem_buf((void *)sbytes, slen);
 
   // Encrypt
-  p7 = PKCS7_encrypt(recips, sbio, EVP_des_ede3_cbc(), flags);
+  cms = CMS_encrypt(recips, sbio, EVP_des_ede3_cbc(), flags);
 
-  if (!p7)
+  if (!cms)
     {
       NSLog(@"FATAL: unable to encrypt message");
       goto cleanup;
@@ -189,9 +190,9 @@
 
   // We output the S/MIME encrypted message
   obio = BIO_new(BIO_s_mem());
-  if (!SMIME_write_PKCS7(obio, p7, sbio, flags))
+  if (!SMIME_write_CMS(obio, cms, sbio, flags))
     {
-      NSLog(@"FATAL: unable to write PKCS7 output");
+      NSLog(@"FATAL: unable to write CMS output");
       goto cleanup;
     }
 
@@ -200,7 +201,7 @@
   output = [NSData dataWithBytes: bptr->data  length: bptr->length];
 
  cleanup:
-  PKCS7_free(p7);
+  CMS_ContentInfo_free(cms);
   X509_free(rcert);        
   BIO_free(tbio);
   BIO_free(sbio);
@@ -216,11 +217,11 @@
 {
   NSData *output = NULL;
 
-  BIO *tbio, *sbio, *obio;
+  BIO *tbio, *sbio = NULL, *obio = NULL;
   BUF_MEM *bptr;
   X509 *scert = NULL;
   EVP_PKEY *skey = NULL;
-  PKCS7 *p7 = NULL;
+  CMS_ContentInfo *cms = NULL;
   
   unsigned int len, slen;
   const char* bytes;
@@ -257,9 +258,9 @@
   slen = [self length];
   sbio = BIO_new_mem_buf((void *)sbytes, slen);
 
-  p7 = SMIME_read_PKCS7(sbio, NULL);
+  cms = SMIME_read_CMS(sbio, NULL);
 
-  if (!p7)
+  if (!cms)
     {
       NSLog(@"FATAL: could not read the content to be decrypted");
       goto cleanup;
@@ -268,7 +269,7 @@
   // We output the S/MIME encrypted message
   obio = BIO_new(BIO_s_mem());
   
-  if (!PKCS7_decrypt(p7, skey, scert, obio, 0))
+  if (!CMS_decrypt(cms, skey, scert, NULL, obio, 0))
     {
       NSLog(@"FATAL: could not decrypt content");
       goto cleanup;
@@ -279,7 +280,7 @@
   output = [NSData dataWithBytes: bptr->data  length: bptr->length];
 
  cleanup:
-  PKCS7_free(p7);
+  CMS_ContentInfo_free(cms);
   X509_free(scert); 
   BIO_free(sbio);
   BIO_free(tbio);
@@ -329,15 +330,15 @@
 {
   NSData *output = NULL;
 
-  BIO *sbio, *obio;
+  BIO *sbio, *obio = NULL;
   BUF_MEM *bptr;
-  PKCS7 *p7 = NULL;
+  CMS_ContentInfo *cms = NULL;
 
   sbio = BIO_new_mem_buf((void *)[self bytes], [self length]);
 
-  p7 = SMIME_read_PKCS7(sbio, NULL);
+  cms = SMIME_read_CMS(sbio, NULL);
 
-  if (!p7)
+  if (!cms)
     {
       NSLog(@"FATAL: could not read the signature");
       goto cleanup;
@@ -346,7 +347,7 @@
   // We output the S/MIME encrypted message
   obio = BIO_new(BIO_s_mem());
 
-  if (!PKCS7_verify(p7, NULL, NULL, NULL, obio, PKCS7_NOVERIFY|PKCS7_NOSIGS))
+  if (!CMS_verify(cms, NULL, NULL, NULL, obio, CMS_NOVERIFY|CMS_NOSIGS))
     {
       NSLog(@"FATAL: could not extract content");
       goto cleanup;
@@ -357,7 +358,7 @@
   output = [NSData dataWithBytes: bptr->data  length: bptr->length];
 
  cleanup:
-  PKCS7_free(p7);
+  CMS_ContentInfo_free(cms);
   BIO_free(sbio);
   BIO_free(obio);
 
@@ -388,7 +389,7 @@
 {
   NSData *output = NULL;
 
-  BIO *ibio, *obio;
+  BIO *ibio, *obio = NULL;
   EVP_PKEY *pkey;
   BUF_MEM *bptr;
   PKCS12 *p12;
@@ -455,14 +456,14 @@
 //
 //
 //
-- (NSData *) signersFromPKCS7
+- (NSData *) signersFromCMS
 {
   NSData *output = NULL;
 
   STACK_OF(X509) *certs = NULL;
-  BIO *ibio, *obio;
+  BIO *ibio, *obio = NULL, *dummybio = NULL;
   BUF_MEM *bptr;
-  PKCS7 *p7;
+  CMS_ContentInfo *cms;
 
   const char* bytes;
   int i, len;
@@ -474,18 +475,22 @@
   len = [self length];
   ibio = BIO_new_mem_buf((void *)bytes, len);
   
-  p7 = d2i_PKCS7_bio(ibio, NULL);
+  cms = d2i_CMS_bio(ibio, NULL);
 
-  if (!p7)
+  if (!cms)
     {
-      NSLog(@"FATAL: could not read PKCS7 content");
+      NSLog(@"FATAL: could not read CMS content");
       goto cleanup;
     }
   
+  // before calling CMS_get0_signers(), CMS_verify() must be called
+  dummybio = BIO_new(BIO_s_mem());
+  CMS_verify(cms, NULL, NULL, dummybio, NULL, CMS_NO_SIGNER_CERT_VERIFY | CMS_NO_ATTR_VERIFY | CMS_NO_CONTENT_VERIFY);
+  ERR_clear_error();
+
   // We output everything in PEM
   obio = BIO_new(BIO_s_mem());
-
-  certs = PKCS7_get0_signers(p7, NULL, 0);
+  certs = CMS_get0_signers(cms);
   if (certs != NULL)
     {
       X509 *x;
@@ -503,7 +508,8 @@
   output = [NSData dataWithBytes: bptr->data  length: bptr->length];
 
  cleanup:
-  PKCS7_free(p7);
+  CMS_ContentInfo_free(cms);
+  BIO_free(dummybio);  
   BIO_free(ibio);  
   BIO_free(obio);  
   
diff -ur SOGo-5.4.0.orig/SoObjects/Mailer/SOGoDraftObject.m SOGo-5.4.0/SoObjects/Mailer/SOGoDraftObject.m
--- SOGo-5.4.0.orig/SoObjects/Mailer/SOGoDraftObject.m	2021-12-16 18:03:37.000000000 +0100
+++ SOGo-5.4.0/SoObjects/Mailer/SOGoDraftObject.m	2021-12-21 13:56:22.304396539 +0100
@@ -1910,7 +1910,7 @@
                                   lookupName: @"Contacts"
                                    inContext: context
                                      acquire: NO];
-          certificate = [[contactFolders certificateForEmail: theRecipient] signersFromPKCS7];
+          certificate = [[contactFolders certificateForEmail: theRecipient] signersFromCMS];
         }
       else
         certificate =  [[self mailAccountFolder] certificate];
diff -ur SOGo-5.4.0.orig/UI/Contacts/UIxContactActions.m SOGo-5.4.0/UI/Contacts/UIxContactActions.m
--- SOGo-5.4.0.orig/UI/Contacts/UIxContactActions.m	2021-12-16 18:03:37.000000000 +0100
+++ SOGo-5.4.0/UI/Contacts/UIxContactActions.m	2021-12-21 13:56:22.308396541 +0100
@@ -160,7 +160,7 @@
 
   if (pkcs7)
     {
-      data = [[pkcs7 signersFromPKCS7] certificateDescription];
+      data = [[pkcs7 signersFromCMS] certificateDescription];
       if (data)
         {
           response = [self responseWithStatus: 200  andJSONRepresentation: data];
diff -ur SOGo-5.4.0.orig/UI/MailPartViewers/UIxMailPartEncryptedViewer.m SOGo-5.4.0/UI/MailPartViewers/UIxMailPartEncryptedViewer.m
--- SOGo-5.4.0.orig/UI/MailPartViewers/UIxMailPartEncryptedViewer.m	2021-12-16 18:03:37.000000000 +0100
+++ SOGo-5.4.0/UI/MailPartViewers/UIxMailPartEncryptedViewer.m	2021-12-21 13:56:22.308396541 +0100
@@ -23,7 +23,7 @@
 #include <openssl/ssl.h>
 #include <openssl/bio.h>
 #include <openssl/err.h>
-#include <openssl/pkcs7.h>
+#include <openssl/cms.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #endif
@@ -101,8 +101,8 @@
 
   STACK_OF(X509) *certs;
   X509_STORE *x509Store;
-  BIO *msgBio, *obio;
-  PKCS7 *p7;
+  BIO *msgBio, *obio = NULL;
+  CMS_ContentInfo *cms;
   int err, i;
 
   ERR_clear_error();
@@ -110,21 +110,25 @@
   msgBio = BIO_new_mem_buf ((void *) [signedData bytes], [signedData length]);
   output = NULL;
 
-  p7 = SMIME_read_PKCS7(msgBio, NULL);
+  cms = SMIME_read_CMS(msgBio, NULL);
 
   certs = NULL;
   certificates = [NSMutableArray array];
   emails = [NSMutableArray array];
   validationMessage = nil;
 
-  if (p7)
+  if (cms)
     {
-      if (OBJ_obj2nid(p7->type) == NID_pkcs7_signed)
+      if (OBJ_obj2nid(CMS_get0_type(cms)) == NID_pkcs7_signed)
 	{
           NSString *subject, *issuer;
 	  X509 *x;
 
-	  certs = p7->d.sign->cert;
+	  BIO *dummybio = BIO_new(BIO_s_mem());
+	  CMS_verify(cms, NULL, NULL, dummybio, NULL, CMS_NO_SIGNER_CERT_VERIFY | CMS_NO_ATTR_VERIFY | CMS_NO_CONTENT_VERIFY);
+	  ERR_clear_error();
+	  BIO_free(dummybio);
+	  certs = CMS_get0_signers(cms);
 
           for (i = 0; i < sk_X509_num(certs); i++)
             {
@@ -171,7 +175,7 @@
           x509Store = [self _setupVerify];
           obio = BIO_new(BIO_s_mem());
 
-	  validSignature = (PKCS7_verify(p7, NULL, x509Store, NULL,
+	  validSignature = (CMS_verify(cms, NULL, x509Store, NULL,
 					 obio, 0) == 1);
 
 	  err = ERR_get_error();
@@ -214,7 +218,7 @@
         }
     }
 
-  PKCS7_free(p7);
+  CMS_ContentInfo_free(cms);
   BIO_free (msgBio);
   BIO_free (obio);
 
diff -ur SOGo-5.4.0.orig/UI/MailPartViewers/UIxMailPartSignedViewer.m SOGo-5.4.0/UI/MailPartViewers/UIxMailPartSignedViewer.m
--- SOGo-5.4.0.orig/UI/MailPartViewers/UIxMailPartSignedViewer.m	2021-12-16 18:03:37.000000000 +0100
+++ SOGo-5.4.0/UI/MailPartViewers/UIxMailPartSignedViewer.m	2021-12-21 13:56:22.308396541 +0100
@@ -21,7 +21,7 @@
 #if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
 #include <openssl/bio.h>
 #include <openssl/err.h>
-#include <openssl/pkcs7.h>
+#include <openssl/cms.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #endif
@@ -99,7 +99,7 @@
   STACK_OF(X509) *certs;
   X509_STORE *x509Store;
   BIO *msgBio, *inData;
-  PKCS7 *p7;
+  CMS_ContentInfo *cms;
   int err, i;
  
   ERR_clear_error();
@@ -112,21 +112,25 @@
   msgBio = BIO_new_mem_buf ((void *) [signedData bytes], [signedData length]);
 
   inData = NULL;
-  p7 = SMIME_read_PKCS7(msgBio, &inData);
+  cms = SMIME_read_CMS(msgBio, &inData);
 
   certs = NULL;
   certificates = [NSMutableArray array];
   emails = [NSMutableArray array];
   validationMessage = nil;
 
-  if (p7)
+  if (cms)
     {
-      if (OBJ_obj2nid(p7->type) == NID_pkcs7_signed)
+      if (OBJ_obj2nid(CMS_get0_type(cms)) == NID_pkcs7_signed)
 	{
           NSString *subject, *issuer;
 	  X509 *x;
 	  
-	  certs = PKCS7_get0_signers(p7, NULL, 0);
+	  BIO *dummybio = BIO_new(BIO_s_mem());
+	  CMS_verify(cms, NULL, NULL, dummybio, NULL, CMS_NO_SIGNER_CERT_VERIFY | CMS_NO_ATTR_VERIFY | CMS_NO_CONTENT_VERIFY);
+	  ERR_clear_error();
+	  BIO_free(dummybio);
+	  certs = CMS_get0_signers(cms);
 
           for (i = 0; i < sk_X509_num(certs); i++)
             {
@@ -172,7 +176,7 @@
       else
 	{
 	  x509Store = [self _setupVerify];
-	  validSignature = (PKCS7_verify(p7, NULL, x509Store, inData,
+	  validSignature = (CMS_verify(cms, NULL, x509Store, inData,
 					 NULL, PKCS7_DETACHED) == 1);
 	  
 	  err = ERR_get_error();
@@ -205,6 +209,7 @@
     }
 
   
+  CMS_ContentInfo_free(cms);
   BIO_free (msgBio);
   if (inData)
     BIO_free (inData);
sogo-5.4.0-cms.patch (12,641 bytes)   

Related Changesets

sogo: master 54b163da

2022-01-21 16:24

francis


Details Diff
fix(mail): S/MIME improvements

Fixes #4891
Fixes 0005450
Affected Issues
0005450
mod - SoObjects/Mailer/NSData+SMIME.h Diff File
mod - SoObjects/Mailer/NSData+SMIME.m Diff File
mod - SoObjects/Mailer/SOGoDraftObject.m Diff File
mod - UI/Contacts/UIxContactActions.m Diff File
mod - UI/MailPartViewers/UIxMailPartEncryptedViewer.m Diff File
mod - UI/MailPartViewers/UIxMailPartSignedViewer.m Diff File

Issue History

Date Modified Username Field Change
2021-12-21 13:32 schmirl New Issue
2021-12-21 13:32 schmirl File Added: sogo-5.4.0-cms.patch
2022-01-21 21:28 francis Changeset attached => sogo master 54b163da
2022-01-21 21:28 francis Assigned To => francis
2022-01-21 21:28 francis Resolution open => fixed
2022-01-21 21:28 francis Status new => resolved
2022-01-21 21:28 francis Fixed in Version => 5.5.1