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