Adapt all EVP_CIPHER users for it becoming opaque
[openssl.git] / crypto / pem / pem_info.c
index fec18a4c2ed6bc012ba1a980d9e217d242eed4a7..67cd99d13f07580bd2d9fab1e910866942fb3903 100644 (file)
@@ -5,21 +5,21 @@
  * This package is an SSL implementation written
  * by Eric Young (eay@cryptsoft.com).
  * The implementation was written so as to conform with Netscapes SSL.
- * 
+ *
  * This library is free for commercial and non-commercial use as long as
  * the following conditions are aheared to.  The following conditions
  * apply to all code found in this distribution, be it the RC4, RSA,
  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
  * included with this distribution is covered by the same copyright terms
  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- * 
+ *
  * Copyright remains Eric Young's, and as such any Copyright notices in
  * the code are not to be removed.
  * If this package is used in a product, Eric Young should be given attribution
  * as the author of the parts of the library used.
  * This can be in the form of a textual message at program startup or
  * in documentation (online or textual) provided with the package.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  *     Eric Young (eay@cryptsoft.com)"
  *    The word 'cryptographic' can be left out if the rouines from the library
  *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from 
+ * 4. If you include any Windows specific code (or a derivative thereof) from
  *    the apps directory (application code) you must include an acknowledgement:
  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -49,7 +49,7 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- * 
+ *
  * The licence and distribution terms for any publically available version or
  * derivative of this code cannot be changed.  i.e. this code cannot simply be
  * copied and put under another distribution licence
  */
 
 #include <stdio.h>
-#include "cryptlib.h"
+#include "internal/cryptlib.h"
 #include <openssl/buffer.h>
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include <openssl/x509.h>
 #include <openssl/pem.h>
+#ifndef OPENSSL_NO_RSA
+# include <openssl/rsa.h>
+#endif
+#ifndef OPENSSL_NO_DSA
+# include <openssl/dsa.h>
+#endif
 
-#ifndef NO_FP_API
-STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u)
-       {
-        BIO *b;
-        STACK_OF(X509_INFO) *ret;
+#ifndef OPENSSL_NO_STDIO
+STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
+                                        pem_password_cb *cb, void *u)
+{
+    BIO *b;
+    STACK_OF(X509_INFO) *ret;
 
-        if ((b=BIO_new(BIO_s_file())) == NULL)
-               {
-               PEMerr(PEM_F_PEM_X509_INFO_READ,ERR_R_BUF_LIB);
-                return(0);
-               }
-        BIO_set_fp(b,fp,BIO_NOCLOSE);
-        ret=PEM_X509_INFO_read_bio(b,sk,cb,u);
-        BIO_free(b);
-        return(ret);
-       }
+    if ((b = BIO_new(BIO_s_file())) == NULL) {
+        PEMerr(PEM_F_PEM_X509_INFO_READ, ERR_R_BUF_LIB);
+        return (0);
+    }
+    BIO_set_fp(b, fp, BIO_NOCLOSE);
+    ret = PEM_X509_INFO_read_bio(b, sk, cb, u);
+    BIO_free(b);
+    return (ret);
+}
 #endif
 
-STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u)
-       {
-       X509_INFO *xi=NULL;
-       char *name=NULL,*header=NULL,**pp;
-       unsigned char *data=NULL,*p;
-       long len,error=0;
-       int ok=0;
-       STACK_OF(X509_INFO) *ret=NULL;
-       unsigned int i,raw;
-       char *(*d2i)();
+STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk,
+                                            pem_password_cb *cb, void *u)
+{
+    X509_INFO *xi = NULL;
+    char *name = NULL, *header = NULL;
+    void *pp;
+    unsigned char *data = NULL;
+    const unsigned char *p;
+    long len, error = 0;
+    int ok = 0;
+    STACK_OF(X509_INFO) *ret = NULL;
+    unsigned int i, raw, ptype;
+    d2i_of_void *d2i = 0;
+
+    if (sk == NULL) {
+        if ((ret = sk_X509_INFO_new_null()) == NULL) {
+            PEMerr(PEM_F_PEM_X509_INFO_READ_BIO, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+    } else
+        ret = sk;
+
+    if ((xi = X509_INFO_new()) == NULL)
+        goto err;
+    for (;;) {
+        raw = 0;
+        ptype = 0;
+        i = PEM_read_bio(bp, &name, &header, &data, &len);
+        if (i == 0) {
+            error = ERR_GET_REASON(ERR_peek_last_error());
+            if (error == PEM_R_NO_START_LINE) {
+                ERR_clear_error();
+                break;
+            }
+            goto err;
+        }
+ start:
+        if ((strcmp(name, PEM_STRING_X509) == 0) ||
+            (strcmp(name, PEM_STRING_X509_OLD) == 0)) {
+            d2i = (D2I_OF(void)) d2i_X509;
+            if (xi->x509 != NULL) {
+                if (!sk_X509_INFO_push(ret, xi))
+                    goto err;
+                if ((xi = X509_INFO_new()) == NULL)
+                    goto err;
+                goto start;
+            }
+            pp = &(xi->x509);
+        } else if ((strcmp(name, PEM_STRING_X509_TRUSTED) == 0)) {
+            d2i = (D2I_OF(void)) d2i_X509_AUX;
+            if (xi->x509 != NULL) {
+                if (!sk_X509_INFO_push(ret, xi))
+                    goto err;
+                if ((xi = X509_INFO_new()) == NULL)
+                    goto err;
+                goto start;
+            }
+            pp = &(xi->x509);
+        } else if (strcmp(name, PEM_STRING_X509_CRL) == 0) {
+            d2i = (D2I_OF(void)) d2i_X509_CRL;
+            if (xi->crl != NULL) {
+                if (!sk_X509_INFO_push(ret, xi))
+                    goto err;
+                if ((xi = X509_INFO_new()) == NULL)
+                    goto err;
+                goto start;
+            }
+            pp = &(xi->crl);
+        } else
+#ifndef OPENSSL_NO_RSA
+        if (strcmp(name, PEM_STRING_RSA) == 0) {
+            d2i = (D2I_OF(void)) d2i_RSAPrivateKey;
+            if (xi->x_pkey != NULL) {
+                if (!sk_X509_INFO_push(ret, xi))
+                    goto err;
+                if ((xi = X509_INFO_new()) == NULL)
+                    goto err;
+                goto start;
+            }
 
-       if (sk == NULL)
-               {
-               if ((ret=sk_X509_INFO_new_null()) == NULL)
-                       {
-                       PEMerr(PEM_F_PEM_X509_INFO_READ_BIO,ERR_R_MALLOC_FAILURE);
-                       goto err;
-                       }
-               }
-       else
-               ret=sk;
+            xi->enc_data = NULL;
+            xi->enc_len = 0;
 
-       if ((xi=X509_INFO_new()) == NULL) goto err;
-       for (;;)
-               {
-               raw=0;
-               i=PEM_read_bio(bp,&name,&header,&data,&len);
-               if (i == 0)
-                       {
-                       error=ERR_GET_REASON(ERR_peek_error());
-                       if (error == PEM_R_NO_START_LINE)
-                               {
-                               ERR_clear_error();
-                               break;
-                               }
-                       goto err;
-                       }
-start:
-               if (    (strcmp(name,PEM_STRING_X509) == 0) ||
-                       (strcmp(name,PEM_STRING_X509_OLD) == 0))
-                       {
-                       d2i=(char *(*)())d2i_X509;
-                       if (xi->x509 != NULL)
-                               {
-                               if (!sk_X509_INFO_push(ret,xi)) goto err;
-                               if ((xi=X509_INFO_new()) == NULL) goto err;
-                               goto start;
-                               }
-                       pp=(char **)&(xi->x509);
-                       }
-               else if (strcmp(name,PEM_STRING_X509_CRL) == 0)
-                       {
-                       d2i=(char *(*)())d2i_X509_CRL;
-                       if (xi->crl != NULL)
-                               {
-                               if (!sk_X509_INFO_push(ret,xi)) goto err;
-                               if ((xi=X509_INFO_new()) == NULL) goto err;
-                               goto start;
-                               }
-                       pp=(char **)&(xi->crl);
-                       }
-               else
-#ifndef NO_RSA
-                       if (strcmp(name,PEM_STRING_RSA) == 0)
-                       {
-                       d2i=(char *(*)())d2i_RSAPrivateKey;
-                       if (xi->x_pkey != NULL) 
-                               {
-                               if (!sk_X509_INFO_push(ret,xi)) goto err;
-                               if ((xi=X509_INFO_new()) == NULL) goto err;
-                               goto start;
-                               }
+            xi->x_pkey = X509_PKEY_new();
+            if (xi->x_pkey == NULL)
+                goto err;
+            ptype = EVP_PKEY_RSA;
+            pp = &xi->x_pkey->dec_pkey;
+            if ((int)strlen(header) > 10) /* assume encrypted */
+                raw = 1;
+        } else
+#endif
+#ifndef OPENSSL_NO_DSA
+        if (strcmp(name, PEM_STRING_DSA) == 0) {
+            d2i = (D2I_OF(void)) d2i_DSAPrivateKey;
+            if (xi->x_pkey != NULL) {
+                if (!sk_X509_INFO_push(ret, xi))
+                    goto err;
+                if ((xi = X509_INFO_new()) == NULL)
+                    goto err;
+                goto start;
+            }
 
-                       xi->enc_data=NULL;
-                       xi->enc_len=0;
+            xi->enc_data = NULL;
+            xi->enc_len = 0;
 
-                       xi->x_pkey=X509_PKEY_new();
-                       if ((xi->x_pkey->dec_pkey=EVP_PKEY_new()) == NULL)
-                               goto err;
-                       xi->x_pkey->dec_pkey->type=EVP_PKEY_RSA;
-                       pp=(char **)&(xi->x_pkey->dec_pkey->pkey.rsa);
-                       if ((int)strlen(header) > 10) /* assume encrypted */
-                               raw=1;
-                       }
-               else
+            xi->x_pkey = X509_PKEY_new();
+            if (xi->x_pkey == NULL)
+                goto err;
+            ptype = EVP_PKEY_DSA;
+            pp = &xi->x_pkey->dec_pkey;
+            if ((int)strlen(header) > 10) /* assume encrypted */
+                raw = 1;
+        } else
 #endif
-#ifndef NO_DSA
-                       if (strcmp(name,PEM_STRING_DSA) == 0)
-                       {
-                       d2i=(char *(*)())d2i_DSAPrivateKey;
-                       if (xi->x_pkey != NULL) 
-                               {
-                               if (!sk_X509_INFO_push(ret,xi)) goto err;
-                               if ((xi=X509_INFO_new()) == NULL) goto err;
-                               goto start;
-                               }
+#ifndef OPENSSL_NO_EC
+        if (strcmp(name, PEM_STRING_ECPRIVATEKEY) == 0) {
+            d2i = (D2I_OF(void)) d2i_ECPrivateKey;
+            if (xi->x_pkey != NULL) {
+                if (!sk_X509_INFO_push(ret, xi))
+                    goto err;
+                if ((xi = X509_INFO_new()) == NULL)
+                    goto err;
+                goto start;
+            }
 
-                       xi->enc_data=NULL;
-                       xi->enc_len=0;
+            xi->enc_data = NULL;
+            xi->enc_len = 0;
 
-                       xi->x_pkey=X509_PKEY_new();
-                       if ((xi->x_pkey->dec_pkey=EVP_PKEY_new()) == NULL)
-                               goto err;
-                       xi->x_pkey->dec_pkey->type=EVP_PKEY_DSA;
-                       pp=(char **)&(xi->x_pkey->dec_pkey->pkey.dsa);
-                       if ((int)strlen(header) > 10) /* assume encrypted */
-                               raw=1;
-                       }
-               else
+            xi->x_pkey = X509_PKEY_new();
+            if (xi->x_pkey == NULL)
+                goto err;
+            ptype = EVP_PKEY_EC;
+            pp = &xi->x_pkey->dec_pkey;
+            if ((int)strlen(header) > 10) /* assume encrypted */
+                raw = 1;
+        } else
 #endif
-                       {
-                       d2i=NULL;
-                       pp=NULL;
-                       }
+        {
+            d2i = NULL;
+            pp = NULL;
+        }
 
-               if (d2i != NULL)
-                       {
-                       if (!raw)
-                               {
-                               EVP_CIPHER_INFO cipher;
+        if (d2i != NULL) {
+            if (!raw) {
+                EVP_CIPHER_INFO cipher;
 
-                               if (!PEM_get_EVP_CIPHER_INFO(header,&cipher))
-                                       goto err;
-                               if (!PEM_do_header(&cipher,data,&len,cb,u))
-                                       goto err;
-                               p=data;
-                               if (d2i(pp,&p,len) == NULL)
-                                       {
-                                       PEMerr(PEM_F_PEM_X509_INFO_READ_BIO,ERR_R_ASN1_LIB);
-                                       goto err;
-                                       }
-                               }
-                       else
-                               { /* encrypted RSA data */
-                               if (!PEM_get_EVP_CIPHER_INFO(header,
-                                       &xi->enc_cipher)) goto err;
-                               xi->enc_data=(char *)data;
-                               xi->enc_len=(int)len;
-                               data=NULL;
-                               }
-                       }
-               else    {
-                       /* unknown */
-                       }
-               if (name != NULL) Free(name);
-               if (header != NULL) Free(header);
-               if (data != NULL) Free(data);
-               name=NULL;
-               header=NULL;
-               data=NULL;
-               }
+                if (!PEM_get_EVP_CIPHER_INFO(header, &cipher))
+                    goto err;
+                if (!PEM_do_header(&cipher, data, &len, cb, u))
+                    goto err;
+                p = data;
+                if (ptype) {
+                    if (!d2i_PrivateKey(ptype, pp, &p, len)) {
+                        PEMerr(PEM_F_PEM_X509_INFO_READ_BIO, ERR_R_ASN1_LIB);
+                        goto err;
+                    }
+                } else if (d2i(pp, &p, len) == NULL) {
+                    PEMerr(PEM_F_PEM_X509_INFO_READ_BIO, ERR_R_ASN1_LIB);
+                    goto err;
+                }
+            } else {            /* encrypted RSA data */
+                if (!PEM_get_EVP_CIPHER_INFO(header, &xi->enc_cipher))
+                    goto err;
+                xi->enc_data = (char *)data;
+                xi->enc_len = (int)len;
+                data = NULL;
+            }
+        } else {
+            /* unknown */
+        }
+        OPENSSL_free(name);
+        name = NULL;
+        OPENSSL_free(header);
+        header = NULL;
+        OPENSSL_free(data);
+        data = NULL;
+    }
 
-       /* if the last one hasn't been pushed yet and there is anything
-        * in it then add it to the stack ... 
-        */
-       if ((xi->x509 != NULL) || (xi->crl != NULL) ||
-               (xi->x_pkey != NULL) || (xi->enc_data != NULL))
-               {
-               if (!sk_X509_INFO_push(ret,xi)) goto err;
-               xi=NULL;
-               }
-       ok=1;
-err:
-       if (xi != NULL) X509_INFO_free(xi);
-       if (!ok)
-               {
-               for (i=0; ((int)i)<sk_X509_INFO_num(ret); i++)
-                       {
-                       xi=sk_X509_INFO_value(ret,i);
-                       X509_INFO_free(xi);
-                       }
-               if (ret != sk) sk_X509_INFO_free(ret);
-               ret=NULL;
-               }
-               
-       if (name != NULL) Free(name);
-       if (header != NULL) Free(header);
-       if (data != NULL) Free(data);
-       return(ret);
-       }
+    /*
+     * if the last one hasn't been pushed yet and there is anything in it
+     * then add it to the stack ...
+     */
+    if ((xi->x509 != NULL) || (xi->crl != NULL) ||
+        (xi->x_pkey != NULL) || (xi->enc_data != NULL)) {
+        if (!sk_X509_INFO_push(ret, xi))
+            goto err;
+        xi = NULL;
+    }
+    ok = 1;
+ err:
+    X509_INFO_free(xi);
+    if (!ok) {
+        for (i = 0; ((int)i) < sk_X509_INFO_num(ret); i++) {
+            xi = sk_X509_INFO_value(ret, i);
+            X509_INFO_free(xi);
+        }
+        if (ret != sk)
+            sk_X509_INFO_free(ret);
+        ret = NULL;
+    }
 
+    OPENSSL_free(name);
+    OPENSSL_free(header);
+    OPENSSL_free(data);
+    return (ret);
+}
 
 /* A TJH addition */
 int PEM_X509_INFO_write_bio(BIO *bp, X509_INFO *xi, EVP_CIPHER *enc,
-            unsigned char *kstr, int klen, pem_password_cb *cb, void *u)
-       {
-       EVP_CIPHER_CTX ctx;
-       int i,ret=0;
-       unsigned char *data=NULL;
-       const char *objstr=NULL;
-       char buf[PEM_BUFSIZE];
-       unsigned char *iv=NULL;
-       
-       if (enc != NULL)
-               {
-               objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc));
-               if (objstr == NULL)
-                       {
-                       PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO,PEM_R_UNSUPPORTED_CIPHER);
-                       goto err;
-                       }
-               }
+                            unsigned char *kstr, int klen,
+                            pem_password_cb *cb, void *u)
+{
+    int i, ret = 0;
+    unsigned char *data = NULL;
+    const char *objstr = NULL;
+    char buf[PEM_BUFSIZE];
+    unsigned char *iv = NULL;
+
+    if (enc != NULL) {
+        objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc));
+        if (objstr == NULL) {
+            PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO, PEM_R_UNSUPPORTED_CIPHER);
+            goto err;
+        }
+    }
+
+    /*
+     * now for the fun part ... if we have a private key then we have to be
+     * able to handle a not-yet-decrypted key being written out correctly ...
+     * if it is decrypted or it is non-encrypted then we use the base code
+     */
+    if (xi->x_pkey != NULL) {
+        if ((xi->enc_data != NULL) && (xi->enc_len > 0)) {
+            if (enc == NULL) {
+                PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO, PEM_R_CIPHER_IS_NULL);
+                goto err;
+            }
 
-       /* now for the fun part ... if we have a private key then 
-        * we have to be able to handle a not-yet-decrypted key
-        * being written out correctly ... if it is decrypted or
-        * it is non-encrypted then we use the base code
-        */
-       if (xi->x_pkey!=NULL)
-               {
-               if ( (xi->enc_data!=NULL) && (xi->enc_len>0) )
-                       {
-                       /* copy from wierdo names into more normal things */
-                       iv=xi->enc_cipher.iv;
-                       data=(unsigned char *)xi->enc_data;
-                       i=xi->enc_len;
+            /* copy from weirdo names into more normal things */
+            iv = xi->enc_cipher.iv;
+            data = (unsigned char *)xi->enc_data;
+            i = xi->enc_len;
 
-                       /* we take the encryption data from the
-                        * internal stuff rather than what the
-                        * user has passed us ... as we have to 
-                        * match exactly for some strange reason
-                        */
-                       objstr=OBJ_nid2sn(
-                               EVP_CIPHER_nid(xi->enc_cipher.cipher));
-                       if (objstr == NULL)
-                               {
-                               PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO,PEM_R_UNSUPPORTED_CIPHER);
-                               goto err;
-                               }
+            /*
+             * we take the encryption data from the internal stuff rather
+             * than what the user has passed us ... as we have to match
+             * exactly for some strange reason
+             */
+            objstr = OBJ_nid2sn(EVP_CIPHER_nid(xi->enc_cipher.cipher));
+            if (objstr == NULL) {
+                PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO,
+                       PEM_R_UNSUPPORTED_CIPHER);
+                goto err;
+            }
 
-                       /* create the right magic header stuff */
-                       buf[0]='\0';
-                       PEM_proc_type(buf,PEM_TYPE_ENCRYPTED);
-                       PEM_dek_info(buf,objstr,8,(char *)iv);
+            /* create the right magic header stuff */
+            OPENSSL_assert(strlen(objstr) + 23
+                           + 2 * EVP_CIPHER_iv_length(enc) + 13 <=
+                           sizeof buf);
+            buf[0] = '\0';
+            PEM_proc_type(buf, PEM_TYPE_ENCRYPTED);
+            PEM_dek_info(buf, objstr, EVP_CIPHER_iv_length(enc),
+                         (char *)iv);
 
-                       /* use the normal code to write things out */
-                       i=PEM_write_bio(bp,PEM_STRING_RSA,buf,data,i);
-                       if (i <= 0) goto err;
-                       }
-               else
-                       {
-                       /* Add DSA/DH */
-#ifndef NO_RSA
-                       /* normal optionally encrypted stuff */
-                       if (PEM_write_bio_RSAPrivateKey(bp,
-                               xi->x_pkey->dec_pkey->pkey.rsa,
-                               enc,kstr,klen,cb,u)<=0)
-                               goto err;
+            /* use the normal code to write things out */
+            i = PEM_write_bio(bp, PEM_STRING_RSA, buf, data, i);
+            if (i <= 0)
+                goto err;
+        } else {
+            /* Add DSA/DH */
+#ifndef OPENSSL_NO_RSA
+            /* normal optionally encrypted stuff */
+            if (PEM_write_bio_RSAPrivateKey(bp,
+                                            xi->x_pkey->dec_pkey->pkey.rsa,
+                                            enc, kstr, klen, cb, u) <= 0)
+                goto err;
 #endif
-                       }
-               }
+        }
+    }
 
-       /* if we have a certificate then write it out now */
-       if ((xi->x509 != NULL) || (PEM_write_bio_X509(bp,xi->x509) <= 0))
-               goto err;
+    /* if we have a certificate then write it out now */
+    if ((xi->x509 != NULL) && (PEM_write_bio_X509(bp, xi->x509) <= 0))
+        goto err;
 
-       /* we are ignoring anything else that is loaded into the X509_INFO
-        * structure for the moment ... as I don't need it so I'm not
-        * coding it here and Eric can do it when this makes it into the
-        * base library --tjh
-        */
+    /*
+     * we are ignoring anything else that is loaded into the X509_INFO
+     * structure for the moment ... as I don't need it so I'm not coding it
+     * here and Eric can do it when this makes it into the base library --tjh
+     */
 
-       ret=1;
+    ret = 1;
 
-err:
-       memset((char *)&ctx,0,sizeof(ctx));
-       memset(buf,0,PEM_BUFSIZE);
-       return(ret);
-       }
+ err:
+    OPENSSL_cleanse(buf, PEM_BUFSIZE);
+    return (ret);
+}