Extend all the loading functions to take an engine pointer, a pass
string (some engines may have certificates protected by a PIN!) and
a description to put into error messages.

Also, have our own password callback that we can send both a password
and some prompt info to.  The default password callback in EVP assumes
that the passed parameter is a password, which isn't always the right
thing, and the ENGINE code (at least the nCipher one) makes other
assumptions...

Also, in spite of having the functions to load keys, some utilities
did the loading all by themselves...  That's changed too.
diff --git a/apps/apps.c b/apps/apps.c
index 4aeabdf..659a3ad 100644
--- a/apps/apps.c
+++ b/apps/apps.c
@@ -369,6 +369,57 @@
         return 0;
 }
 
+int password_callback(char *buf, int bufsiz, int verify,
+	PW_CB_DATA *cb_data)
+	{
+	int i,j;
+	char prompt[80];
+	const char *prompt_info = NULL;
+	const char *password = NULL;
+
+	if (cb_data)
+		{
+		if (cb_data->password)
+			password = cb_data->password;
+		if (cb_data->prompt_info)
+			prompt_info = cb_data->prompt_info;
+		}
+
+	if(password) {
+		i=strlen(password);
+		i=(i > bufsiz)?bufsiz:i;
+		memcpy(buf,password,i);
+		return(i);
+	}
+
+	if (EVP_get_pw_prompt())
+		BIO_snprintf(prompt, sizeof(prompt)-1, EVP_get_pw_prompt(),
+			prompt_info ? prompt_info : "");
+	else
+		BIO_snprintf(prompt, sizeof(prompt)-1,
+			"Enter pass phrase for %s:",
+			prompt_info ? prompt_info : "");
+
+	for (;;)
+		{
+		i=EVP_read_pw_string(buf,bufsiz,prompt,verify);
+		if (i != 0)
+			{
+			BIO_printf(bio_err,"aborted!\n");
+			memset(buf,0,(unsigned int)bufsiz);
+			return(-1);
+			}
+		j=strlen(buf);
+		if (j < PW_MIN_LENGTH)
+			{
+			BIO_printf(bio_err,"phrase is too short, needs to be at least %d chars\n",PW_MIN_LENGTH);
+			}
+		else
+			break;
+		}
+	return(j);
+	}
+
 static char *app_get_pass(BIO *err, char *arg, int keepbio);
 
 int app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2)
@@ -470,7 +521,8 @@
 	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 +544,9 @@
 		{
 		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 +597,8 @@
 		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 +608,8 @@
 		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 +624,15 @@
 	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 +644,8 @@
 		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,
+				(pem_password_cb *)password_callback, &cb_data);
 		goto end;
 		}
 	key=BIO_new(BIO_s_file());
@@ -594,7 +656,8 @@
 		}
 	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 +666,8 @@
 		}
 	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 +679,25 @@
 		}
 	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 +709,8 @@
 		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,
+				(pem_password_cb *)password_callback, &cb_data);
 		goto end;
 		}
 	key=BIO_new(BIO_s_file());
@@ -651,7 +721,8 @@
 		}
 	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 +731,33 @@
 		}
 	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 +771,9 @@
 		{
 		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 +787,8 @@
 			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 +801,8 @@
 		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:
diff --git a/apps/apps.h b/apps/apps.h
index 96dafd9..a2b72f0 100644
--- a/apps/apps.h
+++ b/apps/apps.h
@@ -142,6 +142,16 @@
 	int count;
 	} ARGS;
 
+#define PW_MIN_LENGTH 4
+typedef struct pw_cb_data
+	{
+	const void *password;
+	const char *prompt_info;
+	} PW_CB_DATA;
+
+int password_callback(char *buf, int bufsiz, int verify,
+	PW_CB_DATA *cb_data);
+
 int should_retry(int i);
 int args_from_file(char *file, int *argc, char **argv[]);
 int str2fmt(char *s);
@@ -157,10 +167,14 @@
 int copy_extensions(X509 *x, X509_REQ *req, int copy_type);
 int app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2);
 int add_oid_section(BIO *err, LHASH *conf);
-X509 *load_cert(BIO *err, char *file, int format);
-EVP_PKEY *load_key(BIO *err, char *file, int format, char *pass, ENGINE *e);
-EVP_PKEY *load_pubkey(BIO *err, char *file, int format, ENGINE *e);
-STACK_OF(X509) *load_certs(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);
+EVP_PKEY *load_key(BIO *err, const char *file, int format,
+	const char *pass, ENGINE *e, const char *key_descrip);
+EVP_PKEY *load_pubkey(BIO *err, const char *file, int format,
+	const char *pass, ENGINE *e, const char *key_descrip);
+STACK_OF(X509) *load_certs(BIO *err, const char *file, int format,
+	const char *pass, ENGINE *e, const char *cert_descrip);
 X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath);
 
 #define FORMAT_UNDEF    0
diff --git a/apps/ca.c b/apps/ca.c
index a4bc7bd..921e1f1 100644
--- a/apps/ca.c
+++ b/apps/ca.c
@@ -702,34 +702,12 @@
 		BIO_printf(bio_err,"Error getting password\n");
 		goto err;
 		}
-	if (keyform == FORMAT_ENGINE)
-		{
-		if (!e)
-			{
-			BIO_printf(bio_err,"no engine specified\n");
-			goto err;
-			}
-		pkey = ENGINE_load_private_key(e, keyfile, key);
-		}
-	else if (keyform == FORMAT_PEM)
-		{
-		if (BIO_read_filename(in,keyfile) <= 0)
-			{
-			perror(keyfile);
-			BIO_printf(bio_err,"trying to load CA private key\n");
-			goto err;
-			}
-		pkey=PEM_read_bio_PrivateKey(in,NULL,NULL,key);
-		}
-	else
-		{
-		BIO_printf(bio_err,"bad input format specified for key file\n");
-		goto err;
-		}
+	pkey = load_key(bio_err, keyfile, keyform, key, e, 
+		"CA private key");
 	if (key) memset(key,0,strlen(key));
 	if (pkey == NULL)
 		{
-		BIO_printf(bio_err,"unable to load CA private key\n");
+		/* load_key() has already printed an appropriate message */
 		goto err;
 		}
 
diff --git a/apps/dgst.c b/apps/dgst.c
index a6b2e30..a010ba0 100644
--- a/apps/dgst.c
+++ b/apps/dgst.c
@@ -289,52 +289,19 @@
 
 	if(keyfile)
 		{
-		if (keyform == FORMAT_PEM)
-			{
-			BIO *keybio;
-			keybio = BIO_new_file(keyfile, "r");
-			if(!keybio)
-				{
-				BIO_printf(bio_err,
-					"Error opening key file %s\n",
-					keyfile);
-				ERR_print_errors(bio_err);
-				goto end;
-				}
-			if(want_pub) 
-				sigkey = PEM_read_bio_PUBKEY(keybio,
-					NULL, NULL, NULL);
-			else
-				sigkey = PEM_read_bio_PrivateKey(keybio,
-					NULL, NULL, NULL);
-			BIO_free(keybio);
-			}
-		else if (keyform == FORMAT_ENGINE)
-			{
-			if (!e)
-				{
-				BIO_printf(bio_err,"no engine specified\n");
-				goto end;
-				}
-			if (want_pub)
-				sigkey = ENGINE_load_public_key(e, keyfile, NULL);
-			else
-				sigkey = ENGINE_load_private_key(e, keyfile, NULL);
-			}
+		if (want_pub)
+			sigkey = load_pubkey(bio_err, keyfile, keyform, NULL,
+				e, "key file");
 		else
+			sigkey = load_key(bio_err, keyfile, keyform, NULL,
+				e, "key file");
+		if (!sigkey)
 			{
-			BIO_printf(bio_err,
-				"bad input format specified for key file\n");
+			/* load_[pub]key() has already printed an appropriate
+			   message */
 			goto end;
 			}
-		
-		if(!sigkey) {
-			BIO_printf(bio_err, "Error reading key file %s\n",
-								keyfile);
-			ERR_print_errors(bio_err);
-			goto end;
 		}
-	}
 
 	if(sigfile && sigkey) {
 		BIO *sigbio;
diff --git a/apps/ocsp.c b/apps/ocsp.c
index ba456fc..16207a6 100644
--- a/apps/ocsp.c
+++ b/apps/ocsp.c
@@ -82,6 +82,7 @@
 
 int MAIN(int argc, char **argv)
 	{
+	ENGINE *e = NULL;
 	char **args;
 	char *host = NULL, *port = NULL, *path = "/";
 	char *reqin = NULL, *respin = NULL;
@@ -326,7 +327,8 @@
 				{
 				args++;
 				X509_free(issuer);
-				issuer = load_cert(bio_err, *args, FORMAT_PEM);
+				issuer = load_cert(bio_err, *args, FORMAT_PEM,
+					NULL, e, "issuer certificate");
 				if(!issuer) goto end;
 				}
 			else badarg = 1;
@@ -337,7 +339,8 @@
 				{
 				args++;
 				X509_free(cert);
-				cert = load_cert(bio_err, *args, FORMAT_PEM);
+				cert = load_cert(bio_err, *args, FORMAT_PEM,
+					NULL, e, "certificate");
 				if(!cert) goto end;
 				if(!add_ocsp_cert(&req, cert, issuer, ids))
 					goto end;
@@ -445,7 +448,8 @@
 	if (signfile)
 		{
 		if (!keyfile) keyfile = signfile;
-		signer = load_cert(bio_err, signfile, FORMAT_PEM);
+		signer = load_cert(bio_err, signfile, FORMAT_PEM,
+			NULL, e, "signer certificate");
 		if (!signer)
 			{
 			BIO_printf(bio_err, "Error loading signer certificate\n");
@@ -453,13 +457,17 @@
 			}
 		if (sign_certfile)
 			{
-			sign_other = load_certs(bio_err, sign_certfile, FORMAT_PEM);
+			sign_other = load_certs(bio_err, sign_certfile, FORMAT_PEM,
+				NULL, e, "signer certificates");
 			if (!sign_other) goto end;
 			}
-		key = load_key(bio_err, keyfile, FORMAT_PEM, NULL, NULL);
+		key = load_key(bio_err, keyfile, FORMAT_PEM, NULL, NULL,
+			"signer private key");
 		if (!key)
 			{
+#if 0			/* An appropriate message has already been printed */
 			BIO_printf(bio_err, "Error loading signer private key\n");
+#endif
 			goto end;
 			}
 		if (!OCSP_request_sign(req, signer, key, EVP_sha1(), sign_other, sign_flags))
@@ -565,7 +573,8 @@
 	if(!store) goto end;
 	if (verify_certfile)
 		{
-		verify_other = load_certs(bio_err, verify_certfile, FORMAT_PEM);
+		verify_other = load_certs(bio_err, verify_certfile, FORMAT_PEM,
+			NULL, e, "validator certificate");
 		if (!verify_other) goto end;
 		}
 
diff --git a/apps/req.c b/apps/req.c
index f422d3e..429eb9d 100644
--- a/apps/req.c
+++ b/apps/req.c
@@ -606,40 +606,12 @@
 
 	if (keyfile != NULL)
 		{
-		if (keyform == FORMAT_ENGINE)
+		pkey = load_key(bio_err, keyfile, keyform, NULL, e,
+			"Private Key");
+		if (!pkey)
 			{
-			if (!e)
-				{
-				BIO_printf(bio_err,"no engine specified\n");
-				goto end;
-				}
-			pkey = ENGINE_load_private_key(e, keyfile, NULL);
-			}
-		else
-			{
-			if (BIO_read_filename(in,keyfile) <= 0)
-				{
-				perror(keyfile);
-				goto end;
-				}
-
-			if (keyform == FORMAT_ASN1)
-				pkey=d2i_PrivateKey_bio(in,NULL);
-			else if (keyform == FORMAT_PEM)
-				{
-				pkey=PEM_read_bio_PrivateKey(in,NULL,NULL,
-					passin);
-				}
-			else
-				{
-				BIO_printf(bio_err,"bad input format specified for X509 request\n");
-				goto end;
-				}
-			}
-
-		if (pkey == NULL)
-			{
-			BIO_printf(bio_err,"unable to load Private key\n");
+			/* load_key() has already printed an appropriate
+			   message */
 			goto end;
 			}
 		if (EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA)
diff --git a/apps/rsautl.c b/apps/rsautl.c
index 662c11a..86aa95d 100644
--- a/apps/rsautl.c
+++ b/apps/rsautl.c
@@ -180,15 +180,18 @@
 	
 	switch(key_type) {
 		case KEY_PRIVKEY:
-		pkey = load_key(bio_err, keyfile, keyform, NULL, e);
+		pkey = load_key(bio_err, keyfile, keyform,
+			NULL, e, "Private Key");
 		break;
 
 		case KEY_PUBKEY:
-		pkey = load_pubkey(bio_err, keyfile, keyform, e);
+		pkey = load_pubkey(bio_err, keyfile, keyform,
+			NULL, e, "Public Key");
 		break;
 
 		case KEY_CERT:
-		x = load_cert(bio_err, keyfile, keyform);
+		x = load_cert(bio_err, keyfile, keyform,
+			NULL, e, "Certificate");
 		if(x) {
 			pkey = X509_get_pubkey(x);
 			X509_free(x);
@@ -197,7 +200,6 @@
 	}
 
 	if(!pkey) {
-		BIO_printf(bio_err, "Error loading key\n");
 		return 1;
 	}
 
diff --git a/apps/smime.c b/apps/smime.c
index ede9531..8699334 100644
--- a/apps/smime.c
+++ b/apps/smime.c
@@ -372,8 +372,11 @@
 		}
 		encerts = sk_X509_new_null();
 		while (*args) {
-			if(!(cert = load_cert(bio_err,*args,FORMAT_PEM))) {
+			if(!(cert = load_cert(bio_err,*args,FORMAT_PEM,
+				NULL, e, "recipient certificate file"))) {
+#if 0				/* An appropriate message is already printed */
 				BIO_printf(bio_err, "Can't read recipient certificate file %s\n", *args);
+#endif
 				goto end;
 			}
 			sk_X509_push(encerts, cert);
@@ -383,23 +386,32 @@
 	}
 
 	if(signerfile && (operation == SMIME_SIGN)) {
-		if(!(signer = load_cert(bio_err,signerfile,FORMAT_PEM))) {
+		if(!(signer = load_cert(bio_err,signerfile,FORMAT_PEM, NULL,
+			e, "signer certificate"))) {
+#if 0			/* An appropri message has already been printed */
 			BIO_printf(bio_err, "Can't read signer certificate file %s\n", signerfile);
+#endif
 			goto end;
 		}
 	}
 
 	if(certfile) {
-		if(!(other = load_certs(bio_err,certfile,FORMAT_PEM))) {
+		if(!(other = load_certs(bio_err,certfile,FORMAT_PEM, NULL,
+			e, "certificate file"))) {
+#if 0			/* An appropriate message has already been printed */
 			BIO_printf(bio_err, "Can't read certificate file %s\n", certfile);
+#endif
 			ERR_print_errors(bio_err);
 			goto end;
 		}
 	}
 
 	if(recipfile && (operation == SMIME_DECRYPT)) {
-		if(!(recip = load_cert(bio_err,recipfile,FORMAT_PEM))) {
+		if(!(recip = load_cert(bio_err,recipfile,FORMAT_PEM,NULL,
+			e, "recipient certificate file"))) {
+#if 0			/* An appropriate message has alrady been printed */
 			BIO_printf(bio_err, "Can't read recipient certificate file %s\n", recipfile);
+#endif
 			ERR_print_errors(bio_err);
 			goto end;
 		}
@@ -412,18 +424,10 @@
 	} else keyfile = NULL;
 
 	if(keyfile) {
-                if (keyform == FORMAT_ENGINE) {
-        		if (!e) {
-        			BIO_printf(bio_err,"no engine specified\n");
-                		goto end;
-			}
-                        key = ENGINE_load_private_key(e, keyfile, passin);
-                } else {
-                        if(!(key = load_key(bio_err,keyfile, FORMAT_PEM, passin, NULL))) {
-                                BIO_printf(bio_err, "Can't read recipient certificate file %s\n", keyfile);
-        			ERR_print_errors(bio_err);
-                		goto end;
-                        }
+		key = load_key(bio_err, keyfile, keyform, passin, e,
+			       "signing key file");
+		if (!key) {
+			goto end;
                 }
 	}
 
diff --git a/apps/x509.c b/apps/x509.c
index 391bb3e..5be9074 100644
--- a/apps/x509.c
+++ b/apps/x509.c
@@ -619,12 +619,12 @@
 		EVP_PKEY_free(pkey);
 		}
 	else
-		x=load_cert(bio_err,infile,informat);
+		x=load_cert(bio_err,infile,informat,NULL,e,"Certificate");
 
 	if (x == NULL) goto end;
 	if (CA_flag)
 		{
-		xca=load_cert(bio_err,CAfile,CAformat);
+		xca=load_cert(bio_err,CAfile,CAformat,NULL,e,"CA Certificate");
 		if (xca == NULL) goto end;
 		}
 
@@ -874,7 +874,8 @@
 				if (Upkey == NULL)
 					{
 					Upkey=load_key(bio_err,
-						keyfile,keyformat, passin, e);
+						keyfile,keyformat, passin, e,
+						"Private key");
 					if (Upkey == NULL) goto end;
 					}
 #ifndef OPENSSL_NO_DSA
@@ -893,7 +894,7 @@
 					{
 					CApkey=load_key(bio_err,
 						CAkeyfile,CAkeyformat, passin,
-						e);
+						e, "CA Private Key");
 					if (CApkey == NULL) goto end;
 					}
 #ifndef OPENSSL_NO_DSA
@@ -920,7 +921,8 @@
 				else
 					{
 					pk=load_key(bio_err,
-						keyfile,FORMAT_PEM, passin, e);
+						keyfile,FORMAT_PEM, passin, e,
+						"request key");
 					if (pk == NULL) goto end;
 					}