cms_ess.c revision 296465
1/* crypto/cms/cms_ess.c */ 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 "cryptlib.h" 56#include <openssl/asn1t.h> 57#include <openssl/pem.h> 58#include <openssl/rand.h> 59#include <openssl/x509v3.h> 60#include <openssl/err.h> 61#include <openssl/cms.h> 62#include "cms_lcl.h" 63 64DECLARE_ASN1_ITEM(CMS_ReceiptRequest) 65DECLARE_ASN1_ITEM(CMS_Receipt) 66 67IMPLEMENT_ASN1_FUNCTIONS_const(CMS_ReceiptRequest) 68 69/* ESS services: for now just Signed Receipt related */ 70 71int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr) 72{ 73 ASN1_STRING *str; 74 CMS_ReceiptRequest *rr = NULL; 75 if (prr) 76 *prr = NULL; 77 str = CMS_signed_get0_data_by_OBJ(si, 78 OBJ_nid2obj 79 (NID_id_smime_aa_receiptRequest), -3, 80 V_ASN1_SEQUENCE); 81 if (!str) 82 return 0; 83 84 rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest)); 85 if (!rr) 86 return -1; 87 if (prr) 88 *prr = rr; 89 else 90 CMS_ReceiptRequest_free(rr); 91 return 1; 92} 93 94CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen, 95 int allorfirst, 96 STACK_OF(GENERAL_NAMES) 97 *receiptList, STACK_OF(GENERAL_NAMES) 98 *receiptsTo) 99{ 100 CMS_ReceiptRequest *rr = NULL; 101 102 rr = CMS_ReceiptRequest_new(); 103 if (!rr) 104 goto merr; 105 if (id) 106 ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen); 107 else { 108 if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32)) 109 goto merr; 110 if (RAND_pseudo_bytes(rr->signedContentIdentifier->data, 32) 111 <= 0) 112 goto err; 113 } 114 115 sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free); 116 rr->receiptsTo = receiptsTo; 117 118 if (receiptList) { 119 rr->receiptsFrom->type = 1; 120 rr->receiptsFrom->d.receiptList = receiptList; 121 } else { 122 rr->receiptsFrom->type = 0; 123 rr->receiptsFrom->d.allOrFirstTier = allorfirst; 124 } 125 126 return rr; 127 128 merr: 129 CMSerr(CMS_F_CMS_RECEIPTREQUEST_CREATE0, ERR_R_MALLOC_FAILURE); 130 131 err: 132 if (rr) 133 CMS_ReceiptRequest_free(rr); 134 135 return NULL; 136 137} 138 139int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr) 140{ 141 unsigned char *rrder = NULL; 142 int rrderlen, r = 0; 143 144 rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder); 145 if (rrderlen < 0) 146 goto merr; 147 148 if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest, 149 V_ASN1_SEQUENCE, rrder, rrderlen)) 150 goto merr; 151 152 r = 1; 153 154 merr: 155 if (!r) 156 CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE); 157 158 if (rrder) 159 OPENSSL_free(rrder); 160 161 return r; 162 163} 164 165void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, 166 ASN1_STRING **pcid, 167 int *pallorfirst, 168 STACK_OF(GENERAL_NAMES) **plist, 169 STACK_OF(GENERAL_NAMES) **prto) 170{ 171 if (pcid) 172 *pcid = rr->signedContentIdentifier; 173 if (rr->receiptsFrom->type == 0) { 174 if (pallorfirst) 175 *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier; 176 if (plist) 177 *plist = NULL; 178 } else { 179 if (pallorfirst) 180 *pallorfirst = -1; 181 if (plist) 182 *plist = rr->receiptsFrom->d.receiptList; 183 } 184 if (prto) 185 *prto = rr->receiptsTo; 186} 187 188/* Digest a SignerInfo structure for msgSigDigest attribute processing */ 189 190static int cms_msgSigDigest(CMS_SignerInfo *si, 191 unsigned char *dig, unsigned int *diglen) 192{ 193 const EVP_MD *md; 194 md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm); 195 if (md == NULL) 196 return 0; 197 if (!ASN1_item_digest(ASN1_ITEM_rptr(CMS_Attributes_Verify), md, 198 si->signedAttrs, dig, diglen)) 199 return 0; 200 return 1; 201} 202 203/* Add a msgSigDigest attribute to a SignerInfo */ 204 205int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src) 206{ 207 unsigned char dig[EVP_MAX_MD_SIZE]; 208 unsigned int diglen; 209 if (!cms_msgSigDigest(src, dig, &diglen)) { 210 CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR); 211 return 0; 212 } 213 if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest, 214 V_ASN1_OCTET_STRING, dig, diglen)) { 215 CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, ERR_R_MALLOC_FAILURE); 216 return 0; 217 } 218 return 1; 219} 220 221/* Verify signed receipt after it has already passed normal CMS verify */ 222 223int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms) 224{ 225 int r = 0, i; 226 CMS_ReceiptRequest *rr = NULL; 227 CMS_Receipt *rct = NULL; 228 STACK_OF(CMS_SignerInfo) *sis, *osis; 229 CMS_SignerInfo *si, *osi = NULL; 230 ASN1_OCTET_STRING *msig, **pcont; 231 ASN1_OBJECT *octype; 232 unsigned char dig[EVP_MAX_MD_SIZE]; 233 unsigned int diglen; 234 235 /* Get SignerInfos, also checks SignedData content type */ 236 osis = CMS_get0_SignerInfos(req_cms); 237 sis = CMS_get0_SignerInfos(cms); 238 if (!osis || !sis) 239 goto err; 240 241 if (sk_CMS_SignerInfo_num(sis) != 1) { 242 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NEED_ONE_SIGNER); 243 goto err; 244 } 245 246 /* Check receipt content type */ 247 if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) { 248 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NOT_A_SIGNED_RECEIPT); 249 goto err; 250 } 251 252 /* Extract and decode receipt content */ 253 pcont = CMS_get0_content(cms); 254 if (!pcont || !*pcont) { 255 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT); 256 goto err; 257 } 258 259 rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt)); 260 261 if (!rct) { 262 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_RECEIPT_DECODE_ERROR); 263 goto err; 264 } 265 266 /* Locate original request */ 267 268 for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) { 269 osi = sk_CMS_SignerInfo_value(osis, i); 270 if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue)) 271 break; 272 } 273 274 if (i == sk_CMS_SignerInfo_num(osis)) { 275 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MATCHING_SIGNATURE); 276 goto err; 277 } 278 279 si = sk_CMS_SignerInfo_value(sis, 0); 280 281 /* Get msgSigDigest value and compare */ 282 283 msig = CMS_signed_get0_data_by_OBJ(si, 284 OBJ_nid2obj 285 (NID_id_smime_aa_msgSigDigest), -3, 286 V_ASN1_OCTET_STRING); 287 288 if (!msig) { 289 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MSGSIGDIGEST); 290 goto err; 291 } 292 293 if (!cms_msgSigDigest(osi, dig, &diglen)) { 294 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_ERROR); 295 goto err; 296 } 297 298 if (diglen != (unsigned int)msig->length) { 299 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_WRONG_LENGTH); 300 goto err; 301 } 302 303 if (memcmp(dig, msig->data, diglen)) { 304 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, 305 CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE); 306 goto err; 307 } 308 309 /* Compare content types */ 310 311 octype = CMS_signed_get0_data_by_OBJ(osi, 312 OBJ_nid2obj(NID_pkcs9_contentType), 313 -3, V_ASN1_OBJECT); 314 if (!octype) { 315 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT_TYPE); 316 goto err; 317 } 318 319 /* Compare details in receipt request */ 320 321 if (OBJ_cmp(octype, rct->contentType)) { 322 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENT_TYPE_MISMATCH); 323 goto err; 324 } 325 326 /* Get original receipt request details */ 327 328 if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) { 329 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_RECEIPT_REQUEST); 330 goto err; 331 } 332 333 if (ASN1_STRING_cmp(rr->signedContentIdentifier, 334 rct->signedContentIdentifier)) { 335 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENTIDENTIFIER_MISMATCH); 336 goto err; 337 } 338 339 r = 1; 340 341 err: 342 if (rr) 343 CMS_ReceiptRequest_free(rr); 344 if (rct) 345 M_ASN1_free_of(rct, CMS_Receipt); 346 347 return r; 348 349} 350 351/* 352 * Encode a Receipt into an OCTET STRING read for including into content of a 353 * SignedData ContentInfo. 354 */ 355 356ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si) 357{ 358 CMS_Receipt rct; 359 CMS_ReceiptRequest *rr = NULL; 360 ASN1_OBJECT *ctype; 361 ASN1_OCTET_STRING *os = NULL; 362 363 /* Get original receipt request */ 364 365 /* Get original receipt request details */ 366 367 if (CMS_get1_ReceiptRequest(si, &rr) <= 0) { 368 CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST); 369 goto err; 370 } 371 372 /* Get original content type */ 373 374 ctype = CMS_signed_get0_data_by_OBJ(si, 375 OBJ_nid2obj(NID_pkcs9_contentType), 376 -3, V_ASN1_OBJECT); 377 if (!ctype) { 378 CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_CONTENT_TYPE); 379 goto err; 380 } 381 382 rct.version = 1; 383 rct.contentType = ctype; 384 rct.signedContentIdentifier = rr->signedContentIdentifier; 385 rct.originatorSignatureValue = si->signature; 386 387 os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL); 388 389 err: 390 if (rr) 391 CMS_ReceiptRequest_free(rr); 392 393 return os; 394 395} 396