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