pk7_lib.c revision 280268
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 /* NOTE(emilia): does not support detached digested data. */ 74 case PKCS7_OP_SET_DETACHED_SIGNATURE: 75 if (nid == NID_pkcs7_signed) 76 { 77 ret=p7->detached=(int)larg; 78 if (ret && PKCS7_type_is_data(p7->d.sign->contents)) 79 { 80 ASN1_OCTET_STRING *os; 81 os=p7->d.sign->contents->d.data; 82 ASN1_OCTET_STRING_free(os); 83 p7->d.sign->contents->d.data = NULL; 84 } 85 } 86 else 87 { 88 PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); 89 ret=0; 90 } 91 break; 92 case PKCS7_OP_GET_DETACHED_SIGNATURE: 93 if (nid == NID_pkcs7_signed) 94 { 95 if(!p7->d.sign || !p7->d.sign->contents->d.ptr) 96 ret = 1; 97 else ret = 0; 98 99 p7->detached = ret; 100 } 101 else 102 { 103 PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); 104 ret=0; 105 } 106 107 break; 108 default: 109 PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_UNKNOWN_OPERATION); 110 ret=0; 111 } 112 return(ret); 113 } 114 115int PKCS7_content_new(PKCS7 *p7, int type) 116 { 117 PKCS7 *ret=NULL; 118 119 if ((ret=PKCS7_new()) == NULL) goto err; 120 if (!PKCS7_set_type(ret,type)) goto err; 121 if (!PKCS7_set_content(p7,ret)) goto err; 122 123 return(1); 124err: 125 if (ret != NULL) PKCS7_free(ret); 126 return(0); 127 } 128 129int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data) 130 { 131 int i; 132 133 i=OBJ_obj2nid(p7->type); 134 switch (i) 135 { 136 case NID_pkcs7_signed: 137 if (p7->d.sign->contents != NULL) 138 PKCS7_free(p7->d.sign->contents); 139 p7->d.sign->contents=p7_data; 140 break; 141 case NID_pkcs7_digest: 142 if (p7->d.digest->contents != NULL) 143 PKCS7_free(p7->d.digest->contents); 144 p7->d.digest->contents=p7_data; 145 break; 146 case NID_pkcs7_data: 147 case NID_pkcs7_enveloped: 148 case NID_pkcs7_signedAndEnveloped: 149 case NID_pkcs7_encrypted: 150 default: 151 PKCS7err(PKCS7_F_PKCS7_SET_CONTENT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); 152 goto err; 153 } 154 return(1); 155err: 156 return(0); 157 } 158 159int PKCS7_set_type(PKCS7 *p7, int type) 160 { 161 ASN1_OBJECT *obj; 162 163 /*PKCS7_content_free(p7);*/ 164 obj=OBJ_nid2obj(type); /* will not fail */ 165 166 switch (type) 167 { 168 case NID_pkcs7_signed: 169 p7->type=obj; 170 if ((p7->d.sign=PKCS7_SIGNED_new()) == NULL) 171 goto err; 172 if (!ASN1_INTEGER_set(p7->d.sign->version,1)) 173 { 174 PKCS7_SIGNED_free(p7->d.sign); 175 p7->d.sign=NULL; 176 goto err; 177 } 178 break; 179 case NID_pkcs7_data: 180 p7->type=obj; 181 if ((p7->d.data=M_ASN1_OCTET_STRING_new()) == NULL) 182 goto err; 183 break; 184 case NID_pkcs7_signedAndEnveloped: 185 p7->type=obj; 186 if ((p7->d.signed_and_enveloped=PKCS7_SIGN_ENVELOPE_new()) 187 == NULL) goto err; 188 ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1); 189 if (!ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1)) 190 goto err; 191 p7->d.signed_and_enveloped->enc_data->content_type 192 = OBJ_nid2obj(NID_pkcs7_data); 193 break; 194 case NID_pkcs7_enveloped: 195 p7->type=obj; 196 if ((p7->d.enveloped=PKCS7_ENVELOPE_new()) 197 == NULL) goto err; 198 if (!ASN1_INTEGER_set(p7->d.enveloped->version,0)) 199 goto err; 200 p7->d.enveloped->enc_data->content_type 201 = OBJ_nid2obj(NID_pkcs7_data); 202 break; 203 case NID_pkcs7_encrypted: 204 p7->type=obj; 205 if ((p7->d.encrypted=PKCS7_ENCRYPT_new()) 206 == NULL) goto err; 207 if (!ASN1_INTEGER_set(p7->d.encrypted->version,0)) 208 goto err; 209 p7->d.encrypted->enc_data->content_type 210 = OBJ_nid2obj(NID_pkcs7_data); 211 break; 212 213 case NID_pkcs7_digest: 214 p7->type=obj; 215 if ((p7->d.digest=PKCS7_DIGEST_new()) 216 == NULL) goto err; 217 if (!ASN1_INTEGER_set(p7->d.digest->version,0)) 218 goto err; 219 break; 220 default: 221 PKCS7err(PKCS7_F_PKCS7_SET_TYPE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); 222 goto err; 223 } 224 return(1); 225err: 226 return(0); 227 } 228 229int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other) 230 { 231 p7->type = OBJ_nid2obj(type); 232 p7->d.other = other; 233 return 1; 234 } 235 236int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *psi) 237 { 238 int i,j,nid; 239 X509_ALGOR *alg; 240 STACK_OF(PKCS7_SIGNER_INFO) *signer_sk; 241 STACK_OF(X509_ALGOR) *md_sk; 242 243 i=OBJ_obj2nid(p7->type); 244 switch (i) 245 { 246 case NID_pkcs7_signed: 247 signer_sk= p7->d.sign->signer_info; 248 md_sk= p7->d.sign->md_algs; 249 break; 250 case NID_pkcs7_signedAndEnveloped: 251 signer_sk= p7->d.signed_and_enveloped->signer_info; 252 md_sk= p7->d.signed_and_enveloped->md_algs; 253 break; 254 default: 255 PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,PKCS7_R_WRONG_CONTENT_TYPE); 256 return(0); 257 } 258 259 nid=OBJ_obj2nid(psi->digest_alg->algorithm); 260 261 /* If the digest is not currently listed, add it */ 262 j=0; 263 for (i=0; i<sk_X509_ALGOR_num(md_sk); i++) 264 { 265 alg=sk_X509_ALGOR_value(md_sk,i); 266 if (OBJ_obj2nid(alg->algorithm) == nid) 267 { 268 j=1; 269 break; 270 } 271 } 272 if (!j) /* we need to add another algorithm */ 273 { 274 if(!(alg=X509_ALGOR_new()) 275 || !(alg->parameter = ASN1_TYPE_new())) 276 { 277 X509_ALGOR_free(alg); 278 PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,ERR_R_MALLOC_FAILURE); 279 return(0); 280 } 281 alg->algorithm=OBJ_nid2obj(nid); 282 alg->parameter->type = V_ASN1_NULL; 283 if (!sk_X509_ALGOR_push(md_sk,alg)) 284 { 285 X509_ALGOR_free(alg); 286 return 0; 287 } 288 } 289 290 if (!sk_PKCS7_SIGNER_INFO_push(signer_sk,psi)) 291 return 0; 292 return(1); 293 } 294 295int PKCS7_add_certificate(PKCS7 *p7, X509 *x509) 296 { 297 int i; 298 STACK_OF(X509) **sk; 299 300 i=OBJ_obj2nid(p7->type); 301 switch (i) 302 { 303 case NID_pkcs7_signed: 304 sk= &(p7->d.sign->cert); 305 break; 306 case NID_pkcs7_signedAndEnveloped: 307 sk= &(p7->d.signed_and_enveloped->cert); 308 break; 309 default: 310 PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,PKCS7_R_WRONG_CONTENT_TYPE); 311 return(0); 312 } 313 314 if (*sk == NULL) 315 *sk=sk_X509_new_null(); 316 if (*sk == NULL) 317 { 318 PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,ERR_R_MALLOC_FAILURE); 319 return 0; 320 } 321 CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); 322 if (!sk_X509_push(*sk,x509)) 323 { 324 X509_free(x509); 325 return 0; 326 } 327 return(1); 328 } 329 330int PKCS7_add_crl(PKCS7 *p7, X509_CRL *crl) 331 { 332 int i; 333 STACK_OF(X509_CRL) **sk; 334 335 i=OBJ_obj2nid(p7->type); 336 switch (i) 337 { 338 case NID_pkcs7_signed: 339 sk= &(p7->d.sign->crl); 340 break; 341 case NID_pkcs7_signedAndEnveloped: 342 sk= &(p7->d.signed_and_enveloped->crl); 343 break; 344 default: 345 PKCS7err(PKCS7_F_PKCS7_ADD_CRL,PKCS7_R_WRONG_CONTENT_TYPE); 346 return(0); 347 } 348 349 if (*sk == NULL) 350 *sk=sk_X509_CRL_new_null(); 351 if (*sk == NULL) 352 { 353 PKCS7err(PKCS7_F_PKCS7_ADD_CRL,ERR_R_MALLOC_FAILURE); 354 return 0; 355 } 356 357 CRYPTO_add(&crl->references,1,CRYPTO_LOCK_X509_CRL); 358 if (!sk_X509_CRL_push(*sk,crl)) 359 { 360 X509_CRL_free(crl); 361 return 0; 362 } 363 return(1); 364 } 365 366int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, 367 const EVP_MD *dgst) 368 { 369 int nid; 370 char is_dsa; 371 372 if (pkey->type == EVP_PKEY_DSA || pkey->type == EVP_PKEY_EC) 373 is_dsa = 1; 374 else 375 is_dsa = 0; 376 /* We now need to add another PKCS7_SIGNER_INFO entry */ 377 if (!ASN1_INTEGER_set(p7i->version,1)) 378 goto err; 379 if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, 380 X509_get_issuer_name(x509))) 381 goto err; 382 383 /* because ASN1_INTEGER_set is used to set a 'long' we will do 384 * things the ugly way. */ 385 M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); 386 if (!(p7i->issuer_and_serial->serial= 387 M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) 388 goto err; 389 390 /* lets keep the pkey around for a while */ 391 CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY); 392 p7i->pkey=pkey; 393 394 /* Set the algorithms */ 395 if (is_dsa) p7i->digest_alg->algorithm=OBJ_nid2obj(NID_sha1); 396 else 397 p7i->digest_alg->algorithm=OBJ_nid2obj(EVP_MD_type(dgst)); 398 399 if (p7i->digest_alg->parameter != NULL) 400 ASN1_TYPE_free(p7i->digest_alg->parameter); 401 if ((p7i->digest_alg->parameter=ASN1_TYPE_new()) == NULL) 402 goto err; 403 p7i->digest_alg->parameter->type=V_ASN1_NULL; 404 405 if (p7i->digest_enc_alg->parameter != NULL) 406 ASN1_TYPE_free(p7i->digest_enc_alg->parameter); 407 nid = EVP_PKEY_type(pkey->type); 408 if (nid == EVP_PKEY_RSA) 409 { 410 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_rsaEncryption); 411 if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) 412 goto err; 413 p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; 414 } 415 else if (nid == EVP_PKEY_DSA) 416 { 417#if 1 418 /* use 'dsaEncryption' OID for compatibility with other software 419 * (PKCS #7 v1.5 does specify how to handle DSA) ... */ 420 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_dsa); 421#else 422 /* ... although the 'dsaWithSHA1' OID (as required by RFC 2630 for CMS) 423 * would make more sense. */ 424 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_dsaWithSHA1); 425#endif 426 p7i->digest_enc_alg->parameter = NULL; /* special case for DSA: omit 'parameter'! */ 427 } 428 else if (nid == EVP_PKEY_EC) 429 { 430 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_ecdsa_with_SHA1); 431 if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) 432 goto err; 433 p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; 434 } 435 else 436 return(0); 437 438 return(1); 439err: 440 return(0); 441 } 442 443PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey, 444 const EVP_MD *dgst) 445 { 446 PKCS7_SIGNER_INFO *si; 447 448 if ((si=PKCS7_SIGNER_INFO_new()) == NULL) goto err; 449 if (!PKCS7_SIGNER_INFO_set(si,x509,pkey,dgst)) goto err; 450 if (!PKCS7_add_signer(p7,si)) goto err; 451 return(si); 452err: 453 PKCS7_SIGNER_INFO_free(si); 454 return(NULL); 455 } 456 457int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) 458 { 459 if (PKCS7_type_is_digest(p7)) 460 { 461 if(!(p7->d.digest->md->parameter = ASN1_TYPE_new())) 462 { 463 PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,ERR_R_MALLOC_FAILURE); 464 return 0; 465 } 466 p7->d.digest->md->parameter->type = V_ASN1_NULL; 467 p7->d.digest->md->algorithm = OBJ_nid2obj(EVP_MD_nid(md)); 468 return 1; 469 } 470 471 PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,PKCS7_R_WRONG_CONTENT_TYPE); 472 return 1; 473 } 474 475STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7) 476 { 477 if (p7 == NULL || p7->d.ptr == NULL) 478 return NULL; 479 if (PKCS7_type_is_signed(p7)) 480 { 481 return(p7->d.sign->signer_info); 482 } 483 else if (PKCS7_type_is_signedAndEnveloped(p7)) 484 { 485 return(p7->d.signed_and_enveloped->signer_info); 486 } 487 else 488 return(NULL); 489 } 490 491PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509) 492 { 493 PKCS7_RECIP_INFO *ri; 494 495 if ((ri=PKCS7_RECIP_INFO_new()) == NULL) goto err; 496 if (!PKCS7_RECIP_INFO_set(ri,x509)) goto err; 497 if (!PKCS7_add_recipient_info(p7,ri)) goto err; 498 return(ri); 499err: 500 PKCS7_RECIP_INFO_free(ri); 501 return(NULL); 502 } 503 504int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri) 505 { 506 int i; 507 STACK_OF(PKCS7_RECIP_INFO) *sk; 508 509 i=OBJ_obj2nid(p7->type); 510 switch (i) 511 { 512 case NID_pkcs7_signedAndEnveloped: 513 sk= p7->d.signed_and_enveloped->recipientinfo; 514 break; 515 case NID_pkcs7_enveloped: 516 sk= p7->d.enveloped->recipientinfo; 517 break; 518 default: 519 PKCS7err(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO,PKCS7_R_WRONG_CONTENT_TYPE); 520 return(0); 521 } 522 523 if (!sk_PKCS7_RECIP_INFO_push(sk,ri)) 524 return 0; 525 return(1); 526 } 527 528int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509) 529 { 530 if (!ASN1_INTEGER_set(p7i->version,0)) 531 return 0; 532 if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, 533 X509_get_issuer_name(x509))) 534 return 0; 535 536 M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); 537 if (!(p7i->issuer_and_serial->serial= 538 M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) 539 return 0; 540 541 X509_ALGOR_free(p7i->key_enc_algor); 542 if (!(p7i->key_enc_algor= X509_ALGOR_dup(x509->cert_info->key->algor))) 543 return 0; 544 545 CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); 546 p7i->cert=x509; 547 548 return(1); 549 } 550 551X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si) 552 { 553 if (PKCS7_type_is_signed(p7)) 554 return(X509_find_by_issuer_and_serial(p7->d.sign->cert, 555 si->issuer_and_serial->issuer, 556 si->issuer_and_serial->serial)); 557 else 558 return(NULL); 559 } 560 561int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher) 562 { 563 int i; 564 PKCS7_ENC_CONTENT *ec; 565 566 i=OBJ_obj2nid(p7->type); 567 switch (i) 568 { 569 case NID_pkcs7_signedAndEnveloped: 570 ec=p7->d.signed_and_enveloped->enc_data; 571 break; 572 case NID_pkcs7_enveloped: 573 ec=p7->d.enveloped->enc_data; 574 break; 575 default: 576 PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_WRONG_CONTENT_TYPE); 577 return(0); 578 } 579 580 /* Check cipher OID exists and has data in it*/ 581 i = EVP_CIPHER_type(cipher); 582 if(i == NID_undef) { 583 PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); 584 return(0); 585 } 586 587 ec->cipher = cipher; 588 return 1; 589 } 590 591