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