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 PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,ERR_R_MALLOC_FAILURE); 276 return(0); 277 } 278 alg->algorithm=OBJ_nid2obj(nid); 279 alg->parameter->type = V_ASN1_NULL; 280 sk_X509_ALGOR_push(md_sk,alg); 281 } 282 283 sk_PKCS7_SIGNER_INFO_push(signer_sk,psi); 284 return(1); 285 } 286 287int PKCS7_add_certificate(PKCS7 *p7, X509 *x509) 288 { 289 int i; 290 STACK_OF(X509) **sk; 291 292 i=OBJ_obj2nid(p7->type); 293 switch (i) 294 { 295 case NID_pkcs7_signed: 296 sk= &(p7->d.sign->cert); 297 break; 298 case NID_pkcs7_signedAndEnveloped: 299 sk= &(p7->d.signed_and_enveloped->cert); 300 break; 301 default: 302 PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,PKCS7_R_WRONG_CONTENT_TYPE); 303 return(0); 304 } 305 306 if (*sk == NULL) 307 *sk=sk_X509_new_null(); 308 CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); 309 sk_X509_push(*sk,x509); 310 return(1); 311 } 312 313int PKCS7_add_crl(PKCS7 *p7, X509_CRL *crl) 314 { 315 int i; 316 STACK_OF(X509_CRL) **sk; 317 318 i=OBJ_obj2nid(p7->type); 319 switch (i) 320 { 321 case NID_pkcs7_signed: 322 sk= &(p7->d.sign->crl); 323 break; 324 case NID_pkcs7_signedAndEnveloped: 325 sk= &(p7->d.signed_and_enveloped->crl); 326 break; 327 default: 328 PKCS7err(PKCS7_F_PKCS7_ADD_CRL,PKCS7_R_WRONG_CONTENT_TYPE); 329 return(0); 330 } 331 332 if (*sk == NULL) 333 *sk=sk_X509_CRL_new_null(); 334 335 CRYPTO_add(&crl->references,1,CRYPTO_LOCK_X509_CRL); 336 sk_X509_CRL_push(*sk,crl); 337 return(1); 338 } 339 340int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, 341 const EVP_MD *dgst) 342 { 343 int nid; 344 char is_dsa; 345 346 if (pkey->type == EVP_PKEY_DSA || pkey->type == EVP_PKEY_EC) 347 is_dsa = 1; 348 else 349 is_dsa = 0; 350 /* We now need to add another PKCS7_SIGNER_INFO entry */ 351 if (!ASN1_INTEGER_set(p7i->version,1)) 352 goto err; 353 if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, 354 X509_get_issuer_name(x509))) 355 goto err; 356 357 /* because ASN1_INTEGER_set is used to set a 'long' we will do 358 * things the ugly way. */ 359 M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); 360 if (!(p7i->issuer_and_serial->serial= 361 M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) 362 goto err; 363 364 /* lets keep the pkey around for a while */ 365 CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY); 366 p7i->pkey=pkey; 367 368 /* Set the algorithms */ 369 if (is_dsa) p7i->digest_alg->algorithm=OBJ_nid2obj(NID_sha1); 370 else 371 p7i->digest_alg->algorithm=OBJ_nid2obj(EVP_MD_type(dgst)); 372 373 if (p7i->digest_alg->parameter != NULL) 374 ASN1_TYPE_free(p7i->digest_alg->parameter); 375 if ((p7i->digest_alg->parameter=ASN1_TYPE_new()) == NULL) 376 goto err; 377 p7i->digest_alg->parameter->type=V_ASN1_NULL; 378 379 if (p7i->digest_enc_alg->parameter != NULL) 380 ASN1_TYPE_free(p7i->digest_enc_alg->parameter); 381 nid = EVP_PKEY_type(pkey->type); 382 if (nid == EVP_PKEY_RSA) 383 { 384 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_rsaEncryption); 385 if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) 386 goto err; 387 p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; 388 } 389 else if (nid == EVP_PKEY_DSA) 390 { 391#if 1 392 /* use 'dsaEncryption' OID for compatibility with other software 393 * (PKCS #7 v1.5 does specify how to handle DSA) ... */ 394 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_dsa); 395#else 396 /* ... although the 'dsaWithSHA1' OID (as required by RFC 2630 for CMS) 397 * would make more sense. */ 398 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_dsaWithSHA1); 399#endif 400 p7i->digest_enc_alg->parameter = NULL; /* special case for DSA: omit 'parameter'! */ 401 } 402 else if (nid == EVP_PKEY_EC) 403 { 404 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(NID_ecdsa_with_SHA1); 405 if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) 406 goto err; 407 p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; 408 } 409 else 410 return(0); 411 412 return(1); 413err: 414 return(0); 415 } 416 417PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey, 418 const EVP_MD *dgst) 419 { 420 PKCS7_SIGNER_INFO *si; 421 422 if ((si=PKCS7_SIGNER_INFO_new()) == NULL) goto err; 423 if (!PKCS7_SIGNER_INFO_set(si,x509,pkey,dgst)) goto err; 424 if (!PKCS7_add_signer(p7,si)) goto err; 425 return(si); 426err: 427 return(NULL); 428 } 429 430int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) 431 { 432 if (PKCS7_type_is_digest(p7)) 433 { 434 if(!(p7->d.digest->md->parameter = ASN1_TYPE_new())) 435 { 436 PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,ERR_R_MALLOC_FAILURE); 437 return 0; 438 } 439 p7->d.digest->md->parameter->type = V_ASN1_NULL; 440 p7->d.digest->md->algorithm = OBJ_nid2obj(EVP_MD_nid(md)); 441 return 1; 442 } 443 444 PKCS7err(PKCS7_F_PKCS7_SET_DIGEST,PKCS7_R_WRONG_CONTENT_TYPE); 445 return 1; 446 } 447 448STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7) 449 { 450 if (PKCS7_type_is_signed(p7)) 451 { 452 return(p7->d.sign->signer_info); 453 } 454 else if (PKCS7_type_is_signedAndEnveloped(p7)) 455 { 456 return(p7->d.signed_and_enveloped->signer_info); 457 } 458 else 459 return(NULL); 460 } 461 462PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509) 463 { 464 PKCS7_RECIP_INFO *ri; 465 466 if ((ri=PKCS7_RECIP_INFO_new()) == NULL) goto err; 467 if (!PKCS7_RECIP_INFO_set(ri,x509)) goto err; 468 if (!PKCS7_add_recipient_info(p7,ri)) goto err; 469 return(ri); 470err: 471 return(NULL); 472 } 473 474int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri) 475 { 476 int i; 477 STACK_OF(PKCS7_RECIP_INFO) *sk; 478 479 i=OBJ_obj2nid(p7->type); 480 switch (i) 481 { 482 case NID_pkcs7_signedAndEnveloped: 483 sk= p7->d.signed_and_enveloped->recipientinfo; 484 break; 485 case NID_pkcs7_enveloped: 486 sk= p7->d.enveloped->recipientinfo; 487 break; 488 default: 489 PKCS7err(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO,PKCS7_R_WRONG_CONTENT_TYPE); 490 return(0); 491 } 492 493 sk_PKCS7_RECIP_INFO_push(sk,ri); 494 return(1); 495 } 496 497int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509) 498 { 499 if (!ASN1_INTEGER_set(p7i->version,0)) 500 return 0; 501 if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, 502 X509_get_issuer_name(x509))) 503 return 0; 504 505 M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); 506 if (!(p7i->issuer_and_serial->serial= 507 M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) 508 return 0; 509 510 X509_ALGOR_free(p7i->key_enc_algor); 511 if (!(p7i->key_enc_algor= X509_ALGOR_dup(x509->cert_info->key->algor))) 512 return 0; 513 514 CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); 515 p7i->cert=x509; 516 517 return(1); 518 } 519 520X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si) 521 { 522 if (PKCS7_type_is_signed(p7)) 523 return(X509_find_by_issuer_and_serial(p7->d.sign->cert, 524 si->issuer_and_serial->issuer, 525 si->issuer_and_serial->serial)); 526 else 527 return(NULL); 528 } 529 530int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher) 531 { 532 int i; 533 ASN1_OBJECT *objtmp; 534 PKCS7_ENC_CONTENT *ec; 535 536 i=OBJ_obj2nid(p7->type); 537 switch (i) 538 { 539 case NID_pkcs7_signedAndEnveloped: 540 ec=p7->d.signed_and_enveloped->enc_data; 541 break; 542 case NID_pkcs7_enveloped: 543 ec=p7->d.enveloped->enc_data; 544 break; 545 default: 546 PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_WRONG_CONTENT_TYPE); 547 return(0); 548 } 549 550 /* Check cipher OID exists and has data in it*/ 551 i = EVP_CIPHER_type(cipher); 552 if(i == NID_undef) { 553 PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); 554 return(0); 555 } 556 objtmp = OBJ_nid2obj(i); 557 558 ec->cipher = cipher; 559 return 1; 560 } 561 562