1/* 2 * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10#include "internal/cryptlib.h" 11#include <openssl/asn1t.h> 12#include <openssl/pem.h> 13#include <openssl/rand.h> 14#include <openssl/x509v3.h> 15#include <openssl/err.h> 16#include <openssl/cms.h> 17#include "cms_local.h" 18 19IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest) 20 21/* ESS services: for now just Signed Receipt related */ 22 23int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr) 24{ 25 ASN1_STRING *str; 26 CMS_ReceiptRequest *rr = NULL; 27 if (prr) 28 *prr = NULL; 29 str = CMS_signed_get0_data_by_OBJ(si, 30 OBJ_nid2obj 31 (NID_id_smime_aa_receiptRequest), -3, 32 V_ASN1_SEQUENCE); 33 if (!str) 34 return 0; 35 36 rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest)); 37 if (!rr) 38 return -1; 39 if (prr) 40 *prr = rr; 41 else 42 CMS_ReceiptRequest_free(rr); 43 return 1; 44} 45 46CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen, 47 int allorfirst, 48 STACK_OF(GENERAL_NAMES) 49 *receiptList, STACK_OF(GENERAL_NAMES) 50 *receiptsTo) 51{ 52 CMS_ReceiptRequest *rr = NULL; 53 54 rr = CMS_ReceiptRequest_new(); 55 if (rr == NULL) 56 goto merr; 57 if (id) 58 ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen); 59 else { 60 if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32)) 61 goto merr; 62 if (RAND_bytes(rr->signedContentIdentifier->data, 32) <= 0) 63 goto err; 64 } 65 66 sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free); 67 rr->receiptsTo = receiptsTo; 68 69 if (receiptList) { 70 rr->receiptsFrom->type = 1; 71 rr->receiptsFrom->d.receiptList = receiptList; 72 } else { 73 rr->receiptsFrom->type = 0; 74 rr->receiptsFrom->d.allOrFirstTier = allorfirst; 75 } 76 77 return rr; 78 79 merr: 80 CMSerr(CMS_F_CMS_RECEIPTREQUEST_CREATE0, ERR_R_MALLOC_FAILURE); 81 82 err: 83 CMS_ReceiptRequest_free(rr); 84 return NULL; 85 86} 87 88int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr) 89{ 90 unsigned char *rrder = NULL; 91 int rrderlen, r = 0; 92 93 rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder); 94 if (rrderlen < 0) 95 goto merr; 96 97 if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest, 98 V_ASN1_SEQUENCE, rrder, rrderlen)) 99 goto merr; 100 101 r = 1; 102 103 merr: 104 if (!r) 105 CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE); 106 107 OPENSSL_free(rrder); 108 109 return r; 110 111} 112 113void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, 114 ASN1_STRING **pcid, 115 int *pallorfirst, 116 STACK_OF(GENERAL_NAMES) **plist, 117 STACK_OF(GENERAL_NAMES) **prto) 118{ 119 if (pcid) 120 *pcid = rr->signedContentIdentifier; 121 if (rr->receiptsFrom->type == 0) { 122 if (pallorfirst) 123 *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier; 124 if (plist) 125 *plist = NULL; 126 } else { 127 if (pallorfirst) 128 *pallorfirst = -1; 129 if (plist) 130 *plist = rr->receiptsFrom->d.receiptList; 131 } 132 if (prto) 133 *prto = rr->receiptsTo; 134} 135 136/* Digest a SignerInfo structure for msgSigDigest attribute processing */ 137 138static int cms_msgSigDigest(CMS_SignerInfo *si, 139 unsigned char *dig, unsigned int *diglen) 140{ 141 const EVP_MD *md; 142 md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm); 143 if (md == NULL) 144 return 0; 145 if (!ASN1_item_digest(ASN1_ITEM_rptr(CMS_Attributes_Verify), md, 146 si->signedAttrs, dig, diglen)) 147 return 0; 148 return 1; 149} 150 151/* Add a msgSigDigest attribute to a SignerInfo */ 152 153int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src) 154{ 155 unsigned char dig[EVP_MAX_MD_SIZE]; 156 unsigned int diglen; 157 if (!cms_msgSigDigest(src, dig, &diglen)) { 158 CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR); 159 return 0; 160 } 161 if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest, 162 V_ASN1_OCTET_STRING, dig, diglen)) { 163 CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, ERR_R_MALLOC_FAILURE); 164 return 0; 165 } 166 return 1; 167} 168 169/* Verify signed receipt after it has already passed normal CMS verify */ 170 171int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms) 172{ 173 int r = 0, i; 174 CMS_ReceiptRequest *rr = NULL; 175 CMS_Receipt *rct = NULL; 176 STACK_OF(CMS_SignerInfo) *sis, *osis; 177 CMS_SignerInfo *si, *osi = NULL; 178 ASN1_OCTET_STRING *msig, **pcont; 179 ASN1_OBJECT *octype; 180 unsigned char dig[EVP_MAX_MD_SIZE]; 181 unsigned int diglen; 182 183 /* Get SignerInfos, also checks SignedData content type */ 184 osis = CMS_get0_SignerInfos(req_cms); 185 sis = CMS_get0_SignerInfos(cms); 186 if (!osis || !sis) 187 goto err; 188 189 if (sk_CMS_SignerInfo_num(sis) != 1) { 190 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NEED_ONE_SIGNER); 191 goto err; 192 } 193 194 /* Check receipt content type */ 195 if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) { 196 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NOT_A_SIGNED_RECEIPT); 197 goto err; 198 } 199 200 /* Extract and decode receipt content */ 201 pcont = CMS_get0_content(cms); 202 if (!pcont || !*pcont) { 203 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT); 204 goto err; 205 } 206 207 rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt)); 208 209 if (!rct) { 210 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_RECEIPT_DECODE_ERROR); 211 goto err; 212 } 213 214 /* Locate original request */ 215 216 for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) { 217 osi = sk_CMS_SignerInfo_value(osis, i); 218 if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue)) 219 break; 220 } 221 222 if (i == sk_CMS_SignerInfo_num(osis)) { 223 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MATCHING_SIGNATURE); 224 goto err; 225 } 226 227 si = sk_CMS_SignerInfo_value(sis, 0); 228 229 /* Get msgSigDigest value and compare */ 230 231 msig = CMS_signed_get0_data_by_OBJ(si, 232 OBJ_nid2obj 233 (NID_id_smime_aa_msgSigDigest), -3, 234 V_ASN1_OCTET_STRING); 235 236 if (!msig) { 237 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MSGSIGDIGEST); 238 goto err; 239 } 240 241 if (!cms_msgSigDigest(osi, dig, &diglen)) { 242 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_ERROR); 243 goto err; 244 } 245 246 if (diglen != (unsigned int)msig->length) { 247 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_WRONG_LENGTH); 248 goto err; 249 } 250 251 if (memcmp(dig, msig->data, diglen)) { 252 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, 253 CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE); 254 goto err; 255 } 256 257 /* Compare content types */ 258 259 octype = CMS_signed_get0_data_by_OBJ(osi, 260 OBJ_nid2obj(NID_pkcs9_contentType), 261 -3, V_ASN1_OBJECT); 262 if (!octype) { 263 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT_TYPE); 264 goto err; 265 } 266 267 /* Compare details in receipt request */ 268 269 if (OBJ_cmp(octype, rct->contentType)) { 270 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENT_TYPE_MISMATCH); 271 goto err; 272 } 273 274 /* Get original receipt request details */ 275 276 if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) { 277 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_RECEIPT_REQUEST); 278 goto err; 279 } 280 281 if (ASN1_STRING_cmp(rr->signedContentIdentifier, 282 rct->signedContentIdentifier)) { 283 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENTIDENTIFIER_MISMATCH); 284 goto err; 285 } 286 287 r = 1; 288 289 err: 290 CMS_ReceiptRequest_free(rr); 291 M_ASN1_free_of(rct, CMS_Receipt); 292 return r; 293 294} 295 296/* 297 * Encode a Receipt into an OCTET STRING read for including into content of a 298 * SignedData ContentInfo. 299 */ 300 301ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si) 302{ 303 CMS_Receipt rct; 304 CMS_ReceiptRequest *rr = NULL; 305 ASN1_OBJECT *ctype; 306 ASN1_OCTET_STRING *os = NULL; 307 308 /* Get original receipt request */ 309 310 /* Get original receipt request details */ 311 312 if (CMS_get1_ReceiptRequest(si, &rr) <= 0) { 313 CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST); 314 goto err; 315 } 316 317 /* Get original content type */ 318 319 ctype = CMS_signed_get0_data_by_OBJ(si, 320 OBJ_nid2obj(NID_pkcs9_contentType), 321 -3, V_ASN1_OBJECT); 322 if (!ctype) { 323 CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_CONTENT_TYPE); 324 goto err; 325 } 326 327 rct.version = 1; 328 rct.contentType = ctype; 329 rct.signedContentIdentifier = rr->signedContentIdentifier; 330 rct.originatorSignatureValue = si->signature; 331 332 os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL); 333 334 err: 335 CMS_ReceiptRequest_free(rr); 336 return os; 337} 338