* 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
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);
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)
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;
}
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;
{
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;
}
}
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);
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:
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)
{
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());
}
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)
}
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)
{
}
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)
{
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());
}
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)
}
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)
{
{
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;
}
}
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);
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:
return set_multi_opts(flags, arg, ex_tbl);
}
+int set_ext_copy(int *copy_type, const char *arg)
+{
+ if (!strcasecmp(arg, "none"))
+ *copy_type = EXT_COPY_NONE;
+ else if (!strcasecmp(arg, "copy"))
+ *copy_type = EXT_COPY_ADD;
+ else if (!strcasecmp(arg, "copyall"))
+ *copy_type = EXT_COPY_ALL;
+ else
+ return 0;
+ return 1;
+}
+
+int copy_extensions(X509 *x, X509_REQ *req, int copy_type)
+{
+ STACK_OF(X509_EXTENSION) *exts = NULL;
+ X509_EXTENSION *ext, *tmpext;
+ ASN1_OBJECT *obj;
+ int i, idx, ret = 0;
+ if (!x || !req || (copy_type == EXT_COPY_NONE))
+ return 1;
+ exts = X509_REQ_get_extensions(req);
+
+ for(i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
+ ext = sk_X509_EXTENSION_value(exts, i);
+ obj = X509_EXTENSION_get_object(ext);
+ idx = X509_get_ext_by_OBJ(x, obj, -1);
+ /* Does extension exist? */
+ if (idx != -1) {
+ /* If normal copy don't override existing extension */
+ if (copy_type == EXT_COPY_ADD)
+ continue;
+ /* Delete all extensions of same type */
+ do {
+ tmpext = X509_get_ext(x, idx);
+ X509_delete_ext(x, idx);
+ X509_EXTENSION_free(tmpext);
+ idx = X509_get_ext_by_OBJ(x, obj, -1);
+ } while (idx != -1);
+ }
+ if (!X509_add_ext(x, ext, -1))
+ goto end;
+ }
+
+ ret = 1;
+
+ end:
+
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+
+ return ret;
+}
+
+
+
+
static int set_multi_opts(unsigned long *flags, const char *arg, const NAME_EX_TBL *in_tbl)
{
STACK_OF(CONF_VALUE) *vals;
X509_STORE_free(store);
return NULL;
}
+
+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)
+ {
+ BIO_printf(err,"invalid engine \"%s\"\n", engine);
+ 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");
+ return NULL;
+ }
+
+ BIO_printf(err,"engine \"%s\" set.\n", engine);
+
+ /* Free our "structural" reference. */
+ ENGINE_free(e);
+ }
+ return e;
+ }