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