1/* $OpenBSD: cms_ess.c,v 1.25 2024/03/30 01:53:05 joshua Exp $ */ 2/* 3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 4 * project. 5 */ 6/* ==================================================================== 7 * Copyright (c) 2008 The OpenSSL Project. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. All advertising materials mentioning features or use of this 22 * software must display the following acknowledgment: 23 * "This product includes software developed by the OpenSSL Project 24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25 * 26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27 * endorse or promote products derived from this software without 28 * prior written permission. For written permission, please contact 29 * licensing@OpenSSL.org. 30 * 31 * 5. Products derived from this software may not be called "OpenSSL" 32 * nor may "OpenSSL" appear in their names without prior written 33 * permission of the OpenSSL Project. 34 * 35 * 6. Redistributions of any form whatsoever must retain the following 36 * acknowledgment: 37 * "This product includes software developed by the OpenSSL Project 38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51 * OF THE POSSIBILITY OF SUCH DAMAGE. 52 * ==================================================================== 53 */ 54 55#include <string.h> 56 57#include <openssl/asn1t.h> 58#include <openssl/pem.h> 59#include <openssl/rand.h> 60#include <openssl/x509v3.h> 61#include <openssl/err.h> 62#include <openssl/cms.h> 63 64#include "cms_local.h" 65#include "x509_local.h" 66 67CMS_ReceiptRequest * 68d2i_CMS_ReceiptRequest(CMS_ReceiptRequest **a, const unsigned char **in, long len) 69{ 70 return (CMS_ReceiptRequest *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, 71 &CMS_ReceiptRequest_it); 72} 73LCRYPTO_ALIAS(d2i_CMS_ReceiptRequest); 74 75int 76i2d_CMS_ReceiptRequest(CMS_ReceiptRequest *a, unsigned char **out) 77{ 78 return ASN1_item_i2d((ASN1_VALUE *)a, out, &CMS_ReceiptRequest_it); 79} 80LCRYPTO_ALIAS(i2d_CMS_ReceiptRequest); 81 82CMS_ReceiptRequest * 83CMS_ReceiptRequest_new(void) 84{ 85 return (CMS_ReceiptRequest *)ASN1_item_new(&CMS_ReceiptRequest_it); 86} 87LCRYPTO_ALIAS(CMS_ReceiptRequest_new); 88 89void 90CMS_ReceiptRequest_free(CMS_ReceiptRequest *a) 91{ 92 ASN1_item_free((ASN1_VALUE *)a, &CMS_ReceiptRequest_it); 93} 94LCRYPTO_ALIAS(CMS_ReceiptRequest_free); 95 96/* ESS services: for now just Signed Receipt related */ 97 98int 99CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr) 100{ 101 ASN1_STRING *str; 102 CMS_ReceiptRequest *rr = NULL; 103 104 if (prr) 105 *prr = NULL; 106 str = CMS_signed_get0_data_by_OBJ(si, 107 OBJ_nid2obj(NID_id_smime_aa_receiptRequest), -3, V_ASN1_SEQUENCE); 108 if (!str) 109 return 0; 110 111 rr = ASN1_item_unpack(str, &CMS_ReceiptRequest_it); 112 if (!rr) 113 return -1; 114 if (prr) 115 *prr = rr; 116 else 117 CMS_ReceiptRequest_free(rr); 118 119 return 1; 120} 121LCRYPTO_ALIAS(CMS_get1_ReceiptRequest); 122 123CMS_ReceiptRequest * 124CMS_ReceiptRequest_create0(unsigned char *id, int idlen, int allorfirst, 125 STACK_OF(GENERAL_NAMES) *receiptList, STACK_OF(GENERAL_NAMES) *receiptsTo) 126{ 127 CMS_ReceiptRequest *rr = NULL; 128 129 rr = CMS_ReceiptRequest_new(); 130 if (rr == NULL) 131 goto merr; 132 if (id) 133 ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen); 134 else { 135 if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32)) 136 goto merr; 137 arc4random_buf(rr->signedContentIdentifier->data, 32); 138 } 139 140 sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free); 141 rr->receiptsTo = receiptsTo; 142 143 if (receiptList) { 144 rr->receiptsFrom->type = 1; 145 rr->receiptsFrom->d.receiptList = receiptList; 146 } else { 147 rr->receiptsFrom->type = 0; 148 rr->receiptsFrom->d.allOrFirstTier = allorfirst; 149 } 150 151 return rr; 152 153 merr: 154 CMSerror(ERR_R_MALLOC_FAILURE); 155 CMS_ReceiptRequest_free(rr); 156 157 return NULL; 158} 159LCRYPTO_ALIAS(CMS_ReceiptRequest_create0); 160 161int 162CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr) 163{ 164 unsigned char *rrder = NULL; 165 int rrderlen, r = 0; 166 167 rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder); 168 if (rrderlen < 0) 169 goto merr; 170 171 if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest, 172 V_ASN1_SEQUENCE, rrder, rrderlen)) 173 goto merr; 174 175 r = 1; 176 177 merr: 178 if (!r) 179 CMSerror(ERR_R_MALLOC_FAILURE); 180 181 free(rrder); 182 183 return r; 184} 185LCRYPTO_ALIAS(CMS_add1_ReceiptRequest); 186 187void 188CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, ASN1_STRING **pcid, 189 int *pallorfirst, STACK_OF(GENERAL_NAMES) **plist, 190 STACK_OF(GENERAL_NAMES) **prto) 191{ 192 if (pcid) 193 *pcid = rr->signedContentIdentifier; 194 if (rr->receiptsFrom->type == 0) { 195 if (pallorfirst) 196 *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier; 197 if (plist) 198 *plist = NULL; 199 } else { 200 if (pallorfirst) 201 *pallorfirst = -1; 202 if (plist) 203 *plist = rr->receiptsFrom->d.receiptList; 204 } 205 if (prto) 206 *prto = rr->receiptsTo; 207} 208LCRYPTO_ALIAS(CMS_ReceiptRequest_get0_values); 209 210/* Digest a SignerInfo structure for msgSigDigest attribute processing */ 211 212static int 213cms_msgSigDigest(CMS_SignerInfo *si, unsigned char *dig, unsigned int *diglen) 214{ 215 const EVP_MD *md; 216 217 md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm); 218 if (md == NULL) 219 return 0; 220 if (!ASN1_item_digest(&CMS_Attributes_Verify_it, md, 221 si->signedAttrs, dig, diglen)) 222 return 0; 223 224 return 1; 225} 226 227/* Add a msgSigDigest attribute to a SignerInfo */ 228 229int 230cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src) 231{ 232 unsigned char dig[EVP_MAX_MD_SIZE]; 233 unsigned int diglen; 234 235 if (!cms_msgSigDigest(src, dig, &diglen)) { 236 CMSerror(CMS_R_MSGSIGDIGEST_ERROR); 237 return 0; 238 } 239 if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest, 240 V_ASN1_OCTET_STRING, dig, diglen)) { 241 CMSerror(ERR_R_MALLOC_FAILURE); 242 return 0; 243 } 244 245 return 1; 246} 247 248/* Verify signed receipt after it has already passed normal CMS verify */ 249 250int 251cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms) 252{ 253 int r = 0, i; 254 CMS_ReceiptRequest *rr = NULL; 255 CMS_Receipt *rct = NULL; 256 STACK_OF(CMS_SignerInfo) *sis, *osis; 257 CMS_SignerInfo *si, *osi = NULL; 258 ASN1_OCTET_STRING *msig, **pcont; 259 ASN1_OBJECT *octype; 260 unsigned char dig[EVP_MAX_MD_SIZE]; 261 unsigned int diglen; 262 263 /* Get SignerInfos, also checks SignedData content type */ 264 osis = CMS_get0_SignerInfos(req_cms); 265 sis = CMS_get0_SignerInfos(cms); 266 if (!osis || !sis) 267 goto err; 268 269 if (sk_CMS_SignerInfo_num(sis) != 1) { 270 CMSerror(CMS_R_NEED_ONE_SIGNER); 271 goto err; 272 } 273 274 /* Check receipt content type */ 275 if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) { 276 CMSerror(CMS_R_NOT_A_SIGNED_RECEIPT); 277 goto err; 278 } 279 280 /* Extract and decode receipt content */ 281 pcont = CMS_get0_content(cms); 282 if (!pcont || !*pcont) { 283 CMSerror(CMS_R_NO_CONTENT); 284 goto err; 285 } 286 287 rct = ASN1_item_unpack(*pcont, &CMS_Receipt_it); 288 289 if (!rct) { 290 CMSerror(CMS_R_RECEIPT_DECODE_ERROR); 291 goto err; 292 } 293 294 /* Locate original request */ 295 296 for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) { 297 osi = sk_CMS_SignerInfo_value(osis, i); 298 if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue)) 299 break; 300 } 301 302 if (i == sk_CMS_SignerInfo_num(osis)) { 303 CMSerror(CMS_R_NO_MATCHING_SIGNATURE); 304 goto err; 305 } 306 307 si = sk_CMS_SignerInfo_value(sis, 0); 308 309 /* Get msgSigDigest value and compare */ 310 311 msig = CMS_signed_get0_data_by_OBJ(si, 312 OBJ_nid2obj(NID_id_smime_aa_msgSigDigest), -3, V_ASN1_OCTET_STRING); 313 314 if (!msig) { 315 CMSerror(CMS_R_NO_MSGSIGDIGEST); 316 goto err; 317 } 318 319 if (!cms_msgSigDigest(osi, dig, &diglen)) { 320 CMSerror(CMS_R_MSGSIGDIGEST_ERROR); 321 goto err; 322 } 323 324 if (diglen != (unsigned int)msig->length) { 325 CMSerror(CMS_R_MSGSIGDIGEST_WRONG_LENGTH); 326 goto err; 327 } 328 329 if (memcmp(dig, msig->data, diglen)) { 330 CMSerror(CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE); 331 goto err; 332 } 333 334 /* Compare content types */ 335 336 octype = CMS_signed_get0_data_by_OBJ(osi, 337 OBJ_nid2obj(NID_pkcs9_contentType), -3, V_ASN1_OBJECT); 338 if (!octype) { 339 CMSerror(CMS_R_NO_CONTENT_TYPE); 340 goto err; 341 } 342 343 /* Compare details in receipt request */ 344 345 if (OBJ_cmp(octype, rct->contentType)) { 346 CMSerror(CMS_R_CONTENT_TYPE_MISMATCH); 347 goto err; 348 } 349 350 /* Get original receipt request details */ 351 352 if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) { 353 CMSerror(CMS_R_NO_RECEIPT_REQUEST); 354 goto err; 355 } 356 357 if (ASN1_STRING_cmp(rr->signedContentIdentifier, 358 rct->signedContentIdentifier)) { 359 CMSerror(CMS_R_CONTENTIDENTIFIER_MISMATCH); 360 goto err; 361 } 362 363 r = 1; 364 365 err: 366 CMS_ReceiptRequest_free(rr); 367 ASN1_item_free((ASN1_VALUE *)rct, &CMS_Receipt_it); 368 return r; 369} 370 371/* 372 * Encode a Receipt into an OCTET STRING read for including into content of a 373 * SignedData ContentInfo. 374 */ 375 376ASN1_OCTET_STRING * 377cms_encode_Receipt(CMS_SignerInfo *si) 378{ 379 CMS_Receipt rct; 380 CMS_ReceiptRequest *rr = NULL; 381 ASN1_OBJECT *ctype; 382 ASN1_OCTET_STRING *os = NULL; 383 384 /* Get original receipt request */ 385 386 /* Get original receipt request details */ 387 388 if (CMS_get1_ReceiptRequest(si, &rr) <= 0) { 389 CMSerror(CMS_R_NO_RECEIPT_REQUEST); 390 goto err; 391 } 392 393 /* Get original content type */ 394 395 ctype = CMS_signed_get0_data_by_OBJ(si, 396 OBJ_nid2obj(NID_pkcs9_contentType), -3, V_ASN1_OBJECT); 397 if (!ctype) { 398 CMSerror(CMS_R_NO_CONTENT_TYPE); 399 goto err; 400 } 401 402 rct.version = 1; 403 rct.contentType = ctype; 404 rct.signedContentIdentifier = rr->signedContentIdentifier; 405 rct.originatorSignatureValue = si->signature; 406 407 os = ASN1_item_pack(&rct, &CMS_Receipt_it, NULL); 408 409 err: 410 CMS_ReceiptRequest_free(rr); 411 return os; 412} 413