crypto/cms: add CAdES-BES signed attributes validation
[openssl.git] / crypto / cms / cms_smime.c
index dbdc815e9729b75459491fcb08a3a40797657a99..a83edce0f7e5e960db09f6c6781e60fd1373bfa8 100644 (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,
                                       X509_STORE *store,
                                       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 *signer;
@@ -262,6 +263,10 @@ static int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
         goto err;
     }
     r = 1;
+
+    /* also send back the trust chain when required */
+    if (chain != NULL)
+        *chain = X509_STORE_CTX_get1_chain(ctx);
  err:
     X509_STORE_CTX_free(ctx);
     return r;
@@ -275,9 +280,11 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
     STACK_OF(CMS_SignerInfo) *sinfos;
     STACK_OF(X509) *cms_certs = NULL;
     STACK_OF(X509_CRL) *crls = NULL;
+    STACK_OF(X509) **si_chains = NULL;
     X509 *signer;
     int i, scount = 0, ret = 0;
     BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL;
+    int cadesVerify = (flags & CMS_CADES) != 0;
 
     if (!dcont && !check_content(cms))
         return 0;
@@ -312,27 +319,44 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
     }
 
     /* Attempt to verify all signers certs */
-
-    if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) {
+    /* at this point scount == sk_CMS_SignerInfo_num(sinfos) */
+
+    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);
         if (!(flags & CMS_NOCRL))
             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);
-            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;
         }
     }
 
     /* Attempt to verify all SignerInfo signed attribute signatures */
 
-    if (!(flags & CMS_NO_ATTR_VERIFY)) {
-        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
+    if ((flags & CMS_NO_ATTR_VERIFY) == 0 || cadesVerify) {
+        for (i = 0; i < scount; i++) {
             si = sk_CMS_SignerInfo_value(sinfos, i);
             if (CMS_signed_get_attr_count(si) < 0)
                 continue;
             if (CMS_SignerInfo_verify(si) <= 0)
                 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);
 
  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_CRL_pop_free(crls, X509_CRL_free);