Remove duplicate code.
[openssl.git] / crypto / cms / cms_ess.c
index 00cd9dcb4319c5daa27f479a285dbbf56e0573df..8212560628a9d44da5908dc5396a5a2cd6c43713 100644 (file)
@@ -1,5 +1,6 @@
 /* crypto/cms/cms_ess.c */
 /* crypto/cms/cms_ess.c */
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+/*
+ * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
  * project.
  */
 /* ====================================================================
  * project.
  */
 /* ====================================================================
@@ -10,7 +11,7 @@
  * are met:
  *
  * 1. Redistributions of source code must retain the above copyright
  * are met:
  *
  * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer. 
+ *    notice, this list of conditions and the following disclaimer.
  *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
  *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
 #include <openssl/err.h>
 #include <openssl/cms.h>
 #include "cms_lcl.h"
 #include <openssl/err.h>
 #include <openssl/cms.h>
 #include "cms_lcl.h"
-#include "asn1_locl.h"
 
 DECLARE_ASN1_ITEM(CMS_ReceiptRequest)
 
 DECLARE_ASN1_ITEM(CMS_ReceiptRequest)
+DECLARE_ASN1_ITEM(CMS_Receipt)
 
 IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
 
 /* ESS services: for now just Signed Receipt related */
 
 int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
 
 IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
 
 /* ESS services: for now just Signed Receipt related */
 
 int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
-       {
-       ASN1_STRING *str;
-       CMS_ReceiptRequest *rr = NULL;
-       if (prr)
-               *prr = NULL;
-       str = CMS_signed_get0_data_by_OBJ(si,
-                               OBJ_nid2obj(NID_id_smime_aa_receiptRequest),
-                                       -3, V_ASN1_SEQUENCE);
-       if (!str)
-               return 0;
-
-       rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest));
-       if (!rr)
-               return -1;
-       if (prr)
-               *prr = rr;
-       else
-               CMS_ReceiptRequest_free(rr);
-       return 1;
-       }
-
-int CMS_add1_ReceiptRequest(CMS_SignerInfo *si,
-                               unsigned char *id, int idlen,
-                               int allorfirst,
-                               STACK_OF(GENERAL_NAMES) *receiptList,
-                               STACK_OF(GENERAL_NAMES) *receiptsTo)
-       {
-       CMS_ReceiptRequest *rr = NULL;
-       STACK_OF(GENERAL_NAMES) *tmpto = NULL;
-       unsigned char *rrder = NULL;
-       int rrderlen;
-       int r = 0;
-
-       rr = CMS_ReceiptRequest_new();
-       if (!rr)
-               goto merr;
-       if (id)
-               {
-               if (!ASN1_STRING_set(rr->signedContentIdentifier, id, idlen))
-                       goto merr;
-               }
-       else
-               {
-               if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32))
-                       goto merr;
-               if (RAND_pseudo_bytes(rr->signedContentIdentifier->data, 32) 
-                                       <= 0)
-                       goto err;
-               }
-
-       tmpto = rr->receiptsTo;
-       rr->receiptsTo = receiptsTo;
-
-       if (receiptList)
-               {
-               rr->receiptsFrom->type = 1;
-               rr->receiptsFrom->d.receiptList = receiptList;
-               }
-       else
-               {
-               rr->receiptsFrom->type = 0;
-               rr->receiptsFrom->d.allOrFirstTier = allorfirst;
-               }
-
-       rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder);
-
-       r = CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest,
-                                       V_ASN1_SEQUENCE, rrder, rrderlen);
-
-       merr:
-       CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE);
-
-       err:
-       if (rr)
-               {
-               rr->receiptsTo = tmpto;
-               rr->receiptsFrom->type = 0;
-               CMS_ReceiptRequest_free(rr);
-               }
-       if (rrder)
-               OPENSSL_free(rrder);
-
-       return r;
-       
-       }
+{
+    ASN1_STRING *str;
+    CMS_ReceiptRequest *rr = NULL;
+    if (prr)
+        *prr = NULL;
+    str = CMS_signed_get0_data_by_OBJ(si,
+                                      OBJ_nid2obj
+                                      (NID_id_smime_aa_receiptRequest), -3,
+                                      V_ASN1_SEQUENCE);
+    if (!str)
+        return 0;
+
+    rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest));
+    if (!rr)
+        return -1;
+    if (prr)
+        *prr = rr;
+    else
+        CMS_ReceiptRequest_free(rr);
+    return 1;
+}
+
+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;
+
+    rr = CMS_ReceiptRequest_new();
+    if (!rr)
+        goto merr;
+    if (id)
+        ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen);
+    else {
+        if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32))
+            goto merr;
+        if (RAND_bytes(rr->signedContentIdentifier->data, 32) <= 0)
+            goto err;
+    }
+
+    sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free);
+    rr->receiptsTo = receiptsTo;
+
+    if (receiptList) {
+        rr->receiptsFrom->type = 1;
+        rr->receiptsFrom->d.receiptList = receiptList;
+    } else {
+        rr->receiptsFrom->type = 0;
+        rr->receiptsFrom->d.allOrFirstTier = allorfirst;
+    }
+
+    return rr;
+
+ merr:
+    CMSerr(CMS_F_CMS_RECEIPTREQUEST_CREATE0, ERR_R_MALLOC_FAILURE);
+
+ err:
+    if (rr)
+        CMS_ReceiptRequest_free(rr);
+
+    return NULL;
+
+}
+
+int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr)
+{
+    unsigned char *rrder = NULL;
+    int rrderlen, r = 0;
+
+    rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder);
+    if (rrderlen < 0)
+        goto merr;
+
+    if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest,
+                                     V_ASN1_SEQUENCE, rrder, rrderlen))
+        goto merr;
+
+    r = 1;
+
+ merr:
+    if (!r)
+        CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE);
+
+    if (rrder)
+        OPENSSL_free(rrder);
+
+    return r;
+
+}
 
 void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
 
 void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
-                                       ASN1_STRING **pcid,
-                                       int *pallorfirst,
-                                       STACK_OF(GENERAL_NAMES) **plist,
-                                       STACK_OF(GENERAL_NAMES) **prto)
-       {
-       if (pcid)
-               *pcid = rr->signedContentIdentifier;
-       if (rr->receiptsFrom->type == 0)
-               {
-               if (pallorfirst)
-                       *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier;
-               if (plist)
-                       *plist = NULL;
-               }
-       else
-               {
-               if (pallorfirst)
-                       *pallorfirst = -1;
-               if (plist)
-                       *plist = rr->receiptsFrom->d.receiptList;
-               }
-       if (prto)
-               *prto = rr->receiptsTo;
-       }
+                                    ASN1_STRING **pcid,
+                                    int *pallorfirst,
+                                    STACK_OF(GENERAL_NAMES) **plist,
+                                    STACK_OF(GENERAL_NAMES) **prto)
+{
+    if (pcid)
+        *pcid = rr->signedContentIdentifier;
+    if (rr->receiptsFrom->type == 0) {
+        if (pallorfirst)
+            *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier;
+        if (plist)
+            *plist = NULL;
+    } else {
+        if (pallorfirst)
+            *pallorfirst = -1;
+        if (plist)
+            *plist = rr->receiptsFrom->d.receiptList;
+    }
+    if (prto)
+        *prto = rr->receiptsTo;
+}
+
+/* Digest a SignerInfo structure for msgSigDigest attribute processing */
+
+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;
+    if (!ASN1_item_digest(ASN1_ITEM_rptr(CMS_Attributes_Verify), md,
+                          si->signedAttrs, dig, diglen))
+        return 0;
+    return 1;
+}
+
+/* Add a msgSigDigest attribute to a SignerInfo */
+
+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;
+    }
+    if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest,
+                                     V_ASN1_OCTET_STRING, dig, diglen)) {
+        CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    return 1;
+}
+
+/* Verify signed receipt after it has already passed normal CMS verify */
+
+int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms)
+{
+    int r = 0, i;
+    CMS_ReceiptRequest *rr = NULL;
+    CMS_Receipt *rct = NULL;
+    STACK_OF(CMS_SignerInfo) *sis, *osis;
+    CMS_SignerInfo *si, *osi = NULL;
+    ASN1_OCTET_STRING *msig, **pcont;
+    ASN1_OBJECT *octype;
+    unsigned char dig[EVP_MAX_MD_SIZE];
+    unsigned int diglen;
+
+    /* Get SignerInfos, also checks SignedData content type */
+    osis = CMS_get0_SignerInfos(req_cms);
+    sis = CMS_get0_SignerInfos(cms);
+    if (!osis || !sis)
+        goto err;
+
+    if (sk_CMS_SignerInfo_num(sis) != 1) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NEED_ONE_SIGNER);
+        goto err;
+    }
+
+    /* Check receipt content type */
+    if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NOT_A_SIGNED_RECEIPT);
+        goto err;
+    }
+
+    /* Extract and decode receipt content */
+    pcont = CMS_get0_content(cms);
+    if (!pcont || !*pcont) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT);
+        goto err;
+    }
+
+    rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt));
+
+    if (!rct) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_RECEIPT_DECODE_ERROR);
+        goto err;
+    }
+
+    /* Locate original request */
+
+    for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) {
+        osi = sk_CMS_SignerInfo_value(osis, i);
+        if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue))
+            break;
+    }
+
+    if (i == sk_CMS_SignerInfo_num(osis)) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MATCHING_SIGNATURE);
+        goto err;
+    }
+
+    si = sk_CMS_SignerInfo_value(sis, 0);
+
+    /* Get msgSigDigest value and compare */
+
+    msig = CMS_signed_get0_data_by_OBJ(si,
+                                       OBJ_nid2obj
+                                       (NID_id_smime_aa_msgSigDigest), -3,
+                                       V_ASN1_OCTET_STRING);
+
+    if (!msig) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MSGSIGDIGEST);
+        goto err;
+    }
+
+    if (!cms_msgSigDigest(osi, dig, &diglen)) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_ERROR);
+        goto err;
+    }
+
+    if (diglen != (unsigned int)msig->length) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_WRONG_LENGTH);
+        goto err;
+    }
+
+    if (memcmp(dig, msig->data, diglen)) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY,
+               CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE);
+        goto err;
+    }
+
+    /* Compare content types */
+
+    octype = CMS_signed_get0_data_by_OBJ(osi,
+                                         OBJ_nid2obj(NID_pkcs9_contentType),
+                                         -3, V_ASN1_OBJECT);
+    if (!octype) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT_TYPE);
+        goto err;
+    }
+
+    /* Compare details in receipt request */
+
+    if (OBJ_cmp(octype, rct->contentType)) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENT_TYPE_MISMATCH);
+        goto err;
+    }
+
+    /* Get original receipt request details */
+
+    if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_RECEIPT_REQUEST);
+        goto err;
+    }
+
+    if (ASN1_STRING_cmp(rr->signedContentIdentifier,
+                        rct->signedContentIdentifier)) {
+        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENTIDENTIFIER_MISMATCH);
+        goto err;
+    }
+
+    r = 1;
+
+ err:
+    if (rr)
+        CMS_ReceiptRequest_free(rr);
+    if (rct)
+        M_ASN1_free_of(rct, CMS_Receipt);
+
+    return r;
+
+}
+
+/*
+ * Encode a Receipt into an OCTET STRING read for including into content of a
+ * SignedData ContentInfo.
+ */
+
+ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si)
+{
+    CMS_Receipt rct;
+    CMS_ReceiptRequest *rr = NULL;
+    ASN1_OBJECT *ctype;
+    ASN1_OCTET_STRING *os = NULL;
+
+    /* Get original receipt request */
+
+    /* Get original receipt request details */
+
+    if (CMS_get1_ReceiptRequest(si, &rr) <= 0) {
+        CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST);
+        goto err;
+    }
+
+    /* Get original content type */
+
+    ctype = CMS_signed_get0_data_by_OBJ(si,
+                                        OBJ_nid2obj(NID_pkcs9_contentType),
+                                        -3, V_ASN1_OBJECT);
+    if (!ctype) {
+        CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_CONTENT_TYPE);
+        goto err;
+    }
+
+    rct.version = 1;
+    rct.contentType = ctype;
+    rct.signedContentIdentifier = rr->signedContentIdentifier;
+    rct.originatorSignatureValue = si->signature;
+
+    os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL);
 
 
+ err:
+    if (rr)
+        CMS_ReceiptRequest_free(rr);
 
 
+    return os;
 
 
+}