In this particular error condition, the structural reference wasn't being
[openssl.git] / apps / apps.c
index 4aeabdfa38189f5e5c62cb2858269a851a9ca2cf..dc89fc0a811408441b837886ca73082d4dc271af 100644 (file)
  * copied and put under another distribution licence
  * [including the GNU Public Licence.]
  */
+/* ====================================================================
+ * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <openssl/x509v3.h>
 #include <openssl/pem.h>
 #include <openssl/pkcs12.h>
+#include <openssl/ui.h>
 #include <openssl/safestack.h>
+#include <openssl/engine.h>
 
 #ifdef OPENSSL_SYS_WINDOWS
 #define strcasecmp _stricmp
@@ -87,6 +142,8 @@ typedef struct {
        unsigned long mask;
 } NAME_EX_TBL;
 
+static UI_METHOD *ui_method = NULL;
+
 static int set_table_opts(unsigned long *flags, const char *arg, const NAME_EX_TBL *in_tbl);
 static int set_multi_opts(unsigned long *flags, const char *arg, const NAME_EX_TBL *in_tbl);
 
@@ -369,6 +426,159 @@ int dump_cert_text (BIO *out, X509 *x)
         return 0;
 }
 
+static int ui_open(UI *ui)
+       {
+       return UI_method_get_opener(UI_OpenSSL())(ui);
+       }
+static int ui_read(UI *ui, UI_STRING *uis)
+       {
+       if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD
+               && UI_get0_user_data(ui))
+               {
+               switch(UI_get_string_type(uis))
+                       {
+               case UIT_PROMPT:
+               case UIT_VERIFY:
+                       {
+                       const char *password =
+                               ((PW_CB_DATA *)UI_get0_user_data(ui))->password;
+                       if (password[0] != '\0')
+                               {
+                               UI_set_result(ui, uis, password);
+                               return 1;
+                               }
+                       }
+               default:
+                       break;
+                       }
+               }
+       return UI_method_get_reader(UI_OpenSSL())(ui, uis);
+       }
+static int ui_write(UI *ui, UI_STRING *uis)
+       {
+       if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD
+               && UI_get0_user_data(ui))
+               {
+               switch(UI_get_string_type(uis))
+                       {
+               case UIT_PROMPT:
+               case UIT_VERIFY:
+                       {
+                       const char *password =
+                               ((PW_CB_DATA *)UI_get0_user_data(ui))->password;
+                       if (password[0] != '\0')
+                               return 1;
+                       }
+               default:
+                       break;
+                       }
+               }
+       return UI_method_get_writer(UI_OpenSSL())(ui, uis);
+       }
+static int ui_close(UI *ui)
+       {
+       return UI_method_get_closer(UI_OpenSSL())(ui);
+       }
+int setup_ui_method()
+       {
+       ui_method = UI_create_method("OpenSSL application user interface");
+       UI_method_set_opener(ui_method, ui_open);
+       UI_method_set_reader(ui_method, ui_read);
+       UI_method_set_writer(ui_method, ui_write);
+       UI_method_set_closer(ui_method, ui_close);
+       return 0;
+       }
+void destroy_ui_method()
+       {
+       if(ui_method)
+               {
+               UI_destroy_method(ui_method);
+               ui_method = NULL;
+               }
+       }
+int password_callback(char *buf, int bufsiz, int verify,
+       PW_CB_DATA *cb_tmp)
+       {
+       UI *ui = NULL;
+       int res = 0;
+       const char *prompt_info = NULL;
+       const char *password = NULL;
+       PW_CB_DATA *cb_data = (PW_CB_DATA *)cb_tmp;
+
+       if (cb_data)
+               {
+               if (cb_data->password)
+                       password = cb_data->password;
+               if (cb_data->prompt_info)
+                       prompt_info = cb_data->prompt_info;
+               }
+
+       if (password)
+               {
+               res = strlen(password);
+               if (res > bufsiz)
+                       res = bufsiz;
+               memcpy(buf, password, res);
+               return res;
+               }
+
+       ui = UI_new_method(ui_method);
+       if (ui)
+               {
+               int ok = 0;
+               char *buff = NULL;
+               int ui_flags = 0;
+               char *prompt = NULL;
+
+               prompt = UI_construct_prompt(ui, "pass phrase",
+                       cb_data->prompt_info);
+
+               ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD;
+               UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
+
+               if (ok >= 0)
+                       ok = UI_add_input_string(ui,prompt,ui_flags,buf,
+                               PW_MIN_LENGTH,BUFSIZ-1);
+               if (ok >= 0 && verify)
+                       {
+                       buff = (char *)OPENSSL_malloc(bufsiz);
+                       ok = UI_add_verify_string(ui,prompt,ui_flags,buff,
+                               PW_MIN_LENGTH,BUFSIZ-1, buf);
+                       }
+               if (ok >= 0)
+                       do
+                               {
+                               ok = UI_process(ui);
+                               }
+                       while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
+
+               if (buff)
+                       {
+                       memset(buff,0,(unsigned int)bufsiz);
+                       OPENSSL_free(buff);
+                       }
+
+               if (ok >= 0)
+                       res = strlen(buf);
+               if (ok == -1)
+                       {
+                       BIO_printf(bio_err, "User interface error\n");
+                       ERR_print_errors(bio_err);
+                       memset(buf,0,(unsigned int)bufsiz);
+                       res = 0;
+                       }
+               if (ok == -2)
+                       {
+                       BIO_printf(bio_err,"aborted!\n");
+                       memset(buf,0,(unsigned int)bufsiz);
+                       res = 0;
+                       }
+               UI_free(ui);
+               OPENSSL_free(prompt);
+               }
+       return res;
+       }
+
 static char *app_get_pass(BIO *err, char *arg, int keepbio);
 
 int app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2)
@@ -444,18 +654,18 @@ static char *app_get_pass(BIO *err, char *arg, int keepbio)
        return BUF_strdup(tpass);
 }
 
-int add_oid_section(BIO *err, LHASH *conf)
+int add_oid_section(BIO *err, CONF *conf)
 {      
        char *p;
        STACK_OF(CONF_VALUE) *sktmp;
        CONF_VALUE *cnf;
        int i;
-       if(!(p=CONF_get_string(conf,NULL,"oid_section")))
+       if(!(p=NCONF_get_string(conf,NULL,"oid_section")))
                {
                ERR_clear_error();
                return 1;
                }
-       if(!(sktmp = CONF_get_section(conf, p))) {
+       if(!(sktmp = NCONF_get_section(conf, p))) {
                BIO_printf(err, "problem loading oid section %s\n", p);
                return 0;
        }
@@ -470,7 +680,8 @@ int add_oid_section(BIO *err, LHASH *conf)
        return 1;
 }
 
-X509 *load_cert(BIO *err, char *file, int format)
+X509 *load_cert(BIO *err, const char *file, int format,
+       const char *pass, ENGINE *e, const char *cert_descrip)
        {
        ASN1_HEADER *ah=NULL;
        BUF_MEM *buf=NULL;
@@ -492,7 +703,9 @@ X509 *load_cert(BIO *err, char *file, int format)
                {
                if (BIO_read_filename(cert,file) <= 0)
                        {
-                       perror(file);
+                       BIO_printf(err, "Error opening %s %s\n",
+                               cert_descrip, file);
+                       ERR_print_errors(err);
                        goto end;
                        }
                }
@@ -543,7 +756,8 @@ X509 *load_cert(BIO *err, char *file, int format)
                ah->data=NULL;
                }
        else if (format == FORMAT_PEM)
-               x=PEM_read_bio_X509_AUX(cert,NULL,NULL,NULL);
+               x=PEM_read_bio_X509_AUX(cert,NULL,
+                       (pem_password_cb *)password_callback, NULL);
        else if (format == FORMAT_PKCS12)
                {
                PKCS12 *p12 = d2i_PKCS12_bio(cert, NULL);
@@ -553,7 +767,8 @@ X509 *load_cert(BIO *err, char *file, int format)
                p12 = NULL;
                }
        else    {
-               BIO_printf(err,"bad input format specified for input cert\n");
+               BIO_printf(err,"bad input format specified for %s\n",
+                       cert_descrip);
                goto end;
                }
 end:
@@ -568,10 +783,15 @@ end:
        return(x);
        }
 
-EVP_PKEY *load_key(BIO *err, char *file, int format, char *pass, ENGINE *e)
+EVP_PKEY *load_key(BIO *err, const char *file, int format,
+       const char *pass, ENGINE *e, const char *key_descrip)
        {
        BIO *key=NULL;
        EVP_PKEY *pkey=NULL;
+       PW_CB_DATA cb_data;
+
+       cb_data.password = pass;
+       cb_data.prompt_info = file;
 
        if (file == NULL)
                {
@@ -583,7 +803,8 @@ EVP_PKEY *load_key(BIO *err, char *file, int format, char *pass, ENGINE *e)
                if (!e)
                        BIO_printf(bio_err,"no engine specified\n");
                else
-                       pkey = ENGINE_load_private_key(e, file, pass);
+                       pkey = ENGINE_load_private_key(e, file,
+                               ui_method, &cb_data);
                goto end;
                }
        key=BIO_new(BIO_s_file());
@@ -594,7 +815,8 @@ EVP_PKEY *load_key(BIO *err, char *file, int format, char *pass, ENGINE *e)
                }
        if (BIO_read_filename(key,file) <= 0)
                {
-               perror(file);
+               BIO_printf(err, "Error opening %s %s\n", key_descrip, file);
+               ERR_print_errors(err);
                goto end;
                }
        if (format == FORMAT_ASN1)
@@ -603,7 +825,8 @@ EVP_PKEY *load_key(BIO *err, char *file, int format, char *pass, ENGINE *e)
                }
        else if (format == FORMAT_PEM)
                {
-               pkey=PEM_read_bio_PrivateKey(key,NULL,NULL,pass);
+               pkey=PEM_read_bio_PrivateKey(key,NULL,
+                       (pem_password_cb *)password_callback, &cb_data);
                }
        else if (format == FORMAT_PKCS12)
                {
@@ -615,20 +838,25 @@ EVP_PKEY *load_key(BIO *err, char *file, int format, char *pass, ENGINE *e)
                }
        else
                {
-               BIO_printf(err,"bad input format specified for key\n");
+               BIO_printf(err,"bad input format specified for key file\n");
                goto end;
                }
  end:
        if (key != NULL) BIO_free(key);
        if (pkey == NULL)
-               BIO_printf(err,"unable to load Private Key\n");
+               BIO_printf(err,"unable to load %s\n", key_descrip);
        return(pkey);
        }
 
-EVP_PKEY *load_pubkey(BIO *err, char *file, int format, ENGINE *e)
+EVP_PKEY *load_pubkey(BIO *err, const char *file, int format,
+       const char *pass, ENGINE *e, const char *key_descrip)
        {
        BIO *key=NULL;
        EVP_PKEY *pkey=NULL;
+       PW_CB_DATA cb_data;
+
+       cb_data.password = pass;
+       cb_data.prompt_info = file;
 
        if (file == NULL)
                {
@@ -640,7 +868,8 @@ EVP_PKEY *load_pubkey(BIO *err, char *file, int format, ENGINE *e)
                if (!e)
                        BIO_printf(bio_err,"no engine specified\n");
                else
-                       pkey = ENGINE_load_public_key(e, file, NULL);
+                       pkey = ENGINE_load_public_key(e, file,
+                               ui_method, &cb_data);
                goto end;
                }
        key=BIO_new(BIO_s_file());
@@ -651,7 +880,8 @@ EVP_PKEY *load_pubkey(BIO *err, char *file, int format, ENGINE *e)
                }
        if (BIO_read_filename(key,file) <= 0)
                {
-               perror(file);
+               BIO_printf(err, "Error opening %s %s\n", key_descrip, file);
+               ERR_print_errors(err);
                goto end;
                }
        if (format == FORMAT_ASN1)
@@ -660,27 +890,33 @@ EVP_PKEY *load_pubkey(BIO *err, char *file, int format, ENGINE *e)
                }
        else if (format == FORMAT_PEM)
                {
-               pkey=PEM_read_bio_PUBKEY(key,NULL,NULL,NULL);
+               pkey=PEM_read_bio_PUBKEY(key,NULL,
+                       (pem_password_cb *)password_callback, &cb_data);
                }
        else
                {
-               BIO_printf(err,"bad input format specified for key\n");
+               BIO_printf(err,"bad input format specified for key file\n");
                goto end;
                }
  end:
        if (key != NULL) BIO_free(key);
        if (pkey == NULL)
-               BIO_printf(err,"unable to load Public Key\n");
+               BIO_printf(err,"unable to load %s\n", key_descrip);
        return(pkey);
        }
 
-STACK_OF(X509) *load_certs(BIO *err, char *file, int format)
+STACK_OF(X509) *load_certs(BIO *err, const char *file, int format,
+       const char *pass, ENGINE *e, const char *cert_descrip)
        {
        BIO *certs;
        int i;
        STACK_OF(X509) *othercerts = NULL;
        STACK_OF(X509_INFO) *allcerts = NULL;
        X509_INFO *xi;
+       PW_CB_DATA cb_data;
+
+       cb_data.password = pass;
+       cb_data.prompt_info = file;
 
        if((certs = BIO_new(BIO_s_file())) == NULL)
                {
@@ -694,7 +930,9 @@ STACK_OF(X509) *load_certs(BIO *err, char *file, int format)
                {
                if (BIO_read_filename(certs,file) <= 0)
                        {
-                       perror(file);
+                       BIO_printf(err, "Error opening %s %s\n",
+                               cert_descrip, file);
+                       ERR_print_errors(err);
                        goto end;
                        }
                }
@@ -708,7 +946,8 @@ STACK_OF(X509) *load_certs(BIO *err, char *file, int format)
                        othercerts = NULL;
                        goto end;
                        }
-               allcerts = PEM_X509_INFO_read_bio(certs, NULL, NULL, NULL);
+               allcerts = PEM_X509_INFO_read_bio(certs, NULL,
+                               (pem_password_cb *)password_callback, &cb_data);
                for(i = 0; i < sk_X509_INFO_num(allcerts); i++)
                        {
                        xi = sk_X509_INFO_value (allcerts, i);
@@ -721,7 +960,8 @@ STACK_OF(X509) *load_certs(BIO *err, char *file, int format)
                goto end;
                }
        else    {
-               BIO_printf(err,"bad input format specified for input cert\n");
+               BIO_printf(err,"bad input format specified for %s\n",
+                       cert_descrip);
                goto end;
                }
 end:
@@ -956,3 +1196,60 @@ X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath)
        X509_STORE_free(store);
        return NULL;
 }
+
+/* Try to load an engine in a shareable library */
+ENGINE *try_load_engine(BIO *err, const char *engine, int debug)
+       {
+       ENGINE *e = ENGINE_by_id("dynamic");
+       if (e)
+               {
+               if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0)
+                       || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0))
+                       {
+                       ENGINE_free(e);
+                       e = NULL;
+                       }
+               }
+       return e;
+       }
+
+ENGINE *setup_engine(BIO *err, const char *engine, int debug)
+        {
+        ENGINE *e = NULL;
+
+        if (engine)
+                {
+               if(strcmp(engine, "auto") == 0)
+                       {
+                       BIO_printf(err,"enabling auto ENGINE support\n");
+                       ENGINE_register_all_complete();
+                       return NULL;
+                       }
+               if((e = ENGINE_by_id(engine)) == NULL
+                       && (e = try_load_engine(err, engine, debug)) == NULL)
+                       {
+                       BIO_printf(err,"invalid engine \"%s\"\n", engine);
+                       ERR_print_errors(err);
+                       return NULL;
+                       }
+               if (debug)
+                       {
+                       ENGINE_ctrl(e, ENGINE_CTRL_SET_LOGSTREAM,
+                               0, err, 0);
+                       }
+                ENGINE_ctrl_cmd(e, "SET_USER_INTERFACE", 0, ui_method, 0, 1);
+               if(!ENGINE_set_default(e, ENGINE_METHOD_ALL))
+                       {
+                       BIO_printf(err,"can't use that engine\n");
+                       ERR_print_errors(err);
+                       ENGINE_free(e);
+                       return NULL;
+                       }
+
+               BIO_printf(err,"engine \"%s\" set.\n", ENGINE_get_id(e));
+
+               /* Free our "structural" reference. */
+               ENGINE_free(e);
+               }
+        return e;
+        }