1 /* crypto/pem/pem_info.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/buffer.h> 62 #include <openssl/objects.h> 63 #include <openssl/evp.h> 64 #include <openssl/x509.h> 65 #include <openssl/pem.h> 66 #ifndef OPENSSL_NO_RSA 67 #include <openssl/rsa.h> 68 #endif 69 #ifndef OPENSSL_NO_DSA 70 #include <openssl/dsa.h> 71 #endif 72 73 #ifndef OPENSSL_NO_FP_API 74 STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u) 75 { 76 BIO *b; 77 STACK_OF(X509_INFO) *ret; 78 79 if ((b=BIO_new(BIO_s_file())) == NULL) 80 { 81 PEMerr(PEM_F_PEM_X509_INFO_READ,ERR_R_BUF_LIB); 82 return(0); 83 } 84 BIO_set_fp(b,fp,BIO_NOCLOSE); 85 ret=PEM_X509_INFO_read_bio(b,sk,cb,u); 86 BIO_free(b); 87 return(ret); 88 } 89 #endif 90 91 STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u) 92 { 93 X509_INFO *xi=NULL; 94 char *name=NULL,*header=NULL; 95 void *pp; 96 unsigned char *data=NULL; 97 const unsigned char *p; 98 long len,error=0; 99 int ok=0; 100 STACK_OF(X509_INFO) *ret=NULL; 101 unsigned int i,raw,ptype; 102 d2i_of_void *d2i = 0; 103 104 if (sk == NULL) 105 { 106 if ((ret=sk_X509_INFO_new_null()) == NULL) 107 { 108 PEMerr(PEM_F_PEM_X509_INFO_READ_BIO,ERR_R_MALLOC_FAILURE); 109 goto err; 110 } 111 } 112 else 113 ret=sk; 114 115 if ((xi=X509_INFO_new()) == NULL) goto err; 116 for (;;) 117 { 118 raw=0; 119 ptype = 0; 120 i=PEM_read_bio(bp,&name,&header,&data,&len); 121 if (i == 0) 122 { 123 error=ERR_GET_REASON(ERR_peek_last_error()); 124 if (error == PEM_R_NO_START_LINE) 125 { 126 ERR_clear_error(); 127 break; 128 } 129 goto err; 130 } 131 start: 132 if ( (strcmp(name,PEM_STRING_X509) == 0) || 133 (strcmp(name,PEM_STRING_X509_OLD) == 0)) 134 { 135 d2i=(D2I_OF(void))d2i_X509; 136 if (xi->x509 != NULL) 137 { 138 if (!sk_X509_INFO_push(ret,xi)) goto err; 139 if ((xi=X509_INFO_new()) == NULL) goto err; 140 goto start; 141 } 142 pp=&(xi->x509); 143 } 144 else if ((strcmp(name,PEM_STRING_X509_TRUSTED) == 0)) 145 { 146 d2i=(D2I_OF(void))d2i_X509_AUX; 147 if (xi->x509 != NULL) 148 { 149 if (!sk_X509_INFO_push(ret,xi)) goto err; 150 if ((xi=X509_INFO_new()) == NULL) goto err; 151 goto start; 152 } 153 pp=&(xi->x509); 154 } 155 else if (strcmp(name,PEM_STRING_X509_CRL) == 0) 156 { 157 d2i=(D2I_OF(void))d2i_X509_CRL; 158 if (xi->crl != NULL) 159 { 160 if (!sk_X509_INFO_push(ret,xi)) goto err; 161 if ((xi=X509_INFO_new()) == NULL) goto err; 162 goto start; 163 } 164 pp=&(xi->crl); 165 } 166 else 167 #ifndef OPENSSL_NO_RSA 168 if (strcmp(name,PEM_STRING_RSA) == 0) 169 { 170 d2i=(D2I_OF(void))d2i_RSAPrivateKey; 171 if (xi->x_pkey != NULL) 172 { 173 if (!sk_X509_INFO_push(ret,xi)) goto err; 174 if ((xi=X509_INFO_new()) == NULL) goto err; 175 goto start; 176 } 177 178 xi->enc_data=NULL; 179 xi->enc_len=0; 180 181 xi->x_pkey=X509_PKEY_new(); 182 ptype=EVP_PKEY_RSA; 183 pp=&xi->x_pkey->dec_pkey; 184 if ((int)strlen(header) > 10) /* assume encrypted */ 185 raw=1; 186 } 187 else 188 #endif 189 #ifndef OPENSSL_NO_DSA 190 if (strcmp(name,PEM_STRING_DSA) == 0) 191 { 192 d2i=(D2I_OF(void))d2i_DSAPrivateKey; 193 if (xi->x_pkey != NULL) 194 { 195 if (!sk_X509_INFO_push(ret,xi)) goto err; 196 if ((xi=X509_INFO_new()) == NULL) goto err; 197 goto start; 198 } 199 200 xi->enc_data=NULL; 201 xi->enc_len=0; 202 203 xi->x_pkey=X509_PKEY_new(); 204 ptype = EVP_PKEY_DSA; 205 pp=&xi->x_pkey->dec_pkey; 206 if ((int)strlen(header) > 10) /* assume encrypted */ 207 raw=1; 208 } 209 else 210 #endif 211 #ifndef OPENSSL_NO_EC 212 if (strcmp(name,PEM_STRING_ECPRIVATEKEY) == 0) 213 { 214 d2i=(D2I_OF(void))d2i_ECPrivateKey; 215 if (xi->x_pkey != NULL) 216 { 217 if (!sk_X509_INFO_push(ret,xi)) goto err; 218 if ((xi=X509_INFO_new()) == NULL) goto err; 219 goto start; 220 } 221 222 xi->enc_data=NULL; 223 xi->enc_len=0; 224 225 xi->x_pkey=X509_PKEY_new(); 226 ptype = EVP_PKEY_EC; 227 pp=&xi->x_pkey->dec_pkey; 228 if ((int)strlen(header) > 10) /* assume encrypted */ 229 raw=1; 230 } 231 else 232 #endif 233 { 234 d2i=NULL; 235 pp=NULL; 236 } 237 238 if (d2i != NULL) 239 { 240 if (!raw) 241 { 242 EVP_CIPHER_INFO cipher; 243 244 if (!PEM_get_EVP_CIPHER_INFO(header,&cipher)) 245 goto err; 246 if (!PEM_do_header(&cipher,data,&len,cb,u)) 247 goto err; 248 p=data; 249 if (ptype) 250 { 251 if (!d2i_PrivateKey(ptype, pp, &p, len)) 252 { 253 PEMerr(PEM_F_PEM_X509_INFO_READ_BIO,ERR_R_ASN1_LIB); 254 goto err; 255 } 256 } 257 else if (d2i(pp,&p,len) == NULL) 258 { 259 PEMerr(PEM_F_PEM_X509_INFO_READ_BIO,ERR_R_ASN1_LIB); 260 goto err; 261 } 262 } 263 else 264 { /* encrypted RSA data */ 265 if (!PEM_get_EVP_CIPHER_INFO(header, 266 &xi->enc_cipher)) goto err; 267 xi->enc_data=(char *)data; 268 xi->enc_len=(int)len; 269 data=NULL; 270 } 271 } 272 else { 273 /* unknown */ 274 } 275 if (name != NULL) OPENSSL_free(name); 276 if (header != NULL) OPENSSL_free(header); 277 if (data != NULL) OPENSSL_free(data); 278 name=NULL; 279 header=NULL; 280 data=NULL; 281 } 282 283 /* if the last one hasn't been pushed yet and there is anything 284 * in it then add it to the stack ... 285 */ 286 if ((xi->x509 != NULL) || (xi->crl != NULL) || 287 (xi->x_pkey != NULL) || (xi->enc_data != NULL)) 288 { 289 if (!sk_X509_INFO_push(ret,xi)) goto err; 290 xi=NULL; 291 } 292 ok=1; 293 err: 294 if (xi != NULL) X509_INFO_free(xi); 295 if (!ok) 296 { 297 for (i=0; ((int)i)<sk_X509_INFO_num(ret); i++) 298 { 299 xi=sk_X509_INFO_value(ret,i); 300 X509_INFO_free(xi); 301 } 302 if (ret != sk) sk_X509_INFO_free(ret); 303 ret=NULL; 304 } 305 306 if (name != NULL) OPENSSL_free(name); 307 if (header != NULL) OPENSSL_free(header); 308 if (data != NULL) OPENSSL_free(data); 309 return(ret); 310 } 311 312 313 /* A TJH addition */ 314 int PEM_X509_INFO_write_bio(BIO *bp, X509_INFO *xi, EVP_CIPHER *enc, 315 unsigned char *kstr, int klen, pem_password_cb *cb, void *u) 316 { 317 EVP_CIPHER_CTX ctx; 318 int i,ret=0; 319 unsigned char *data=NULL; 320 const char *objstr=NULL; 321 char buf[PEM_BUFSIZE]; 322 unsigned char *iv=NULL; 323 324 if (enc != NULL) 325 { 326 objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc)); 327 if (objstr == NULL) 328 { 329 PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO,PEM_R_UNSUPPORTED_CIPHER); 330 goto err; 331 } 332 } 333 334 /* now for the fun part ... if we have a private key then 335 * we have to be able to handle a not-yet-decrypted key 336 * being written out correctly ... if it is decrypted or 337 * it is non-encrypted then we use the base code 338 */ 339 if (xi->x_pkey!=NULL) 340 { 341 if ( (xi->enc_data!=NULL) && (xi->enc_len>0) ) 342 { 343 if (enc == NULL) 344 { 345 PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO,PEM_R_CIPHER_IS_NULL); 346 goto err; 347 } 348 349 /* copy from weirdo names into more normal things */ 350 iv=xi->enc_cipher.iv; 351 data=(unsigned char *)xi->enc_data; 352 i=xi->enc_len; 353 354 /* we take the encryption data from the 355 * internal stuff rather than what the 356 * user has passed us ... as we have to 357 * match exactly for some strange reason 358 */ 359 objstr=OBJ_nid2sn( 360 EVP_CIPHER_nid(xi->enc_cipher.cipher)); 361 if (objstr == NULL) 362 { 363 PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO,PEM_R_UNSUPPORTED_CIPHER); 364 goto err; 365 } 366 367 /* create the right magic header stuff */ 368 OPENSSL_assert(strlen(objstr)+23+2*enc->iv_len+13 <= sizeof buf); 369 buf[0]='\0'; 370 PEM_proc_type(buf,PEM_TYPE_ENCRYPTED); 371 PEM_dek_info(buf,objstr,enc->iv_len,(char *)iv); 372 373 /* use the normal code to write things out */ 374 i=PEM_write_bio(bp,PEM_STRING_RSA,buf,data,i); 375 if (i <= 0) goto err; 376 } 377 else 378 { 379 /* Add DSA/DH */ 380 #ifndef OPENSSL_NO_RSA 381 /* normal optionally encrypted stuff */ 382 if (PEM_write_bio_RSAPrivateKey(bp, 383 xi->x_pkey->dec_pkey->pkey.rsa, 384 enc,kstr,klen,cb,u)<=0) 385 goto err; 386 #endif 387 } 388 } 389 390 /* if we have a certificate then write it out now */ 391 if ((xi->x509 != NULL) && (PEM_write_bio_X509(bp,xi->x509) <= 0)) 392 goto err; 393 394 /* we are ignoring anything else that is loaded into the X509_INFO 395 * structure for the moment ... as I don't need it so I'm not 396 * coding it here and Eric can do it when this makes it into the 397 * base library --tjh 398 */ 399 400 ret=1; 401 402 err: 403 OPENSSL_cleanse((char *)&ctx,sizeof(ctx)); 404 OPENSSL_cleanse(buf,PEM_BUFSIZE); 405 return(ret); 406 }