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