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