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 case NID_pkcs7_data: 142 case NID_pkcs7_enveloped: 143 case NID_pkcs7_signedAndEnveloped: 144 case NID_pkcs7_encrypted: 145 default: 146 PKCS7err(PKCS7_F_PKCS7_SET_CONTENT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); 147 goto err; 148 } 149 return(1); 150err: 151 return(0); 152 } 153 154int PKCS7_set_type(PKCS7 *p7, int type) 155 { 156 ASN1_OBJECT *obj; 157 158 /*PKCS7_content_free(p7);*/ 159 obj=OBJ_nid2obj(type); /* will not fail */ 160 161 switch (type) 162 { 163 case NID_pkcs7_signed: 164 p7->type=obj; 165 if ((p7->d.sign=PKCS7_SIGNED_new()) == NULL) 166 goto err; 167 if (!ASN1_INTEGER_set(p7->d.sign->version,1)) 168 { 169 PKCS7_SIGNED_free(p7->d.sign); 170 p7->d.sign=NULL; 171 goto err; 172 } 173 break; 174 case NID_pkcs7_data: 175 p7->type=obj; 176 if ((p7->d.data=M_ASN1_OCTET_STRING_new()) == NULL) 177 goto err; 178 break; 179 case NID_pkcs7_signedAndEnveloped: 180 p7->type=obj; 181 if ((p7->d.signed_and_enveloped=PKCS7_SIGN_ENVELOPE_new()) 182 == NULL) goto err; 183 ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1); 184 if (!ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1)) 185 goto err; 186 break; 187 p7->d.signed_and_enveloped->enc_data->content_type 188 = OBJ_nid2obj(NID_pkcs7_data); 189 break; 190 case NID_pkcs7_enveloped: 191 p7->type=obj; 192 if ((p7->d.enveloped=PKCS7_ENVELOPE_new()) 193 == NULL) goto err; 194 if (!ASN1_INTEGER_set(p7->d.enveloped->version,0)) 195 goto err; 196 p7->d.enveloped->enc_data->content_type 197 = OBJ_nid2obj(NID_pkcs7_data); 198 break; 199 case NID_pkcs7_encrypted: 200 p7->type=obj; 201 if ((p7->d.encrypted=PKCS7_ENCRYPT_new()) 202 == NULL) goto err; 203 if (!ASN1_INTEGER_set(p7->d.encrypted->version,0)) 204 goto err; 205 p7->d.encrypted->enc_data->content_type 206 = OBJ_nid2obj(NID_pkcs7_data); 207 break; 208 209 case NID_pkcs7_digest: 210 default: 211 PKCS7err(PKCS7_F_PKCS7_SET_TYPE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); 212 goto err; 213 } 214 return(1); 215err: 216 return(0); 217 } 218 219int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *psi) 220 { 221 int i,j,nid; 222 X509_ALGOR *alg; 223 STACK_OF(PKCS7_SIGNER_INFO) *signer_sk; 224 STACK_OF(X509_ALGOR) *md_sk; 225 226 i=OBJ_obj2nid(p7->type); 227 switch (i) 228 { 229 case NID_pkcs7_signed: 230 signer_sk= p7->d.sign->signer_info; 231 md_sk= p7->d.sign->md_algs; 232 break; 233 case NID_pkcs7_signedAndEnveloped: 234 signer_sk= p7->d.signed_and_enveloped->signer_info; 235 md_sk= p7->d.signed_and_enveloped->md_algs; 236 break; 237 default: 238 PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,PKCS7_R_WRONG_CONTENT_TYPE); 239 return(0); 240 } 241 242 nid=OBJ_obj2nid(psi->digest_alg->algorithm); 243 244 /* If the digest is not currently listed, add it */ 245 j=0; 246 for (i=0; i<sk_X509_ALGOR_num(md_sk); i++) 247 { 248 alg=sk_X509_ALGOR_value(md_sk,i); 249 if (OBJ_obj2nid(alg->algorithm) == nid) 250 { 251 j=1; 252 break; 253 } 254 } 255 if (!j) /* we need to add another algorithm */ 256 { 257 if(!(alg=X509_ALGOR_new()) 258 || !(alg->parameter = ASN1_TYPE_new())) { 259 PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,ERR_R_MALLOC_FAILURE); 260 return(0); 261 } 262 alg->algorithm=OBJ_nid2obj(nid); 263 alg->parameter->type = V_ASN1_NULL; 264 sk_X509_ALGOR_push(md_sk,alg); 265 } 266 267 sk_PKCS7_SIGNER_INFO_push(signer_sk,psi); 268 return(1); 269 } 270 271int PKCS7_add_certificate(PKCS7 *p7, X509 *x509) 272 { 273 int i; 274 STACK_OF(X509) **sk; 275 276 i=OBJ_obj2nid(p7->type); 277 switch (i) 278 { 279 case NID_pkcs7_signed: 280 sk= &(p7->d.sign->cert); 281 break; 282 case NID_pkcs7_signedAndEnveloped: 283 sk= &(p7->d.signed_and_enveloped->cert); 284 break; 285 default: 286 PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,PKCS7_R_WRONG_CONTENT_TYPE); 287 return(0); 288 } 289 290 if (*sk == NULL) 291 *sk=sk_X509_new_null(); 292 CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); 293 sk_X509_push(*sk,x509); 294 return(1); 295 } 296 297int PKCS7_add_crl(PKCS7 *p7, X509_CRL *crl) 298 { 299 int i; 300 STACK_OF(X509_CRL) **sk; 301 302 i=OBJ_obj2nid(p7->type); 303 switch (i) 304 { 305 case NID_pkcs7_signed: 306 sk= &(p7->d.sign->crl); 307 break; 308 case NID_pkcs7_signedAndEnveloped: 309 sk= &(p7->d.signed_and_enveloped->crl); 310 break; 311 default: 312 PKCS7err(PKCS7_F_PKCS7_ADD_CRL,PKCS7_R_WRONG_CONTENT_TYPE); 313 return(0); 314 } 315 316 if (*sk == NULL) 317 *sk=sk_X509_CRL_new_null(); 318 319 CRYPTO_add(&crl->references,1,CRYPTO_LOCK_X509_CRL); 320 sk_X509_CRL_push(*sk,crl); 321 return(1); 322 } 323 324int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, 325 const EVP_MD *dgst) 326 { 327 char is_dsa; 328 if (pkey->type == EVP_PKEY_DSA) is_dsa = 1; 329 else is_dsa = 0; 330 /* We now need to add another PKCS7_SIGNER_INFO entry */ 331 if (!ASN1_INTEGER_set(p7i->version,1)) 332 goto err; 333 if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, 334 X509_get_issuer_name(x509))) 335 goto err; 336 337 /* because ASN1_INTEGER_set is used to set a 'long' we will do 338 * things the ugly way. */ 339 M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); 340 if (!(p7i->issuer_and_serial->serial= 341 M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) 342 goto err; 343 344 /* lets keep the pkey around for a while */ 345 CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY); 346 p7i->pkey=pkey; 347 348 /* Set the algorithms */ 349 if (is_dsa) p7i->digest_alg->algorithm=OBJ_nid2obj(NID_sha1); 350 else 351 p7i->digest_alg->algorithm=OBJ_nid2obj(EVP_MD_type(dgst)); 352 353 if (p7i->digest_alg->parameter != NULL) 354 ASN1_TYPE_free(p7i->digest_alg->parameter); 355 if ((p7i->digest_alg->parameter=ASN1_TYPE_new()) == NULL) 356 goto err; 357 p7i->digest_alg->parameter->type=V_ASN1_NULL; 358 359 p7i->digest_enc_alg->algorithm=OBJ_nid2obj(EVP_PKEY_type(pkey->type)); 360 361 if (p7i->digest_enc_alg->parameter != NULL) 362 ASN1_TYPE_free(p7i->digest_enc_alg->parameter); 363 if(is_dsa) p7i->digest_enc_alg->parameter = NULL; 364 else { 365 if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new())) 366 goto err; 367 p7i->digest_enc_alg->parameter->type=V_ASN1_NULL; 368 } 369 370 return(1); 371err: 372 return(0); 373 } 374 375PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey, 376 const EVP_MD *dgst) 377 { 378 PKCS7_SIGNER_INFO *si; 379 380 if ((si=PKCS7_SIGNER_INFO_new()) == NULL) goto err; 381 if (!PKCS7_SIGNER_INFO_set(si,x509,pkey,dgst)) goto err; 382 if (!PKCS7_add_signer(p7,si)) goto err; 383 return(si); 384err: 385 return(NULL); 386 } 387 388STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7) 389 { 390 if (PKCS7_type_is_signed(p7)) 391 { 392 return(p7->d.sign->signer_info); 393 } 394 else if (PKCS7_type_is_signedAndEnveloped(p7)) 395 { 396 return(p7->d.signed_and_enveloped->signer_info); 397 } 398 else 399 return(NULL); 400 } 401 402PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509) 403 { 404 PKCS7_RECIP_INFO *ri; 405 406 if ((ri=PKCS7_RECIP_INFO_new()) == NULL) goto err; 407 if (!PKCS7_RECIP_INFO_set(ri,x509)) goto err; 408 if (!PKCS7_add_recipient_info(p7,ri)) goto err; 409 return(ri); 410err: 411 return(NULL); 412 } 413 414int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri) 415 { 416 int i; 417 STACK_OF(PKCS7_RECIP_INFO) *sk; 418 419 i=OBJ_obj2nid(p7->type); 420 switch (i) 421 { 422 case NID_pkcs7_signedAndEnveloped: 423 sk= p7->d.signed_and_enveloped->recipientinfo; 424 break; 425 case NID_pkcs7_enveloped: 426 sk= p7->d.enveloped->recipientinfo; 427 break; 428 default: 429 PKCS7err(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO,PKCS7_R_WRONG_CONTENT_TYPE); 430 return(0); 431 } 432 433 sk_PKCS7_RECIP_INFO_push(sk,ri); 434 return(1); 435 } 436 437int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509) 438 { 439 if (!ASN1_INTEGER_set(p7i->version,0)) 440 return 0; 441 if (!X509_NAME_set(&p7i->issuer_and_serial->issuer, 442 X509_get_issuer_name(x509))) 443 return 0; 444 445 M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial); 446 if (!(p7i->issuer_and_serial->serial= 447 M_ASN1_INTEGER_dup(X509_get_serialNumber(x509)))) 448 return 0; 449 450 X509_ALGOR_free(p7i->key_enc_algor); 451 if (!(p7i->key_enc_algor= X509_ALGOR_dup(x509->cert_info->key->algor))) 452 return 0; 453 454 CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); 455 p7i->cert=x509; 456 457 return(1); 458 } 459 460X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si) 461 { 462 if (PKCS7_type_is_signed(p7)) 463 return(X509_find_by_issuer_and_serial(p7->d.sign->cert, 464 si->issuer_and_serial->issuer, 465 si->issuer_and_serial->serial)); 466 else 467 return(NULL); 468 } 469 470int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher) 471 { 472 int i; 473 ASN1_OBJECT *objtmp; 474 PKCS7_ENC_CONTENT *ec; 475 476 i=OBJ_obj2nid(p7->type); 477 switch (i) 478 { 479 case NID_pkcs7_signedAndEnveloped: 480 ec=p7->d.signed_and_enveloped->enc_data; 481 break; 482 case NID_pkcs7_enveloped: 483 ec=p7->d.enveloped->enc_data; 484 break; 485 default: 486 PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_WRONG_CONTENT_TYPE); 487 return(0); 488 } 489 490 /* Check cipher OID exists and has data in it*/ 491 i = EVP_CIPHER_type(cipher); 492 if(i == NID_undef) { 493 PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); 494 return(0); 495 } 496 objtmp = OBJ_nid2obj(i); 497 498 ec->cipher = cipher; 499 return 1; 500 } 501 502