1/* crypto/pkcs7/pk7_lib.c */ 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59#include <stdio.h> 60#include "cryptlib.h" 61#include <openssl/objects.h> 62#include <openssl/x509.h> 63 64long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg) 65 { 66 int nid; 67 long ret; 68 69 nid=OBJ_obj2nid(p7->type); 70 71 switch (cmd) 72 { 73 case PKCS7_OP_SET_DETACHED_SIGNATURE: 74 if (nid == NID_pkcs7_signed) 75 { 76 ret=p7->detached=(int)larg; 77 if (ret && PKCS7_type_is_data(p7->d.sign->contents)) 78 { 79 ASN1_OCTET_STRING *os; 80 os=p7->d.sign->contents->d.data; 81 ASN1_OCTET_STRING_free(os); 82 p7->d.sign->contents->d.data = NULL; 83 } 84 } 85 else 86 { 87 PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); 88 ret=0; 89 } 90 break; 91 case PKCS7_OP_GET_DETACHED_SIGNATURE: 92 if (nid == NID_pkcs7_signed) 93 { 94 if(!p7->d.sign || !p7->d.sign->contents->d.ptr) 95 ret = 1; 96 else ret = 0; 97 98 p7->detached = ret; 99 } 100 else 101 { 102 PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); 103 ret=0; 104 } 105 106 break; 107 default: 108 PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_UNKNOWN_OPERATION); 109 ret=0; 110 } 111 return(ret); 112 } 113 114int PKCS7_content_new(PKCS7 *p7, int type) 115 { 116 PKCS7 *ret=NULL; 117 118 if ((ret=PKCS7_new()) == NULL) goto err; 119 if (!PKCS7_set_type(ret,type)) goto err; 120 if (!PKCS7_set_content(p7,ret)) goto err; 121 122 return(1); 123err: 124 if (ret != NULL) PKCS7_free(ret); 125 return(0); 126 } 127 128int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data) 129 { 130 int i; 131 132 i=OBJ_obj2nid(p7->type); 133 switch (i) 134 { 135 case NID_pkcs7_signed: 136 if (p7->d.sign->contents != NULL) 137 PKCS7_free(p7->d.sign->contents); 138 p7->d.sign->contents=p7_data; 139 break; 140 case NID_pkcs7_digest: 141 if (p7->d.digest->contents != NULL) 142 PKCS7_free(p7->d.digest->contents); 143 p7->d.digest->contents=p7_data; 144 break; 145 case NID_pkcs7_data: 146 case NID_pkcs7_enveloped: 147 case NID_pkcs7_signedAndEnveloped: 148 case NID_pkcs7_encrypted: 149 default: 150 PKCS7err(PKCS7_F_PKCS7_SET_CONTENT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); 151 goto err; 152 } 153 return(1); 154err: 155 return(0); 156 } 157 158int PKCS7_set_type(PKCS7 *p7, int type) 159 { 160 ASN1_OBJECT *obj; 161 162 /*PKCS7_content_free(p7);*/ 163 obj=OBJ_nid2obj(type); /* will not fail */ 164 165 switch (type) 166 { 167 case NID_pkcs7_signed: 168 p7->type=obj; 169 if ((p7->d.sign=PKCS7_SIGNED_new()) == NULL) 170 goto err; 171 if (!ASN1_INTEGER_set(p7->d.sign->version,1)) 172 { 173 PKCS7_SIGNED_free(p7->d.sign); 174 p7->d.sign=NULL; 175 goto err; 176 } 177 break; 178 case NID_pkcs7_data: 179 p7->type=obj; 180 if ((p7->d.data=M_ASN1_OCTET_STRING_new()) == NULL) 181 goto err; 182 break; 183 case NID_pkcs7_signedAndEnveloped: 184 p7->type=obj; 185 if ((p7->d.signed_and_enveloped=PKCS7_SIGN_ENVELOPE_new()) 186 == NULL) goto err; 187 ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1); 188 if (!ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1)) 189 goto err; 190 p7->d.signed_and_enveloped->enc_data->content_type 191 = OBJ_nid2obj(NID_pkcs7_data); 192 break; 193 case NID_pkcs7_enveloped: 194 p7->type=obj; 195 if ((p7->d.enveloped=PKCS7_ENVELOPE_new()) 196 == NULL) goto err; 197 if (!ASN1_INTEGER_set(p7->d.enveloped->version,0)) 198 goto err; 199 p7->d.enveloped->enc_data->content_type 200 = OBJ_nid2obj(NID_pkcs7_data); 201 break; 202 case NID_pkcs7_encrypted: 203 p7->type=obj; 204 if ((p7->d.encrypted=PKCS7_ENCRYPT_new()) 205 == NULL) goto err; 206 if (!ASN1_INTEGER_set(p7->d.encrypted->version,0)) 207 goto err; 208 p7->d.encrypted->enc_data->content_type 209 = OBJ_nid2obj(NID_pkcs7_data); 210 break; 211 212 case NID_pkcs7_digest: 213 p7->type=obj; 214 if ((p7->d.digest=PKCS7_DIGEST_new()) 215 == NULL) goto err; 216 if (!ASN1_INTEGER_set(p7->d.digest->version,0)) 217 goto err; 218 break; 219 default: 220 PKCS7err(PKCS7_F_PKCS7_SET_TYPE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); 221 goto err; 222 } 223 return(1); 224err: 225 return(0); 226 } 227 228int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other) 229 { 230 p7->type = OBJ_nid2obj(type); 231 p7->d.other = other; 232 return 1; 233 } 234 235int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *psi) 236 { 237 int i,j,nid; 238 X509_ALGOR *alg; 239 STACK_OF(PKCS7_SIGNER_INFO) *signer_sk; 240 STACK_OF(X509_ALGOR) *md_sk; 241 242 i=OBJ_obj2nid(p7->type); 243 switch (i) 244 { 245 case NID_pkcs7_signed: 246 signer_sk= p7->d.sign->signer_info; 247 md_sk= p7->d.sign->md_algs; 248 break; 249 case NID_pkcs7_signedAndEnveloped: 250 signer_sk= p7->d.signed_and_enveloped->signer_info; 251 md_sk= p7->d.signed_and_enveloped->md_algs; 252 break; 253 default: 254 PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,PKCS7_R_WRONG_CONTENT_TYPE); 255 return(0); 256 } 257 258 nid=OBJ_obj2nid(psi->digest_alg->algorithm); 259 260 /* If the digest is not currently listed, add it */ 261 j=0; 262 for (i=0; i<sk_X509_ALGOR_num(md_sk); i++) 263 { 264 alg=sk_X509_ALGOR_value(md_sk,i); 265 if (OBJ_obj2nid(alg->algorithm) == nid) 266 { 267 j=1; 268 break; 269 } 270 } 271 if (!j) /* we need to add another algorithm */ 272 { 273 if(!(alg=X509_ALGOR_new()) 274 || !(alg->parameter = ASN1_TYPE_new())) 275 { 276 X509_ALGOR_free(alg); 277 PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,ERR_R_MALLOC_FAILURE); 278 return(0); 279 } 280 alg->algorithm=OBJ_nid2obj(nid); 281 alg->parameter->type = V_ASN1_NULL; 282 if (!sk_X509_ALGOR_push(md_sk,alg)) 283 { 284 X509_ALGOR_free(alg); 285 return 0; 286 } 287 } 288 289 if (!sk_PKCS7_SIGNER_INFO_push(signer_sk,psi)) 290 return 0; 291 return(1); 292 } 293 294int PKCS7_add_certificate(PKCS7 *p7, X509 *x509) 295 { 296 int i; 297 STACK_OF(X509) **sk; 298 299 i=OBJ_obj2nid(p7->type); 300 switch (i) 301 { 302 case NID_pkcs7_signed: 303 sk= &(p7->d.sign->cert); 304 break; 305 case NID_pkcs7_signedAndEnveloped: 306 sk= &(p7->d.signed_and_enveloped->cert); 307 break; 308 default: 309 PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,PKCS7_R_WRONG_CONTENT_TYPE); 310 return(0); 311 } 312 313 if (*sk == NULL) 314 *sk=sk_X509_new_null(); 315 if (*sk == NULL) 316 { 317 PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,ERR_R_MALLOC_FAILURE); 318 return 0; 319 } 320 CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); 321 if (!sk_X509_push(*sk,x509)) 322 { 323 X509_free(x509); 324 return 0; 325 } 326 return(1); 327 } 328 329int PKCS7_add_crl(PKCS7 *p7, X509_CRL *crl) 330 { 331 int i; 332 STACK_OF(X509_CRL) **sk; 333 334 i=OBJ_obj2nid(p7->type); 335 switch (i) 336 { 337 case NID_pkcs7_signed: 338 sk= &(p7->d.sign->crl); 339 break; 340 case NID_pkcs7_signedAndEnveloped: 341 sk= &(p7->d.signed_and_enveloped->crl); 342 break; 343 default: 344 PKCS7err(PKCS7_F_PKCS7_ADD_CRL,PKCS7_R_WRONG_CONTENT_TYPE); 345 return(0); 346 } 347 348 if (*sk == NULL) 349 *sk=sk_X509_CRL_new_null(); 350 if (*sk == NULL) 351 { 352 PKCS7err(PKCS7_F_PKCS7_ADD_CRL,ERR_R_MALLOC_FAILURE); 353 return 0; 354 } 355 356 CRYPTO_add(&crl->references,1,CRYPTO_LOCK_X509_CRL); 357 if (!sk_X509_CRL_push(*sk,crl)) 358 { 359 X509_CRL_free(crl); 360 return 0; 361 } 362 return(1); 363 } 364 365int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, 366 const EVP_MD *dgst) 367 { 368 int nid; 369 char is_dsa; 370 371 if (pkey->type == EVP_PKEY_DSA || pkey->type == EVP_PKEY_EC) 372 is_dsa = 1; 373 else 374 is_dsa = 0; 375 /* We now need to add another PKCS7_SIGNER_INFO entry */ 376 if (!ASN1_INTEGER_set(p7i->version,1)) 377 goto err; 378 if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, 379 X509_get_issuer_name(x509))) 380 goto err; 381 382 /* because ASN1_INTEGER_set is used to set a 'long' we will do 383 * things the ugly way. */ 384 M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); 385 if (!(p7i->issuer_and_serial->serial= 386 M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) 387 goto err; 388 389 /* lets keep the pkey around for a while */ 390 CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY); 391 p7i->pkey=pkey; 392 393 /* Set the algorithms */ 394 if (is_dsa) p7i->digest_alg->algorithm=OBJ_nid2obj(NID_sha1); 395 else 396 p7i->digest_alg->algorithm=OBJ_nid2obj(EVP_MD_type(dgst)); 397 398 if (p7i->digest_alg->parameter != NULL) 399 ASN1_TYPE_free(p7i->digest_alg->parameter); 400 if ((p7i->digest_alg->parameter=ASN1_TYPE_new()) == NULL) 401 goto err; 402 p7i->digest_alg->parameter->type=V_ASN1_NULL; 403 404 if (p7i->digest_enc_alg->parameter != NULL) 405 ASN1_TYPE_free(p7i->digest_enc_alg->parameter); 406 nid = EVP_PKEY_type(pkey->type); 407 if (nid == EVP_PKEY_RSA) 408 { 409 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_rsaEncryption); 410 if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) 411 goto err; 412 p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; 413 } 414 else if (nid == EVP_PKEY_DSA) 415 { 416#if 1 417 /* use 'dsaEncryption' OID for compatibility with other software 418 * (PKCS #7 v1.5 does specify how to handle DSA) ... */ 419 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_dsa); 420#else 421 /* ... although the 'dsaWithSHA1' OID (as required by RFC 2630 for CMS) 422 * would make more sense. */ 423 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_dsaWithSHA1); 424#endif 425 p7i->digest_enc_alg->parameter = NULL; /* special case for DSA: omit 'parameter'! */ 426 } 427 else if (nid == EVP_PKEY_EC) 428 { 429 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_ecdsa_with_SHA1); 430 if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) 431 goto err; 432 p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; 433 } 434 else 435 return(0); 436 437 return(1); 438err: 439 return(0); 440 } 441 442PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey, 443 const EVP_MD *dgst) 444 { 445 PKCS7_SIGNER_INFO *si; 446 447 if ((si=PKCS7_SIGNER_INFO_new()) == NULL) goto err; 448 if (!PKCS7_SIGNER_INFO_set(si,x509,pkey,dgst)) goto err; 449 if (!PKCS7_add_signer(p7,si)) goto err; 450 return(si); 451err: 452 PKCS7_SIGNER_INFO_free(si); 453 return(NULL); 454 } 455 456int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) 457 { 458 if (PKCS7_type_is_digest(p7)) 459 { 460 if(!(p7->d.digest->md->parameter = ASN1_TYPE_new())) 461 { 462 PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,ERR_R_MALLOC_FAILURE); 463 return 0; 464 } 465 p7->d.digest->md->parameter->type = V_ASN1_NULL; 466 p7->d.digest->md->algorithm = OBJ_nid2obj(EVP_MD_nid(md)); 467 return 1; 468 } 469 470 PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,PKCS7_R_WRONG_CONTENT_TYPE); 471 return 1; 472 } 473 474STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7) 475 { 476 if (PKCS7_type_is_signed(p7)) 477 { 478 return(p7->d.sign->signer_info); 479 } 480 else if (PKCS7_type_is_signedAndEnveloped(p7)) 481 { 482 return(p7->d.signed_and_enveloped->signer_info); 483 } 484 else 485 return(NULL); 486 } 487 488PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509) 489 { 490 PKCS7_RECIP_INFO *ri; 491 492 if ((ri=PKCS7_RECIP_INFO_new()) == NULL) goto err; 493 if (!PKCS7_RECIP_INFO_set(ri,x509)) goto err; 494 if (!PKCS7_add_recipient_info(p7,ri)) goto err; 495 return(ri); 496err: 497 PKCS7_RECIP_INFO_free(ri); 498 return(NULL); 499 } 500 501int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri) 502 { 503 int i; 504 STACK_OF(PKCS7_RECIP_INFO) *sk; 505 506 i=OBJ_obj2nid(p7->type); 507 switch (i) 508 { 509 case NID_pkcs7_signedAndEnveloped: 510 sk= p7->d.signed_and_enveloped->recipientinfo; 511 break; 512 case NID_pkcs7_enveloped: 513 sk= p7->d.enveloped->recipientinfo; 514 break; 515 default: 516 PKCS7err(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO,PKCS7_R_WRONG_CONTENT_TYPE); 517 return(0); 518 } 519 520 if (!sk_PKCS7_RECIP_INFO_push(sk,ri)) 521 return 0; 522 return(1); 523 } 524 525int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509) 526 { 527 if (!ASN1_INTEGER_set(p7i->version,0)) 528 return 0; 529 if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, 530 X509_get_issuer_name(x509))) 531 return 0; 532 533 M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); 534 if (!(p7i->issuer_and_serial->serial= 535 M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) 536 return 0; 537 538 X509_ALGOR_free(p7i->key_enc_algor); 539 if (!(p7i->key_enc_algor= X509_ALGOR_dup(x509->cert_info->key->algor))) 540 return 0; 541 542 CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); 543 p7i->cert=x509; 544 545 return(1); 546 } 547 548X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si) 549 { 550 if (PKCS7_type_is_signed(p7)) 551 return(X509_find_by_issuer_and_serial(p7->d.sign->cert, 552 si->issuer_and_serial->issuer, 553 si->issuer_and_serial->serial)); 554 else 555 return(NULL); 556 } 557 558int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher) 559 { 560 int i; 561 ASN1_OBJECT *objtmp; 562 PKCS7_ENC_CONTENT *ec; 563 564 i=OBJ_obj2nid(p7->type); 565 switch (i) 566 { 567 case NID_pkcs7_signedAndEnveloped: 568 ec=p7->d.signed_and_enveloped->enc_data; 569 break; 570 case NID_pkcs7_enveloped: 571 ec=p7->d.enveloped->enc_data; 572 break; 573 default: 574 PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_WRONG_CONTENT_TYPE); 575 return(0); 576 } 577 578 /* Check cipher OID exists and has data in it*/ 579 i = EVP_CIPHER_type(cipher); 580 if(i == NID_undef) { 581 PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); 582 return(0); 583 } 584 objtmp = OBJ_nid2obj(i); 585 586 ec->cipher = cipher; 587 return 1; 588 } 589 590