crypto/cms: add CAdES-BES signed attributes validation
[openssl.git] / crypto / cms / cms_ess.c
index 3901074033134fe72738bf783bdbec0ee4fd98be..e3604f7db8ae8cc35730ababb97a995bc06a4f7c 100644 (file)
@@ -21,6 +21,9 @@
 
 DEFINE_STACK_OF(GENERAL_NAMES)
 DEFINE_STACK_OF(CMS_SignerInfo)
+DEFINE_STACK_OF(ESS_CERT_ID)
+DEFINE_STACK_OF(ESS_CERT_ID_V2)
+DEFINE_STACK_OF(X509)
 
 IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
 
@@ -29,33 +32,100 @@ IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
 int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
 {
     ASN1_STRING *str;
-    CMS_ReceiptRequest *rr = NULL;
-    if (prr)
+    CMS_ReceiptRequest *rr;
+    ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_receiptRequest);
+
+    if (prr != NULL)
         *prr = NULL;
-    str = CMS_signed_get0_data_by_OBJ(si,
-                                      OBJ_nid2obj
-                                      (NID_id_smime_aa_receiptRequest), -3,
-                                      V_ASN1_SEQUENCE);
-    if (!str)
+    str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE);
+    if (str == NULL)
         return 0;
 
     rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest));
-    if (!rr)
+    if (rr == NULL)
         return -1;
-    if (prr)
+    if (prr != NULL)
         *prr = rr;
     else
         CMS_ReceiptRequest_free(rr);
     return 1;
 }
 
+/*
+    First, get the ESS_SIGNING_CERT(V2) signed attribute from |si|.
+    Then check matching of each cert of trust |chain| with one of 
+    the |cert_ids|(Hash+IssuerID) list from this ESS_SIGNING_CERT.
+    Derived from ts_check_signing_certs()
+*/
+int ess_check_signing_certs(CMS_SignerInfo *si, STACK_OF(X509) *chain)
+{
+    ESS_SIGNING_CERT *ss = NULL;
+    ESS_SIGNING_CERT_V2 *ssv2 = NULL;
+    X509 *cert;
+    int i = 0, ret = 0;
+
+    if (cms_signerinfo_get_signing_cert(si, &ss) > 0 && ss->cert_ids != NULL) {
+        STACK_OF(ESS_CERT_ID) *cert_ids = ss->cert_ids;
+
+        cert = sk_X509_value(chain, 0);
+        if (ess_find_cert(cert_ids, cert) != 0)
+            goto err;
+
+        /*
+         * Check the other certificates of the chain.
+         * Fail if no signing certificate ids found for each certificate.
+         */
+        if (sk_ESS_CERT_ID_num(cert_ids) > 1) {
+            /* for each chain cert, try to find its cert id */
+            for (i = 1; i < sk_X509_num(chain); ++i) {
+                cert = sk_X509_value(chain, i);
+                if (ess_find_cert(cert_ids, cert) < 0)
+                    goto err;
+            }
+        }
+    } else if (cms_signerinfo_get_signing_cert_v2(si, &ssv2) > 0
+                   && ssv2->cert_ids!= NULL) {
+        STACK_OF(ESS_CERT_ID_V2) *cert_ids_v2 = ssv2->cert_ids;
+
+        cert = sk_X509_value(chain, 0);
+        if (ess_find_cert_v2(cert_ids_v2, cert) != 0)
+            goto err;
+
+        /*
+         * Check the other certificates of the chain.
+         * Fail if no signing certificate ids found for each certificate.
+         */
+        if (sk_ESS_CERT_ID_V2_num(cert_ids_v2) > 1) {
+            /* for each chain cert, try to find its cert id */
+            for (i = 1; i < sk_X509_num(chain); ++i) {
+                cert = sk_X509_value(chain, i);
+                if (ess_find_cert_v2(cert_ids_v2, cert) < 0)
+                    goto err;
+            }
+        }
+    } else {
+        CMSerr(CMS_F_ESS_CHECK_SIGNING_CERTS,
+               CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE);
+        return 0;
+    }
+    ret = 1;
+ err:
+    if (!ret)
+        CMSerr(CMS_F_ESS_CHECK_SIGNING_CERTS,
+               CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR);
+
+    ESS_SIGNING_CERT_free(ss);
+    ESS_SIGNING_CERT_V2_free(ssv2);
+    return ret;
+}
+
 CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen,
                                                int allorfirst,
                                                STACK_OF(GENERAL_NAMES)
                                                *receiptList, STACK_OF(GENERAL_NAMES)
                                                *receiptsTo)
 {
-    CMS_ReceiptRequest *rr = NULL;
+    CMS_ReceiptRequest *rr;
 
     rr = CMS_ReceiptRequest_new();
     if (rr == NULL)
@@ -145,6 +215,7 @@ static int cms_msgSigDigest(CMS_SignerInfo *si,
                             unsigned char *dig, unsigned int *diglen)
 {
     const EVP_MD *md;
+
     md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
     if (md == NULL)
         return 0;
@@ -160,6 +231,7 @@ int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
 {
     unsigned char dig[EVP_MAX_MD_SIZE];
     unsigned int diglen;
+
     if (!cms_msgSigDigest(src, dig, &diglen)) {
         CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR);
         return 0;