summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2017-06-09 06:40:25 +0000
committerDamien Miller <djm@cvs.openbsd.org>2017-06-09 06:40:25 +0000
commit272ff0ff90cc41507125d36d140ed8b1a0b3755d (patch)
treeec09d11e3d387805a729ef526a1907defde0754b
parente4485725e84e27f0ad7bab9506399c95a64c5b85 (diff)
better translate libcrypto errors by looking deeper in the accursed
error stack for codes that indicate the wrong passphrase was supplied for a PEM key. bz#2699 ok dtucker@
-rw-r--r--usr.bin/ssh/sshkey.c102
1 files changed, 62 insertions, 40 deletions
diff --git a/usr.bin/ssh/sshkey.c b/usr.bin/ssh/sshkey.c
index 85876612bbe..8ed245e7c6a 100644
--- a/usr.bin/ssh/sshkey.c
+++ b/usr.bin/ssh/sshkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.51 2017/05/31 09:15:42 deraadt Exp $ */
+/* $OpenBSD: sshkey.c,v 1.52 2017/06/09 06:40:24 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@@ -1303,7 +1303,7 @@ sshkey_to_base64(const struct sshkey *key, char **b64p)
return r;
}
-static int
+int
sshkey_format_text(const struct sshkey *key, struct sshbuf *b)
{
int r = SSH_ERR_INTERNAL_ERROR;
@@ -3314,6 +3314,64 @@ sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
#ifdef WITH_OPENSSL
static int
+translate_libcrypto_error(unsigned long pem_err)
+{
+ int pem_reason = ERR_GET_REASON(pem_err);
+
+ switch (ERR_GET_LIB(pem_err)) {
+ case ERR_LIB_PEM:
+ switch (pem_reason) {
+ case PEM_R_BAD_PASSWORD_READ:
+ case PEM_R_PROBLEMS_GETTING_PASSWORD:
+ case PEM_R_BAD_DECRYPT:
+ return SSH_ERR_KEY_WRONG_PASSPHRASE;
+ default:
+ return SSH_ERR_INVALID_FORMAT;
+ }
+ case ERR_LIB_EVP:
+ switch (pem_reason) {
+ case EVP_R_BAD_DECRYPT:
+ return SSH_ERR_KEY_WRONG_PASSPHRASE;
+ case EVP_R_BN_DECODE_ERROR:
+ case EVP_R_DECODE_ERROR:
+#ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
+ case EVP_R_PRIVATE_KEY_DECODE_ERROR:
+#endif
+ return SSH_ERR_INVALID_FORMAT;
+ default:
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ }
+ case ERR_LIB_ASN1:
+ return SSH_ERR_INVALID_FORMAT;
+ }
+ return SSH_ERR_LIBCRYPTO_ERROR;
+}
+
+static void
+clear_libcrypto_errors(void)
+{
+ while (ERR_get_error() != 0)
+ ;
+}
+
+/*
+ * Translate OpenSSL error codes to determine whether
+ * passphrase is required/incorrect.
+ */
+static int
+convert_libcrypto_error(void)
+{
+ /*
+ * Some password errors are reported at the beginning
+ * of the error queue.
+ */
+ if (translate_libcrypto_error(ERR_peek_error()) ==
+ SSH_ERR_KEY_WRONG_PASSPHRASE)
+ return SSH_ERR_KEY_WRONG_PASSPHRASE;
+ return translate_libcrypto_error(ERR_peek_last_error());
+}
+
+static int
sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
const char *passphrase, struct sshkey **keyp)
{
@@ -3333,46 +3391,10 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
goto out;
}
+ clear_libcrypto_errors();
if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL,
(char *)passphrase)) == NULL) {
- unsigned long pem_err = ERR_peek_last_error();
- int pem_reason = ERR_GET_REASON(pem_err);
-
- /*
- * Translate OpenSSL error codes to determine whether
- * passphrase is required/incorrect.
- */
- switch (ERR_GET_LIB(pem_err)) {
- case ERR_LIB_PEM:
- switch (pem_reason) {
- case PEM_R_BAD_PASSWORD_READ:
- case PEM_R_PROBLEMS_GETTING_PASSWORD:
- case PEM_R_BAD_DECRYPT:
- r = SSH_ERR_KEY_WRONG_PASSPHRASE;
- goto out;
- default:
- r = SSH_ERR_INVALID_FORMAT;
- goto out;
- }
- case ERR_LIB_EVP:
- switch (pem_reason) {
- case EVP_R_BAD_DECRYPT:
- r = SSH_ERR_KEY_WRONG_PASSPHRASE;
- goto out;
- case EVP_R_BN_DECODE_ERROR:
- case EVP_R_DECODE_ERROR:
- case EVP_R_PRIVATE_KEY_DECODE_ERROR:
- r = SSH_ERR_INVALID_FORMAT;
- goto out;
- default:
- r = SSH_ERR_LIBCRYPTO_ERROR;
- goto out;
- }
- case ERR_LIB_ASN1:
- r = SSH_ERR_INVALID_FORMAT;
- goto out;
- }
- r = SSH_ERR_LIBCRYPTO_ERROR;
+ r = convert_libcrypto_error();
goto out;
}
if (pk->type == EVP_PKEY_RSA &&