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