Home | History | Annotate | Download | only in pem
      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