load_netscape_key is static.
[openssl.git] / apps / apps.c
index 9bbf476245c8f783ebbfe723e82f4456a252f57d..ac18296e67f6f67c586fc1ebbf22488db96db0d1 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/pkcs12.h>
 #include <openssl/ui.h>
 #include <openssl/safestack.h>
+#include <openssl/engine.h>
 
 #ifdef OPENSSL_SYS_WINDOWS
 #define strcasecmp _stricmp
@@ -93,6 +147,13 @@ 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);
 
+#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA)
+/* Looks like this stuff is worth moving into separate function */
+static EVP_PKEY *
+load_netscape_key(BIO *err, BIO *key, const char *file,
+               const char *key_descrip, int format);
+#endif
+
 int app_init(long mesgwin);
 #ifdef undef /* never finished - probably never will be :-) */
 int args_from_file(char *file, int *argc, char **argv[])
@@ -249,9 +310,16 @@ void program_name(char *in, char *out, int size)
 
        q=strrchr(p,'.');
        if (q == NULL)
-               q = in+size;
-       strncpy(out,p,q-p);
-       out[q-p]='\0';
+               q = p + strlen(p);
+       strncpy(out,p,size-1);
+       if (q-p >= size)
+               {
+               out[size-1]='\0';
+               }
+       else
+               {
+               out[q-p]='\0';
+               }
        }
 #else
 void program_name(char *in, char *out, int size)
@@ -272,16 +340,13 @@ void program_name(char *in, char *out, int size)
 #ifdef OPENSSL_SYS_WIN32
 int WIN32_rename(char *from, char *to)
        {
-#ifdef OPENSSL_SYS_WINNT
-       int ret;
-/* Note: MoveFileEx() doesn't work under Win95, Win98 */
-
-       ret=MoveFileEx(from,to,MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED);
-       return(ret?0:-1);
-#else
-       unlink(to);
-       return MoveFile(from, to);
-#endif
+       /* Windows rename gives an error if 'to' exists, so delete it
+        * first and ignore file not found errror
+        */
+       if((remove(to) != 0) && (errno != ENOENT))
+               return -1;
+#undef rename
+       return rename(from, to);
        }
 #endif
 
@@ -390,7 +455,7 @@ static int ui_read(UI *ui, UI_STRING *uis)
                                ((PW_CB_DATA *)UI_get0_user_data(ui))->password;
                        if (password[0] != '\0')
                                {
-                               UI_set_result(uis, password);
+                               UI_set_result(ui, uis, password);
                                return 1;
                                }
                        }
@@ -425,7 +490,7 @@ static int ui_close(UI *ui)
        {
        return UI_method_get_closer(UI_OpenSSL())(ui);
        }
-int setup_ui_method()
+int setup_ui_method(void)
        {
        ui_method = UI_create_method("OpenSSL application user interface");
        UI_method_set_opener(ui_method, ui_open);
@@ -434,7 +499,7 @@ int setup_ui_method()
        UI_method_set_closer(ui_method, ui_close);
        return 0;
        }
-void destroy_ui_method()
+void destroy_ui_method(void)
        {
        if(ui_method)
                {
@@ -459,11 +524,18 @@ int password_callback(char *buf, int bufsiz, int verify,
                        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)
                {
-               char errstring[80];
-               int errstring_added = 0;
                int ok = 0;
                char *buff = NULL;
                int ui_flags = 0;
@@ -473,44 +545,32 @@ int password_callback(char *buf, int bufsiz, int verify,
                        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,0,BUFSIZ-1);
+                       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,0,BUFSIZ-1,
-                               buf);
+                       ok = UI_add_verify_string(ui,prompt,ui_flags,buff,
+                               PW_MIN_LENGTH,BUFSIZ-1, buf);
                        }
                if (ok >= 0)
-                       for(;;)
+                       do
                                {
-                               res = 0;
-                               ok=UI_process(ui);
-                               if (ok < 0)
-                                       break;
-                               res=strlen(buf);
-                               if (res < PW_MIN_LENGTH)
-                                       {
-                                       if (errstring_added == 0)
-                                               {
-                                               BIO_snprintf(errstring,
-                                                       sizeof(errstring),
-"phrase is too short, needs to be at least %d chars\n", PW_MIN_LENGTH);
-                                               UI_add_error_string(ui,
-                                                       errstring);
-                                               }
-                                       errstring_added = 1;
-                                       }
-                               else
-                                       break;
+                               ok = UI_process(ui);
                                }
+                       while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
+
                if (buff)
                        {
-                       memset(buf,0,(unsigned int)bufsiz);
+                       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");
@@ -525,6 +585,7 @@ int password_callback(char *buf, int bufsiz, int verify,
                        res = 0;
                        }
                UI_free(ui);
+               OPENSSL_free(prompt);
                }
        return res;
        }
@@ -604,18 +665,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;
        }
@@ -778,6 +839,10 @@ EVP_PKEY *load_key(BIO *err, const char *file, int format,
                pkey=PEM_read_bio_PrivateKey(key,NULL,
                        (pem_password_cb *)password_callback, &cb_data);
                }
+#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA)
+       else if (format == FORMAT_NETSCAPE || format == FORMAT_IISSGC)
+               pkey = load_netscape_key(err, key, file, key_descrip, format);
+#endif
        else if (format == FORMAT_PKCS12)
                {
                PKCS12 *p12 = d2i_PKCS12_bio(key, NULL);
@@ -843,6 +908,10 @@ EVP_PKEY *load_pubkey(BIO *err, const char *file, int format,
                pkey=PEM_read_bio_PUBKEY(key,NULL,
                        (pem_password_cb *)password_callback, &cb_data);
                }
+#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA)
+       else if (format == FORMAT_NETSCAPE || format == FORMAT_IISSGC)
+               pkey = load_netscape_key(err, key, file, key_descrip, format);
+#endif
        else
                {
                BIO_printf(err,"bad input format specified for key file\n");
@@ -855,6 +924,52 @@ EVP_PKEY *load_pubkey(BIO *err, const char *file, int format,
        return(pkey);
        }
 
+#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA)
+static EVP_PKEY *
+load_netscape_key(BIO *err, BIO *key, const char *file,
+               const char *key_descrip, int format)
+       {
+       EVP_PKEY *pkey;
+       BUF_MEM *buf;
+       RSA     *rsa;
+       const unsigned char *p;
+       int size, i;
+
+       buf=BUF_MEM_new();
+       pkey = EVP_PKEY_new();
+       size = 0;
+       if (buf == NULL || pkey == NULL)
+               goto error;
+       for (;;)
+               {
+               if (!BUF_MEM_grow(buf,size+1024*10))
+                       goto error;
+               i = BIO_read(key, &(buf->data[size]), 1024*10);
+               size += i;
+               if (i == 0)
+                       break;
+               if (i < 0)
+                       {
+                               BIO_printf(err, "Error reading %s %s",
+                                       key_descrip, file);
+                               goto error;
+                       }
+               }
+       p=(unsigned char *)buf->data;
+       rsa = d2i_RSA_NET(NULL,&p,(long)size,NULL,
+               (format == FORMAT_IISSGC ? 1 : 0));
+       if (rsa == NULL)
+               goto error;
+       BUF_MEM_free(buf);
+       EVP_PKEY_set1_RSA(pkey, rsa);
+       return pkey;
+error:
+       BUF_MEM_free(buf);
+       EVP_PKEY_free(pkey);
+       return NULL;
+       }
+#endif /* ndef OPENSSL_NO_RC4 */
+
 STACK_OF(X509) *load_certs(BIO *err, const char *file, int format,
        const char *pass, ENGINE *e, const char *cert_descrip)
        {
@@ -1147,15 +1262,39 @@ X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath)
        return NULL;
 }
 
+/* Try to load an engine in a shareable library */
+static 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((e = ENGINE_by_id(engine)) == NULL)
+               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)
@@ -1167,11 +1306,33 @@ ENGINE *setup_engine(BIO *err, const char *engine, int debug)
                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);
+
+               BIO_printf(err,"engine \"%s\" set.\n", ENGINE_get_id(e));
+
                /* Free our "structural" reference. */
                ENGINE_free(e);
                }
         return e;
         }
+
+int load_config(BIO *err, CONF *cnf)
+       {
+       if (!cnf)
+               cnf = config;
+       if (!cnf)
+               return 1;
+
+       OPENSSL_load_builtin_modules();
+
+       if (CONF_modules_load(cnf, NULL, 0) <= 0)
+               {
+               BIO_printf(err, "Error configuring OpenSSL\n");
+               ERR_print_errors(err);
+               return 0;
+               }
+       return 1;
+       }