From b560cb4c7bf268ba4cbb1947a417facb676b9782 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 21 Jul 2026 15:23:45 +0200 Subject: [PATCH] crypto: de-duplicate/merge most file/blob codepaths Replace separate codepath for loading private keys from filenames vs. memory buffers (blobs), with unified functions that handle both. Either filename or blob pointer + size must be passed to these functions. To reduce code duplication and small/large differences and bugs between these codepaths. Also to improve readability and ease maintenance. Also fix: - mbedtls: do not pass redundant null-terminator to `mbed_parse_openssh_key()` on in ECDSA blob codepath. (benign) - libgcrypt: add support for RSA/DSA blobs. - openssl: error handling code now applies to from-file codepath. Reported-and-alternate-patch-by: Martin Nowak Fixes #1652 - openssl: add file support for `ssh2_sk_pubkey()`. (not exposed via public API at this time.) - openssl: fix to call `OSSL_INIT_IF_NEEDED()` from `ssh2_pub_privkey()`. (for wolfSSL-debug enabled builds.) - openssl: fix error code returned by `ssh2_sk_pubkey()`. (to be consistent with rest of code.) - openssl: fix potential NULL deref in `ssh2_ed25519_new_priv()` blob codepaths. - openssl: fix potential dangling pointer in RSA, DSA, ECDSA codepaths (both file and blob) if BIO init failed. - os400qc3: fix uninitialized structs in `os400_pub_privkey_*()`. - os400qc3: drop unused local variable. Notes: - os400: use wrappers without actually merging the code. They are very different and difficult to read, also not possible to build test. - openssl: ed25519 loader code has outlier code where the file/blob code is different (both rather short.) - openssl: there is a file/blob function pair left to merge. - pem: there remain two pairs of file/blob internal APIs. Follow-up to 6a951168ceecee100691754b51bc257f46b9d62a #2362 Follow-up to fe9442be4d13b14edb1d6699ed9a75afddbfebcc #2359 Follow-up to 5b94157f1c83967f369d22bf5d90bc456a5a55c2 #2354 Closes #2379 --- src/HACKING-CRYPTO.md | 127 ++++------- src/crypto.h | 86 +++---- src/hostkey.c | 52 +---- src/libgcrypt.c | 125 ++++------- src/mbedtls.c | 274 +++++++++-------------- src/misc.c | 20 +- src/openssl.c | 505 +++++++++++++++++------------------------- src/openssl.h | 2 +- src/os400qc3.c | 251 ++++++++++++--------- src/userauth.c | 56 +++-- src/wincng.c | 270 +++++++--------------- 11 files changed, 701 insertions(+), 1067 deletions(-) diff --git a/src/HACKING-CRYPTO.md b/src/HACKING-CRYPTO.md index ca0b84f8..e72e11ff 100644 --- a/src/HACKING-CRYPTO.md +++ b/src/HACKING-CRYPTO.md @@ -414,29 +414,17 @@ Format of an ED25519 public key: Each item is preceded by its 32-bit byte length, MSB first. ```c -int ssh2_pub_privkey_file(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase); +int ssh2_pub_privkey(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + const char *privatekey, + const char *privkeyblob, size_t privkeyblob_len, + const char *passphrase); ``` -Reads a private key from file `privatekey` and extracts the public key --> -(`pubkeydata`, `pubkeydata_len`). Store the associated method (ssh-rsa or -ssh-dss) into (`method`, `method_len`). -Both buffers have to be allocated using `SSH2_ALLOC()`. -Returns 0 if OK, else -1. -This procedure is already prototyped in `crypto.h`. - -```c -int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privkeyblob, size_t privkeyblob_len, - const char *passphrase); -``` -Gets a private key from bytes at (`privkeyblob`, `privkeyblob_len`) and -extracts the public key --> (`pubkeydata`, `pubkeydata_len`). Store the -associated method (ssh-rsa or ssh-dss) into (`method`, `method_len`). +Gets a private key from file `privatekey`, or bytes at (`privkeyblob`, +`privkeyblob_len`) and extracts the public key --> (`pubkeydata`, +`pubkeydata_len`). Store the associated method (e.g., `ssh-rsa`, `ssh-ed25519`) +into (`method`, `method_len`). Both buffers have to be allocated using `SSH2_ALLOC()`. Returns 0 if OK, else -1. This procedure is already prototyped in `crypto.h`. @@ -478,23 +466,14 @@ key parameters): unless used internally by the backend, it is not needed to support the private key and the other parameters here. ```c -int ssh2_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase); +int ssh2_rsa_new_priv(ssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase); ``` -Reads an RSA private key from file `filename` into a new RSA context. -Must call `ssh2_init_if_needed()`. -Return 0 if OK, else -1. -This procedure is already prototyped in `crypto.h`. - -```c -int ssh2_rsa_new_priv_from_blob(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase); -``` -Gets an RSA private key from `blob` into a new RSA context. +Reads an RSA private key from file `filename`, or `blob` into a new RSA +context. Must call `ssh2_init_if_needed()`. Return 0 if OK, else -1. This procedure is already prototyped in `crypto.h`. @@ -618,23 +597,14 @@ Returns 0 if OK. This procedure is already prototyped in `crypto.h`. ```c -int ssh2_dsa_new_priv_from_file(ssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase); +int ssh2_dsa_new_priv(ssh2_dsa_ctx **dsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase); ``` -Gets a DSA private key from file `filename` into a new DSA context. -Must call `ssh2_init_if_needed()`. -Return 0 if OK, else -1. -This procedure is already prototyped in `crypto.h`. - -```c -int ssh2_dsa_new_priv_from_blob(ssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase); -``` -Gets a DSA private key from the `blob_len`-bytes `blob` into a new DSA context. +Reads a DSA private key from file `filename`, or `blob` into a new DSA +context. Must call `ssh2_init_if_needed()`. Returns 0 if OK, else -1. This procedure is already prototyped in `crypto.h`. @@ -694,24 +664,14 @@ Return 0 if OK, else -1. This procedure is already prototyped in `crypto.h`. ```c -int ssh2_ecdsa_new_priv_from_file(ssh2_ecdsa_ctx **ec_ctx, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase); +int ssh2_ecdsa_new_priv(ssh2_ecdsa_ctx **ec_ctx, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase); ``` -Reads an ECDSA private key from PEM file `filename` into a new ECDSA context. -Must call `ssh2_init_if_needed()`. -Return 0 if OK, else -1. -This procedure is already prototyped in `crypto.h`. - -```c -int ssh2_ecdsa_new_priv_from_blob(ssh2_ecdsa_ctx **ec_ctx, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase); -``` -Builds an ECDSA private key from PEM data at `blob` of length `blob_len` -into a new ECDSA context stored at `ec_ctx`. +Reads an ECDSA private key from file `filename`, or `blob` into a new ECDSA +context stored at `ec_ctx`. Must call `ssh2_init_if_needed()`. Return 0 if OK, else -1. This procedure is already prototyped in `crypto.h`. @@ -797,18 +757,6 @@ Key buffers are allocated and should be released by caller after use. Returns 0 if OK, else -1. This procedure is already prototyped in `crypto.h`. -```c -int ssh2_ed25519_new_priv_from_file(ssh2_ed25519_ctx **ed_ctx, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase); -``` -Reads an ED25519 private key from PEM file `filename` into a new ED25519 -context. -Must call `ssh2_init_if_needed()`. -Return 0 if OK, else -1. -This procedure is already prototyped in `crypto.h`. - ```c int ssh2_ed25519_new_public(ssh2_ed25519_ctx **ed_ctx, LIBSSH2_SESSION *session, @@ -821,13 +769,14 @@ Return 0 if OK, else -1. This procedure is already prototyped in `crypto.h`. ```c -int ssh2_ed25519_new_priv_from_blob(ssh2_ed25519_ctx **ed_ctx, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase); +int ssh2_ed25519_new_priv(ssh2_ed25519_ctx **ed_ctx, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase); ``` -Builds an ED25519 private key from PEM data at `blob` of length `blob_len` -into a new ED25519 context stored at `ed_ctx`. +Reads an ED25519 private key from file `filename`, or `blob` into a new ED25519 +context stored at `ed_ctx`. Must call `ssh2_init_if_needed()`. Return 0 if OK, else -1. This procedure is already prototyped in `crypto.h`. diff --git a/src/crypto.h b/src/crypto.h index 4ded0e7b..b4b429e9 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -133,14 +133,11 @@ int ssh2_rsa_new(ssh2_rsa_ctx **rsa, const unsigned char *e1data, size_t e1len, const unsigned char *e2data, size_t e2len, const unsigned char *coeffdata, size_t coefflen); -int ssh2_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase); -int ssh2_rsa_new_priv_from_blob(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase); +int ssh2_rsa_new_priv(ssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase); #if LIBSSH2_RSA_SHA1 int ssh2_rsa_sha1_sign(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session, const unsigned char *hash, size_t hash_len, @@ -169,14 +166,11 @@ int ssh2_dsa_new(ssh2_dsa_ctx **dsa, const unsigned char *gdata, size_t glen, const unsigned char *ydata, size_t ylen, const unsigned char *xdata, size_t xlen); -int ssh2_dsa_new_priv_from_file(ssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase); -int ssh2_dsa_new_priv_from_blob(ssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase); +int ssh2_dsa_new_priv(ssh2_dsa_ctx **dsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase); int ssh2_dsa_sha1_sign(ssh2_dsa_ctx *dsa, const unsigned char *hash, size_t hash_len, unsigned char *signature); @@ -210,14 +204,11 @@ int ssh2_ecdsa_curve_name_with_octal_new( const unsigned char *publickey_encoded, size_t publickey_encoded_len, ssh2_curve_type curve); -int ssh2_ecdsa_new_priv_from_file(ssh2_ecdsa_ctx **ec_ctx, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase); -int ssh2_ecdsa_new_priv_from_blob(ssh2_ecdsa_ctx **ec_ctx, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase); +int ssh2_ecdsa_new_priv(ssh2_ecdsa_ctx **ec_ctx, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase); int ssh2_ecdsa_sign(ssh2_ecdsa_ctx *ec_ctx, LIBSSH2_SESSION *session, const unsigned char *hash, size_t hash_len, @@ -246,14 +237,11 @@ int ssh2_ed25519_new_public(ssh2_ed25519_ctx **ed_ctx, const unsigned char *raw_pub_key, const size_t key_len); -int ssh2_ed25519_new_priv_from_file(ssh2_ed25519_ctx **ed_ctx, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase); -int ssh2_ed25519_new_priv_from_blob(ssh2_ed25519_ctx **ed_ctx, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase); +int ssh2_ed25519_new_priv(ssh2_ed25519_ctx **ed_ctx, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase); int ssh2_ed25519_sign(ssh2_ed25519_ctx *ed_ctx, LIBSSH2_SESSION *session, uint8_t **out_sig, size_t *out_sig_len, @@ -284,26 +272,22 @@ int ssh2_cipher_crypt(ssh2_cipher_ctx *ctx, SSH2_CIPHER_T(algo), void ssh2_cipher_dtor(ssh2_cipher_ctx *ctx); #endif -int ssh2_pub_privkey_file(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase); +int ssh2_pub_privkey(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + const char *privatekey, + const char *privkeyblob, size_t privkeyblob_len, + const char *passphrase); -int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privkeyblob, size_t privkeyblob_len, - const char *passphrase); - -int ssh2_sk_pubkey_blob(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - int *algorithm, unsigned char *flags, - const char **application, - const unsigned char **key_handle, size_t *handle_len, - const char *privkeyblob, size_t privkeyblob_len, - const char *passphrase); +int ssh2_sk_pubkey(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + int *algorithm, unsigned char *flags, + const char **application, + const unsigned char **key_handle, size_t *handle_len, + const char *privatekey, + const char *privkeyblob, size_t privkeyblob_len, + const char *passphrase); #ifndef ssh2_bn_ctx #define ssh2_bn_ctx int diff --git a/src/hostkey.c b/src/hostkey.c index 21d15926..e5d71f16 100644 --- a/src/hostkey.c +++ b/src/hostkey.c @@ -137,22 +137,15 @@ static int hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, void **abstract) { ssh2_rsa_ctx *rsa; - int rc; if(*abstract) { hostkey_method_ssh_rsa_dtor(session, abstract); *abstract = NULL; } - if(privkeyfile) - rc = ssh2_rsa_new_priv_from_file(&rsa, session, - privkeyfile, - passphrase); - else - rc = ssh2_rsa_new_priv_from_blob(&rsa, session, - privkeyblob, privkeyblob_len, - passphrase); - if(rc) + if(ssh2_rsa_new_priv(&rsa, session, + privkeyfile, privkeyblob, privkeyblob_len, + passphrase)) return -1; *abstract = rsa; @@ -495,22 +488,15 @@ static int hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, void **abstract) { ssh2_dsa_ctx *dsa; - int rc; if(*abstract) { hostkey_method_ssh_dss_dtor(session, abstract); *abstract = NULL; } - if(privkeyfile) - rc = ssh2_dsa_new_priv_from_file(&dsa, session, - privkeyfile, - passphrase); - else - rc = ssh2_dsa_new_priv_from_blob(&dsa, session, - privkeyblob, privkeyblob_len, - passphrase); - if(rc) + if(ssh2_dsa_new_priv(&dsa, session, + privkeyfile, privkeyblob, privkeyblob_len, + passphrase)) return -1; *abstract = dsa; @@ -702,22 +688,15 @@ static int hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION *session, void **abstract) { ssh2_ecdsa_ctx *ec_ctx = NULL; - int rc; if(abstract && *abstract) { hostkey_method_ssh_ecdsa_dtor(session, abstract); *abstract = NULL; } - if(privkeyfile) - rc = ssh2_ecdsa_new_priv_from_file(&ec_ctx, session, - privkeyfile, - passphrase); - else - rc = ssh2_ecdsa_new_priv_from_blob(&ec_ctx, session, - privkeyblob, privkeyblob_len, - passphrase); - if(rc) + if(ssh2_ecdsa_new_priv(&ec_ctx, session, + privkeyfile, privkeyblob, privkeyblob_len, + passphrase)) return -1; if(abstract) @@ -1017,22 +996,15 @@ static int hostkey_method_ssh_ed25519_initPEM(LIBSSH2_SESSION *session, void **abstract) { ssh2_ed25519_ctx *ed_ctx = NULL; - int rc; if(*abstract) { hostkey_method_ssh_ed25519_dtor(session, abstract); *abstract = NULL; } - if(privkeyfile) - rc = ssh2_ed25519_new_priv_from_file(&ed_ctx, session, - privkeyfile, - passphrase); - else - rc = ssh2_ed25519_new_priv_from_blob(&ed_ctx, session, - privkeyblob, privkeyblob_len, - passphrase); - if(rc) + if(ssh2_ed25519_new_priv(&ed_ctx, session, + privkeyfile, privkeyblob, privkeyblob_len, + passphrase)) return -1; *abstract = ed_ctx; diff --git a/src/libgcrypt.c b/src/libgcrypt.c index ed20401e..f5ba30c7 100644 --- a/src/libgcrypt.c +++ b/src/libgcrypt.c @@ -238,25 +238,11 @@ int ssh2_dsa_new(ssh2_dsa_ctx **dsa, #endif #if LIBSSH2_RSA -int ssh2_rsa_new_priv_from_blob(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) -{ - (void)rsa; - (void)blob; - (void)blob_len; - (void)passphrase; - - return ssh2_err(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unimplemented in libgcrypt backend"); -} - -int ssh2_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +int ssh2_rsa_new_priv(ssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) { FILE *fp; unsigned char *data, *save_data; @@ -265,13 +251,19 @@ int ssh2_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff; unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen; - fp = ssh2_fopen(filename, "rb"); - if(!fp) - return -1; - - ret = ssh2_pem_parse_FILE(session, PEM_RSA_HEADER, PEM_RSA_FOOTER, - fp, passphrase, &data, &datalen); - fclose(fp); + if(filename) { + fp = ssh2_fopen(filename, "rb"); + if(!fp) + return -1; + ret = ssh2_pem_parse_FILE(session, PEM_RSA_HEADER, PEM_RSA_FOOTER, + fp, passphrase, + &data, &datalen); + fclose(fp); + } + else + ret = ssh2_pem_parse_blob(session, PEM_RSA_HEADER, PEM_RSA_FOOTER, + blob, blob_len, passphrase, + &data, &datalen); if(ret) return -1; @@ -352,25 +344,11 @@ fail: #endif #if LIBSSH2_DSA -int ssh2_dsa_new_priv_from_blob(ssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) -{ - (void)dsa; - (void)blob; - (void)blob_len; - (void)passphrase; - - return ssh2_err(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unimplemented in libgcrypt backend"); -} - -int ssh2_dsa_new_priv_from_file(ssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +int ssh2_dsa_new_priv(ssh2_dsa_ctx **dsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) { FILE *fp; unsigned char *data, *save_data; @@ -379,13 +357,20 @@ int ssh2_dsa_new_priv_from_file(ssh2_dsa_ctx **dsa, unsigned char *p, *q, *g, *y, *x; unsigned int plen, qlen, glen, ylen, xlen; - fp = ssh2_fopen(filename, "rb"); - if(!fp) - return -1; + if(filename) { + fp = ssh2_fopen(filename, "rb"); + if(!fp) + return -1; - ret = ssh2_pem_parse_FILE(session, PEM_DSA_HEADER, PEM_DSA_FOOTER, - fp, passphrase, &data, &datalen); - fclose(fp); + ret = ssh2_pem_parse_FILE(session, PEM_DSA_HEADER, PEM_DSA_FOOTER, + fp, passphrase, + &data, &datalen); + fclose(fp); + } + else + ret = ssh2_pem_parse_blob(session, PEM_DSA_HEADER, PEM_DSA_FOOTER, + blob, blob_len, passphrase, + &data, &datalen); if(ret) return -1; @@ -696,41 +681,25 @@ int ssh2_cipher_crypt(ssh2_cipher_ctx *ctx, return ret; } -int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privkeyblob, size_t privkeyblob_len, - const char *passphrase) -{ - (void)method; - (void)method_len; - (void)pubkeydata; - (void)pubkeydata_len; - (void)privkeyblob; - (void)privkeyblob_len; - (void)passphrase; - - return ssh2_err(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract public key from private key in " - "memory: Method unimplemented in libgcrypt backend"); -} - -int ssh2_pub_privkey_file(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) +int ssh2_pub_privkey(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + const char *privatekey, + const char *privkeyblob, size_t privkeyblob_len, + const char *passphrase) { (void)method; (void)method_len; (void)pubkeydata; (void)pubkeydata_len; (void)privatekey; + (void)privkeyblob; + (void)privkeyblob_len; (void)passphrase; - return ssh2_err(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key " - "file: Method unimplemented in libgcrypt backend"); + return ssh2_err(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Unable to extract public key from private key: " + "Method unimplemented in libgcrypt backend"); } void ssh2_dh_init(ssh2_dh_ctx *dhctx) diff --git a/src/mbedtls.c b/src/mbedtls.c index 4efb157e..f84a55bd 100644 --- a/src/mbedtls.c +++ b/src/mbedtls.c @@ -354,14 +354,16 @@ int ssh2_rsa_new(ssh2_rsa_ctx **rsa, return ret; } -int ssh2_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +int ssh2_rsa_new_priv(ssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) { int ret; mbedtls_pk_context pkey; mbedtls_rsa_context *pk_rsa; + unsigned char *data_nullterm = NULL; (void)session; @@ -370,61 +372,35 @@ int ssh2_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, return -1; mbedtls_rsa_init(*rsa); + + if(!filename) { + /* mbedtls checks in "mbedtls/pkparse.c:1184" + if "key[keylen - 1] != '\0'" + private-key from memory fails if the last byte is not a null byte */ + data_nullterm = mbedtls_calloc(blob_len + 1, 1); + if(!data_nullterm) { + ssh2_rsa_free(*rsa); + *rsa = NULL; + return -1; + } + + memcpy(data_nullterm, blob, blob_len); + data_nullterm[blob_len] = 0; + } + mbedtls_pk_init(&pkey); - ret = mbedtls_pk_parse_keyfile(&pkey, filename, passphrase, + if(!filename) { + ret = mbedtls_pk_parse_key(&pkey, data_nullterm, blob_len + 1, + (const unsigned char *)passphrase, + passphrase ? strlen(passphrase) : 0, mbedtls_ctr_drbg_random, &mbed_ctr_drbg); - if(ret || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) { - mbedtls_pk_free(&pkey); - ssh2_rsa_free(*rsa); - *rsa = NULL; - return -1; + mbed_zero_free(data_nullterm, blob_len + 1); } - - pk_rsa = mbedtls_pk_rsa(pkey); - mbedtls_rsa_copy(*rsa, pk_rsa); - mbedtls_pk_free(&pkey); - - return 0; -} - -int ssh2_rsa_new_priv_from_blob(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) -{ - int ret; - mbedtls_pk_context pkey; - mbedtls_rsa_context *pk_rsa; - unsigned char *data_nullterm; - - (void)session; - - *rsa = mbedtls_calloc(1, sizeof(ssh2_rsa_ctx)); - if(!*rsa) - return -1; - - mbedtls_rsa_init(*rsa); - - /* mbedtls checks in "mbedtls/pkparse.c:1184" if "key[keylen - 1] != '\0'" - private-key from memory fails if the last byte is not a null byte */ - data_nullterm = mbedtls_calloc(blob_len + 1, 1); - if(!data_nullterm) { - ssh2_rsa_free(*rsa); - *rsa = NULL; - return -1; - } - - memcpy(data_nullterm, blob, blob_len); - data_nullterm[blob_len] = 0; - - mbedtls_pk_init(&pkey); - - ret = mbedtls_pk_parse_key(&pkey, data_nullterm, blob_len + 1, - (const unsigned char *)passphrase, - passphrase ? strlen(passphrase) : 0, - mbedtls_ctr_drbg_random, &mbed_ctr_drbg); - mbed_zero_free(data_nullterm, blob_len + 1); + else + ret = mbedtls_pk_parse_keyfile(&pkey, filename, passphrase, + mbedtls_ctr_drbg_random, + &mbed_ctr_drbg); if(ret || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) { mbedtls_pk_free(&pkey); @@ -645,61 +621,43 @@ static int mbed_pub_priv_key(LIBSSH2_SESSION *session, return ret; } -int ssh2_pub_privkey_file(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) +int ssh2_pub_privkey(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + const char *privatekey, + const char *privkeyblob, size_t privkeyblob_len, + const char *passphrase) { mbedtls_pk_context pkey; char buf[1024]; int ret; + unsigned char *data_nullterm = NULL; - mbedtls_pk_init(&pkey); - ret = mbedtls_pk_parse_keyfile(&pkey, privatekey, passphrase, - mbedtls_ctr_drbg_random, &mbed_ctr_drbg); - if(ret) { - mbedtls_strerror(ret, (char *)buf, sizeof(buf)); - mbedtls_pk_free(&pkey); - return ssh2_err_flags(session, LIBSSH2_ERROR_FILE, buf, - SSH2_ERR_FLAG_DUP); + if(!privatekey) { + /* mbedtls checks in "mbedtls/pkparse.c:1184" + if "key[keylen - 1] != '\0'" + private-key from memory fails if the last byte is not a null byte */ + data_nullterm = mbedtls_calloc(privkeyblob_len + 1, 1); + if(!data_nullterm) + return -1; + + memcpy(data_nullterm, privkeyblob, privkeyblob_len); + data_nullterm[privkeyblob_len] = 0; } - ret = mbed_pub_priv_key(session, method, method_len, - pubkeydata, pubkeydata_len, &pkey); - - mbedtls_pk_free(&pkey); - - return ret; -} - -int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privkeyblob, size_t privkeyblob_len, - const char *passphrase) -{ - mbedtls_pk_context pkey; - char buf[1024]; - int ret; - unsigned char *data_nullterm; - - /* mbedtls checks in "mbedtls/pkparse.c:1184" if "key[keylen - 1] != '\0'" - private-key from memory fails if the last byte is not a null byte */ - data_nullterm = mbedtls_calloc(privkeyblob_len + 1, 1); - if(!data_nullterm) - return -1; - - memcpy(data_nullterm, privkeyblob, privkeyblob_len); - data_nullterm[privkeyblob_len] = 0; - mbedtls_pk_init(&pkey); - ret = mbedtls_pk_parse_key(&pkey, data_nullterm, privkeyblob_len + 1, - (const unsigned char *)passphrase, - passphrase ? strlen(passphrase) : 0, - mbedtls_ctr_drbg_random, &mbed_ctr_drbg); - mbed_zero_free(data_nullterm, privkeyblob_len + 1); + if(!privatekey) { + ret = mbedtls_pk_parse_key(&pkey, data_nullterm, privkeyblob_len + 1, + (const unsigned char *)passphrase, + passphrase ? strlen(passphrase) : 0, + mbedtls_ctr_drbg_random, &mbed_ctr_drbg); + mbed_zero_free(data_nullterm, privkeyblob_len + 1); + } + else + ret = mbedtls_pk_parse_keyfile(&pkey, privatekey, passphrase, + mbedtls_ctr_drbg_random, + &mbed_ctr_drbg); if(ret) { mbedtls_strerror(ret, (char *)buf, sizeof(buf)); @@ -997,10 +955,11 @@ cleanup: } static int mbed_parse_eckey(ssh2_ecdsa_ctx **ctx, mbedtls_pk_context *pkey, - const unsigned char *data, size_t data_len, + const char *data, size_t data_len, const char *passphrase) { - if(mbedtls_pk_parse_key(pkey, data, data_len, + if(mbedtls_pk_parse_key(pkey, + (const unsigned char *)data, data_len, (const unsigned char *)passphrase, passphrase ? strlen(passphrase) : 0, mbedtls_ctr_drbg_random, &mbed_ctr_drbg)) @@ -1062,8 +1021,7 @@ static int mbed_ecdsa_curve_type_from_name(const char *name, static int mbed_parse_openssh_key(ssh2_ecdsa_ctx **ctx, LIBSSH2_SESSION *session, - const unsigned char *data, - size_t data_len, + const char *data, size_t data_len, const char *passphrase) { ssh2_curve_type type; @@ -1072,8 +1030,7 @@ static int mbed_parse_openssh_key(ssh2_ecdsa_ctx **ctx, size_t curvelen, exponentlen, pointlen; unsigned char *curve, *exponent, *point_buf; - if(ssh2_openssh_pem_parse_blob(session, - (const char *)data, data_len, + if(ssh2_openssh_pem_parse_blob(session, data, data_len, passphrase, &decrypted)) goto failed; @@ -1131,39 +1088,49 @@ cleanup: } /* - * Creates a new private key given a file path and password + * Creates a new private key given a file/blob and password */ -int ssh2_ecdsa_new_priv_from_file(ssh2_ecdsa_ctx **ec_ctx, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +int ssh2_ecdsa_new_priv(ssh2_ecdsa_ctx **ec_ctx, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) { mbedtls_pk_context pkey; - unsigned char *data = NULL; + char *data = NULL; size_t data_len = 0; FILE *fp = NULL; - long file_size; mbedtls_pk_init(&pkey); - fp = ssh2_fopen(filename, "rb"); - if(!fp) - goto cleanup; - if(fseek(fp, 0, SEEK_END)) - goto cleanup; - file_size = ftell(fp); - if(file_size < 0 || file_size > (1024 * 1024)) - goto cleanup; - if(fseek(fp, 0, SEEK_SET)) - goto cleanup; - data_len = (size_t)file_size; - if(data_len == 0) - goto cleanup; - data = SSH2_ALLOC(session, data_len + 1); - if(!data) - goto cleanup; - if(fread(data, 1, data_len, fp) != data_len) - goto cleanup; + if(filename) { + long file_size; + fp = ssh2_fopen(filename, "rb"); + if(!fp) + goto cleanup; + if(fseek(fp, 0, SEEK_END)) + goto cleanup; + file_size = ftell(fp); + if(file_size < 0 || file_size > (1024 * 1024)) + goto cleanup; + if(fseek(fp, 0, SEEK_SET)) + goto cleanup; + data_len = (size_t)file_size; + if(data_len == 0) + goto cleanup; + data = mbedtls_calloc(1, data_len + 1); + if(!data) + goto cleanup; + if(fread(data, 1, data_len, fp) != data_len) + goto cleanup; + } + else { + data_len = blob_len; + data = mbedtls_calloc(1, data_len + 1); + if(!data) + goto cleanup; + memcpy(data, blob, blob_len); + } data[data_len] = 0; /* for mbedtls_pk_parse_key() */ if(mbed_parse_eckey(ec_ctx, &pkey, data, data_len + 1, passphrase) == 0) @@ -1175,54 +1142,13 @@ cleanup: if(fp) fclose(fp); - if(data) { - ssh2_explicit_zero(data, data_len + 1); - SSH2_FREE(session, data); - } + mbed_zero_free(data, data_len + 1); mbedtls_pk_free(&pkey); return *ec_ctx ? 0 : -1; } -/* - * Creates a new private key given a file data and password - */ -int ssh2_ecdsa_new_priv_from_blob(ssh2_ecdsa_ctx **ec_ctx, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) -{ - unsigned char *data_nullterm; - mbedtls_pk_context pkey; - - (void)session; - - mbedtls_pk_init(&pkey); - - data_nullterm = mbedtls_calloc(1, blob_len + 1); - if(!data_nullterm) - goto cleanup; - - memcpy(data_nullterm, blob, blob_len); - data_nullterm[blob_len] = 0; - - if(mbed_parse_eckey(ec_ctx, &pkey, data_nullterm, blob_len + 1, - passphrase) == 0) - goto cleanup; - - mbed_parse_openssh_key(ec_ctx, session, data_nullterm, blob_len + 1, - passphrase); - -cleanup: - - mbedtls_pk_free(&pkey); - - mbed_zero_free(data_nullterm, blob_len + 1); - - return *ec_ctx ? 0 : -1; -} - static unsigned char *mbed_write_bn(unsigned char *buf, const mbedtls_mpi *bn, size_t bn_size) { diff --git a/src/misc.c b/src/misc.c index a48d5ee6..80154021 100644 --- a/src/misc.c +++ b/src/misc.c @@ -999,14 +999,15 @@ int ssh2_timingsafe_bcmp(const void *b1, const void *b2, size_t n) } #ifndef LIBSSH2_KEY_SK -int ssh2_sk_pubkey_blob(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - int *algorithm, unsigned char *flags, - const char **application, - const unsigned char **key_handle, size_t *handle_len, - const char *privkeyblob, size_t privkeyblob_len, - const char *passphrase) +int ssh2_sk_pubkey(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + int *algorithm, unsigned char *flags, + const char **application, + const unsigned char **key_handle, size_t *handle_len, + const char *privatekey, + const char *privkeyblob, size_t privkeyblob_len, + const char *passphrase) { (void)method; (void)method_len; @@ -1017,12 +1018,13 @@ int ssh2_sk_pubkey_blob(LIBSSH2_SESSION *session, (void)application; (void)key_handle; (void)handle_len; + (void)privatekey; (void)privkeyblob; (void)privkeyblob_len; (void)passphrase; return ssh2_err(session, LIBSSH2_ERROR_FILE, - "Unable to extract public SK key from private key file: " + "Unable to extract public SK key from private key: " "Method unimplemented in " SSH2_CRYPTO_ENGINE_NAME " backend"); } diff --git a/src/openssl.c b/src/openssl.c index 337e4370..5dfc89e5 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -1049,34 +1049,6 @@ static int ossl_passphrase_cb(char *buf, int size, int rwflag, #endif /* LIBSSH2_RSA || LIBSSH2_DSA || LIBSSH2_ECDSA || LIBSSH2_ED25519 */ #if LIBSSH2_RSA -int ssh2_rsa_new_priv_from_blob(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) -{ - int rc = 0; - BIO *bp; - - OSSL_INIT_IF_NEEDED(); - - bp = BIO_new_mem_buf(blob, (int)blob_len); - if(bp) -#ifdef USE_OPENSSL_3 - *rsa = PEM_read_bio_PrivateKey(bp, NULL, ossl_passphrase_cb, - SSH2_UNCONST(passphrase)); -#else - *rsa = PEM_read_bio_RSAPrivateKey(bp, NULL, ossl_passphrase_cb, - SSH2_UNCONST(passphrase)); -#endif - BIO_free(bp); - - if(!*rsa) - rc = ossl_key_from_openssh_blob(session, (void **)rsa, "ssh-rsa", - NULL, NULL, NULL, NULL, - blob, blob_len, passphrase); - return rc; -} - static unsigned char *ossl_rsa_to_pubkey(LIBSSH2_SESSION *session, ssh2_rsa_ctx *rsa, size_t *key_len) { @@ -1373,7 +1345,7 @@ static int ossl_rsa_openssh_priv_new(ssh2_rsa_ctx **rsa, if(rc) return rc; - /* We have a new key file, now try and parse it using supported types */ + /* We have a new key file, now try and parse it using supported types */ rc = ssh2_get_string(decrypted, &buf, NULL); if(rc || !buf) { ssh2_err(session, LIBSSH2_ERROR_PROTO, @@ -1396,17 +1368,23 @@ cleanup: return rc; } -int ssh2_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +int ssh2_rsa_new_priv(ssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) { int rc = 0; BIO *bp; OSSL_INIT_IF_NEEDED(); - bp = BIO_new_file(filename, "r"); + *rsa = NULL; + + if(filename) + bp = BIO_new_file(filename, "r"); + else + bp = BIO_new_mem_buf(blob, (int)blob_len); if(bp) #ifdef USE_OPENSSL_3 *rsa = PEM_read_bio_PrivateKey(bp, NULL, ossl_passphrase_cb, @@ -1417,42 +1395,20 @@ int ssh2_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, #endif BIO_free(bp); - if(!*rsa) - rc = ossl_rsa_openssh_priv_new(rsa, session, filename, passphrase); + if(!*rsa) { + if(filename) + rc = ossl_rsa_openssh_priv_new(rsa, session, filename, passphrase); + else + rc = ossl_key_from_openssh_blob(session, (void **)rsa, "ssh-rsa", + NULL, NULL, NULL, NULL, + blob, blob_len, passphrase); + } return rc; } #endif #if LIBSSH2_DSA -int ssh2_dsa_new_priv_from_blob(ssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) -{ - int rc = 0; - BIO *bp; - - OSSL_INIT_IF_NEEDED(); - - bp = BIO_new_mem_buf(blob, (int)blob_len); - if(bp) -#ifdef USE_OPENSSL_3 - *dsa = PEM_read_bio_PrivateKey(bp, NULL, ossl_passphrase_cb, - SSH2_UNCONST(passphrase)); -#else - *dsa = PEM_read_bio_DSAPrivateKey(bp, NULL, ossl_passphrase_cb, - SSH2_UNCONST(passphrase)); -#endif - BIO_free(bp); - - if(!*dsa) - rc = ossl_key_from_openssh_blob(session, (void **)dsa, "ssh-dsa", - NULL, NULL, NULL, NULL, - blob, blob_len, passphrase); - return rc; -} - static unsigned char *ossl_dsa_to_pubkey(LIBSSH2_SESSION *session, ssh2_dsa_ctx *dsa, size_t *key_len) { @@ -1682,7 +1638,7 @@ static int ossl_dsa_openssh_priv_new(ssh2_dsa_ctx **dsa, if(rc) return rc; - /* We have a new key file, now try and parse it using supported types */ + /* We have a new key file, now try and parse it using supported types */ rc = ssh2_get_string(decrypted, &buf, NULL); if(rc || !buf) { ssh2_err(session, LIBSSH2_ERROR_PROTO, @@ -1705,17 +1661,23 @@ cleanup: return rc; } -int ssh2_dsa_new_priv_from_file(ssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +int ssh2_dsa_new_priv(ssh2_dsa_ctx **dsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) { int rc = 0; BIO *bp; OSSL_INIT_IF_NEEDED(); - bp = BIO_new_file(filename, "r"); + *dsa = NULL; + + if(filename) + bp = BIO_new_file(filename, "r"); + else + bp = BIO_new_mem_buf(blob, (int)blob_len); if(bp) #ifdef USE_OPENSSL_3 *dsa = PEM_read_bio_PrivateKey(bp, NULL, ossl_passphrase_cb, @@ -1726,43 +1688,19 @@ int ssh2_dsa_new_priv_from_file(ssh2_dsa_ctx **dsa, #endif BIO_free(bp); - if(!*dsa) - rc = ossl_dsa_openssh_priv_new(dsa, session, filename, passphrase); + if(!*dsa) { + if(filename) + rc = ossl_dsa_openssh_priv_new(dsa, session, filename, passphrase); + else + rc = ossl_key_from_openssh_blob(session, (void **)dsa, "ssh-dsa", + NULL, NULL, NULL, NULL, + blob, blob_len, passphrase); + } return rc; } #endif /* LIBSSH2_DSA */ -#if LIBSSH2_ECDSA -int ssh2_ecdsa_new_priv_from_blob(ssh2_ecdsa_ctx **ec_ctx, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) -{ - int rc = 0; - BIO *bp; - - OSSL_INIT_IF_NEEDED(); - - bp = BIO_new_mem_buf(blob, (int)blob_len); - if(bp) -#ifdef USE_OPENSSL_3 - *ec_ctx = PEM_read_bio_PrivateKey(bp, NULL, ossl_passphrase_cb, - SSH2_UNCONST(passphrase)); -#else - *ec_ctx = PEM_read_bio_ECPrivateKey(bp, NULL, ossl_passphrase_cb, - SSH2_UNCONST(passphrase)); -#endif - BIO_free(bp); - - if(!*ec_ctx) - rc = ossl_key_from_openssh_blob(session, (void **)ec_ctx, "ssh-ecdsa", - NULL, NULL, NULL, NULL, - blob, blob_len, passphrase); - return rc; -} -#endif /* LIBSSH2_ECDSA */ - #if LIBSSH2_ED25519 int ssh2_curve25519_new(LIBSSH2_SESSION *session, @@ -2164,15 +2102,12 @@ clean_exit: return -1; } -int ssh2_ed25519_new_priv_from_file(ssh2_ed25519_ctx **ed_ctx, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +int ssh2_ed25519_new_priv(ssh2_ed25519_ctx **ed_ctx, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) { - int rc; - FILE *fp; - unsigned char *buf; - struct string_buf *decrypted = NULL; ssh2_ed25519_ctx *ctx = NULL; if(!session) @@ -2180,78 +2115,81 @@ int ssh2_ed25519_new_priv_from_file(ssh2_ed25519_ctx **ed_ctx, OSSL_INIT_IF_NEEDED(); - fp = ssh2_fopen(filename, "r"); - if(!fp) { - ssh2_err(session, LIBSSH2_ERROR_FILE, - "Unable to open ED25519 private key file"); - return -1; - } + if(filename) { + int rc; + FILE *fp; + unsigned char *buf; + struct string_buf *decrypted = NULL; - rc = ssh2_openssh_pem_parse_FILE(session, fp, passphrase, &decrypted); - fclose(fp); - if(rc) - return rc; + fp = ssh2_fopen(filename, "r"); + if(!fp) { + ssh2_err(session, LIBSSH2_ERROR_FILE, + "Unable to open ED25519 private key file"); + return -1; + } - /* We have a new key file, now try and parse it using supported types */ - rc = ssh2_get_string(decrypted, &buf, NULL); - if(rc || !buf) { - ssh2_err(session, LIBSSH2_ERROR_PROTO, - "Public key type in decrypted key data not found"); - rc = -1; - goto cleanup; - } + rc = ssh2_openssh_pem_parse_FILE(session, fp, passphrase, &decrypted); + fclose(fp); + if(rc) + return rc; - if(!strcmp("ssh-ed25519", (const char *)buf)) - rc = ossl_ed25519_openssh_priv_to_pubkey(session, decrypted, - NULL, NULL, NULL, NULL, &ctx); - else - rc = -1; + /* We have a new key file, now try and parse it using supported + types */ + rc = ssh2_get_string(decrypted, &buf, NULL); + if(rc || !buf) { + ssh2_err(session, LIBSSH2_ERROR_PROTO, + "Public key type in decrypted key data not found"); + rc = -1; + goto cleanup; + } - if(rc == 0) { - if(ed_ctx) - *ed_ctx = ctx; - else if(ctx) - ssh2_ed25519_free(ctx); - } + if(!strcmp("ssh-ed25519", (const char *)buf)) + rc = ossl_ed25519_openssh_priv_to_pubkey(session, decrypted, + NULL, NULL, NULL, NULL, + &ctx); + else + rc = -1; + + if(rc == 0) { + if(ed_ctx) + *ed_ctx = ctx; + else if(ctx) + ssh2_ed25519_free(ctx); + } cleanup: - if(decrypted) - ssh2_string_buf_free(session, decrypted); + if(decrypted) + ssh2_string_buf_free(session, decrypted); - return rc; -} - -int ssh2_ed25519_new_priv_from_blob(ssh2_ed25519_ctx **ed_ctx, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) -{ - ssh2_ed25519_ctx *ctx = NULL; - BIO *bp; - - OSSL_INIT_IF_NEEDED(); - - bp = BIO_new_mem_buf(blob, (int)blob_len); - if(bp) { - ctx = PEM_read_bio_PrivateKey(bp, NULL, ossl_passphrase_cb, - SSH2_UNCONST(passphrase)); - BIO_free(bp); - if(ctx) { - if(EVP_PKEY_id(ctx) != EVP_PKEY_ED25519) { - ssh2_ed25519_free(ctx); - return ssh2_err(session, LIBSSH2_ERROR_PROTO, - "Private key is not an ED25519 key"); - } - - *ed_ctx = ctx; - return 0; - } + return rc; } + else { + BIO *bp = BIO_new_mem_buf(blob, (int)blob_len); + if(bp) { + ctx = PEM_read_bio_PrivateKey(bp, NULL, ossl_passphrase_cb, + SSH2_UNCONST(passphrase)); + BIO_free(bp); + if(ctx) { + if(EVP_PKEY_id(ctx) != EVP_PKEY_ED25519) { + ssh2_ed25519_free(ctx); + return ssh2_err(session, LIBSSH2_ERROR_PROTO, + "Private key is not an ED25519 key"); + } - return ossl_key_from_openssh_blob(session, (void **)ed_ctx, "ssh-ed25519", - NULL, NULL, NULL, NULL, - blob, blob_len, passphrase); + if(ed_ctx) + *ed_ctx = ctx; + else + ssh2_ed25519_free(ctx); + return 0; + } + } + + return ossl_key_from_openssh_blob(session, + (void **)ed_ctx, "ssh-ed25519", + NULL, NULL, NULL, NULL, + blob, blob_len, passphrase); + } } int ssh2_ed25519_new_public(ssh2_ed25519_ctx **ed_ctx, @@ -3140,7 +3078,7 @@ static int ossl_ecdsa_openssh_priv_new(ssh2_ecdsa_ctx **ec_ctx, if(rc) return rc; - /* We have a new key file, now try and parse it using supported types */ + /* We have a new key file, now try and parse it using supported types */ rc = ssh2_get_string(decrypted, &buf, NULL); if(rc || !buf) { ssh2_err(session, LIBSSH2_ERROR_PROTO, @@ -3165,17 +3103,23 @@ cleanup: return rc; } -int ssh2_ecdsa_new_priv_from_file(ssh2_ecdsa_ctx **ec_ctx, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +int ssh2_ecdsa_new_priv(ssh2_ecdsa_ctx **ec_ctx, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) { int rc = 0; BIO *bp; OSSL_INIT_IF_NEEDED(); - bp = BIO_new_file(filename, "r"); + *ec_ctx = NULL; + + if(filename) + bp = BIO_new_file(filename, "r"); + else + bp = BIO_new_mem_buf(blob, (int)blob_len); if(bp) #ifdef USE_OPENSSL_3 *ec_ctx = PEM_read_bio_PrivateKey(bp, NULL, ossl_passphrase_cb, @@ -3186,9 +3130,16 @@ int ssh2_ecdsa_new_priv_from_file(ssh2_ecdsa_ctx **ec_ctx, #endif BIO_free(bp); - if(!*ec_ctx) - rc = ossl_ecdsa_openssh_priv_new(ec_ctx, session, filename, - passphrase); + if(!*ec_ctx) { + if(filename) + rc = ossl_ecdsa_openssh_priv_new(ec_ctx, session, filename, + passphrase); + else + rc = ossl_key_from_openssh_blob(session, + (void **)ec_ctx, "ssh-ecdsa", + NULL, NULL, NULL, NULL, + blob, blob_len, passphrase); + } return rc; } @@ -3659,14 +3610,13 @@ static int ossl_key_from_openssh_file(LIBSSH2_SESSION *session, } rc = ssh2_openssh_pem_parse_FILE(session, fp, passphrase, &decrypted); - fclose(fp); if(rc) { ssh2_err(session, LIBSSH2_ERROR_FILE, "Not an OpenSSH key file"); return rc; } - /* We have a new key file, now try and parse it using supported types */ + /* We have a new key file, now try and parse it using supported types */ rc = ssh2_get_string(decrypted, &buf, NULL); if(rc || !buf) { ssh2_err(session, LIBSSH2_ERROR_PROTO, @@ -3723,82 +3673,6 @@ cleanup: return rc; } -int ssh2_pub_privkey_file(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ - BIO *bp; - EVP_PKEY *pk; - int pktype; - int rc; - - ssh2_deb((session, LIBSSH2_TRACE_AUTH, - "Computing public key from private key file: %s", privatekey)); - - bp = BIO_new_file(privatekey, "r"); - if(!bp) - return ssh2_err(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key file: " - "Unable to open private key file"); - - (void)BIO_reset(bp); - pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, SSH2_UNCONST(passphrase)); - BIO_free(bp); - - if(!pk) { - /* Try OpenSSH format */ - rc = ossl_key_from_openssh_file(session, method, method_len, - pubkeydata, pubkeydata_len, - privatekey, passphrase); - if(rc) - return ssh2_err(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key file: " - "Wrong passphrase or invalid/unrecognized " - "private key file format"); - return 0; - } - - pktype = EVP_PKEY_id(pk); - - switch(pktype) { -#if LIBSSH2_ED25519 - case EVP_PKEY_ED25519: - rc = ossl_ed25519_evp_to_pubkey(session, method, method_len, - pubkeydata, pubkeydata_len, pk); - break; -#endif /* LIBSSH2_ED25519 */ -#if LIBSSH2_RSA - case EVP_PKEY_RSA: - rc = ossl_rsa_evp_to_pubkey(session, method, method_len, - pubkeydata, pubkeydata_len, pk); - break; -#endif /* LIBSSH2_RSA */ -#if LIBSSH2_DSA - case EVP_PKEY_DSA: - rc = ossl_dsa_evp_to_pubkey(session, method, method_len, - pubkeydata, pubkeydata_len, pk); - break; -#endif /* LIBSSH2_DSA */ -#if LIBSSH2_ECDSA - case EVP_PKEY_EC: - rc = ossl_ecdsa_evp_to_pubkey(session, method, method_len, - pubkeydata, pubkeydata_len, 0, pk); - break; -#endif /* LIBSSH2_ECDSA */ - default: - rc = ssh2_err(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key file: " - "Unsupported private key file format"); - break; - } - - EVP_PKEY_free(pk); - return rc; -} - static int ossl_key_from_openssh_blob(LIBSSH2_SESSION *session, void **key_ctx, const char *want_method, @@ -3827,14 +3701,13 @@ static int ossl_key_from_openssh_blob(LIBSSH2_SESSION *session, OSSL_INIT_IF_NEEDED(); - rc = ssh2_openssh_pem_parse_blob(session, - privkeyblob, privkeyblob_len, + rc = ssh2_openssh_pem_parse_blob(session, privkeyblob, privkeyblob_len, passphrase, &decrypted); if(rc) return rc; - /* We have a new key file, now try and parse it using supported types */ + /* We have a new key file, now try and parse it using supported types */ rc = ssh2_get_string(decrypted, &buf, NULL); if(rc || !buf) { rc = ssh2_err(session, LIBSSH2_ERROR_PROTO, @@ -3899,8 +3772,8 @@ static int ossl_key_from_openssh_blob(LIBSSH2_SESSION *session, if(rc == LIBSSH2_ERROR_FILE) rc = ssh2_err(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key file: " - "invalid/unrecognized private key file format"); + "Unable to extract public key from private key: " + "invalid/unrecognized private key format"); cleanup: @@ -3910,14 +3783,15 @@ cleanup: return rc; } -int ssh2_sk_pubkey_blob(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - int *algorithm, unsigned char *flags, - const char **application, - const unsigned char **key_handle, size_t *handle_len, - const char *privkeyblob, size_t privkeyblob_len, - const char *passphrase) +int ssh2_sk_pubkey(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + int *algorithm, unsigned char *flags, + const char **application, + const unsigned char **key_handle, size_t *handle_len, + const char *privatekey, + const char *privkeyblob, size_t privkeyblob_len, + const char *passphrase) { int rc; unsigned char *buf = NULL; @@ -3931,14 +3805,22 @@ int ssh2_sk_pubkey_blob(LIBSSH2_SESSION *session, OSSL_INIT_IF_NEEDED(); - rc = ssh2_openssh_pem_parse_blob(session, - privkeyblob, privkeyblob_len, - passphrase, - &decrypted); + if(privatekey) { + FILE *fp = ssh2_fopen(privatekey, "rb"); + if(!fp) + return ssh2_err(session, LIBSSH2_ERROR_FILE, + "Opening the private key failed"); + rc = ssh2_openssh_pem_parse_FILE(session, fp, passphrase, &decrypted); + fclose(fp); + } + else + rc = ssh2_openssh_pem_parse_blob(session, privkeyblob, privkeyblob_len, + passphrase, + &decrypted); if(rc) return rc; - /* We have a new key file, now try and parse it using supported types */ + /* We have a new key file, now try and parse it using supported types */ rc = ssh2_get_string(decrypted, &buf, NULL); if(rc || !buf) { rc = ssh2_err(session, LIBSSH2_ERROR_PROTO, @@ -3985,8 +3867,8 @@ int ssh2_sk_pubkey_blob(LIBSSH2_SESSION *session, if(rc == LIBSSH2_ERROR_FILE) rc = ssh2_err(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key file: " - "invalid/unrecognized private key file format"); + "Unable to extract public key from private key: " + "invalid/unrecognized private key format"); cleanup: @@ -4000,12 +3882,12 @@ cleanup: #define HAVE_SSLERROR_BAD_DECRYPT #endif -int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privkeyblob, - size_t privkeyblob_len, - const char *passphrase) +int ssh2_pub_privkey(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + const char *privatekey, + const char *privkeyblob, size_t privkeyblob_len, + const char *passphrase) { int rc; BIO *bp; @@ -4015,13 +3897,29 @@ int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, unsigned long sslError; #endif - ssh2_deb((session, LIBSSH2_TRACE_AUTH, - "Computing public key from private key.")); + OSSL_INIT_IF_NEEDED(); + + if(privatekey) { + ssh2_deb((session, LIBSSH2_TRACE_AUTH, + "Computing public key from private key file: %s", + privatekey)); + + bp = BIO_new_file(privatekey, "r"); + if(!bp) + return ssh2_err(session, LIBSSH2_ERROR_FILE, + "Unable to open private key file"); + } + else { + ssh2_deb((session, LIBSSH2_TRACE_AUTH, + "Computing public key from private key.")); + + bp = BIO_new_mem_buf(privkeyblob, (int)privkeyblob_len); + if(!bp) + return ssh2_err(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory when computing " + "public key"); + } - bp = BIO_new_mem_buf(privkeyblob, (int)privkeyblob_len); - if(!bp) - return ssh2_err(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory when computing public key"); (void)BIO_reset(bp); pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, SSH2_UNCONST(passphrase)); #ifdef HAVE_SSLERROR_BAD_DECRYPT @@ -4031,11 +3929,18 @@ int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, if(!pk) { /* Try OpenSSH format */ - rc = ossl_key_from_openssh_blob(session, NULL, NULL, - method, method_len, - pubkeydata, pubkeydata_len, - privkeyblob, privkeyblob_len, - passphrase); + if(privatekey) + rc = ossl_key_from_openssh_file(session, + method, method_len, + pubkeydata, pubkeydata_len, + privatekey, + passphrase); + else + rc = ossl_key_from_openssh_blob(session, NULL, NULL, + method, method_len, + pubkeydata, pubkeydata_len, + privkeyblob, privkeyblob_len, + passphrase); if(rc == 0) return 0; @@ -4048,8 +3953,8 @@ int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, "Wrong passphrase for private key"); #endif return ssh2_err(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key file: " - "Unsupported private key file format"); + "Unable to extract public key from private key: " + "Unsupported private key format"); } pktype = EVP_PKEY_id(pk); @@ -4081,8 +3986,8 @@ int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, #endif /* LIBSSH2_ECDSA */ default: rc = ssh2_err(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key file: " - "Unsupported private key file format"); + "Unable to extract public key from private key: " + "Unsupported private key format"); break; } diff --git a/src/openssl.h b/src/openssl.h index 12d7ba43..682bea3f 100644 --- a/src/openssl.h +++ b/src/openssl.h @@ -222,7 +222,7 @@ # define LIBSSH2_3DES 1 #endif -#define LIBSSH2_KEY_SK /* implements ssh2_sk_pubkey_blob() */ +#define LIBSSH2_KEY_SK /* implements ssh2_sk_pubkey() */ #include "crypto_config.h" diff --git a/src/os400qc3.c b/src/os400qc3.c index 325a4398..5d518414 100644 --- a/src/os400qc3.c +++ b/src/os400qc3.c @@ -2073,34 +2073,14 @@ static int load_rsa_private_file(LIBSSH2_SESSION *session, return ret; } -int ssh2_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +static int os400_pub_privkey_file(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + const char *privatekey, + const char *passphrase) { - ssh2_rsa_ctx *ctx = init_crypto_ctx(NULL); - int ret; - - if(!ctx) - return -1; - ret = load_rsa_private_file(session, filename, passphrase, - rsapkcs1privkey, rsapkcs8privkey, - (void *)ctx); - if(ret) { - ssh2_os400qc3_crypto_dtor(ctx); - ctx = NULL; - } - *rsa = ctx; - return ret; -} - -int ssh2_pub_privkey_file(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ - struct loadpubkeydata p; + struct loadpubkeydata p = { 0 }; int ret; *method = NULL; @@ -2134,91 +2114,19 @@ int ssh2_pub_privkey_file(LIBSSH2_SESSION *session, return ret; } -int ssh2_rsa_new_priv_from_blob(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) +static int os400_pub_privkey_blob(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + const char *privkeyblob, + size_t privkeyblob_len, + const char *passphrase) { - ssh2_rsa_ctx *ctx = init_crypto_ctx(NULL); + struct loadpubkeydata p = { 0 }; unsigned char *data = NULL; size_t datalen = 0; int ret; - if(!ctx) - return -1; - - /* Try with "ENCRYPTED PRIVATE KEY" PEM armor. - --> PKCS#8 EncryptedPrivateKeyInfo */ - ret = ssh2_pem_parse_blob(session, - beginencprivkeyhdr, endencprivkeyhdr, - blob, blob_len, - passphrase, - &data, &datalen); - - /* Try with "PRIVATE KEY" PEM armor. - --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ - if(ret) - ret = ssh2_pem_parse_blob(session, - beginprivkeyhdr, endprivkeyhdr, - blob, blob_len, - passphrase, - &data, &datalen); - - if(!ret) { - /* Process PKCS#8. */ - ret = rsapkcs8privkey(session, - data, datalen, passphrase, (void *)&ctx); - } - else { - /* Try with "RSA PRIVATE KEY" PEM armor. - --> PKCS#1 RSAPrivateKey */ - ret = ssh2_pem_parse_blob(session, - beginrsaprivkeyhdr, endrsaprivkeyhdr, - blob, blob_len, - passphrase, - &data, &datalen); - if(!ret) - ret = rsapkcs1privkey(session, - data, datalen, passphrase, (void *)&ctx); - } - - if(ret) { - /* Try as PKCS#8 DER data. - --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ - ret = rsapkcs8privkey(session, blob, blob_len, - passphrase, (void *)&ctx); - - /* Try as PKCS#1 DER data. - --> PKCS#1 RSAPrivateKey */ - if(ret) - ret = rsapkcs1privkey(session, blob, blob_len, - passphrase, (void *)&ctx); - } - - if(data) - SSH2_FREE(session, data); - - if(ret) { - ssh2_os400qc3_crypto_dtor(ctx); - ctx = NULL; - } - - *rsa = ctx; - return ret; -} - -int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privkeyblob, size_t privkeyblob_len, - const char *passphrase) -{ - struct loadpubkeydata p; - unsigned char *data = NULL; - size_t datalen = 0; - const char *meth; - int ret; - *method = NULL; *method_len = 0; *pubkeydata = NULL; @@ -2297,6 +2205,135 @@ int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, return ret; } +/* TODO: merge the two callees into one. */ +int ssh2_pub_privkey(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + const char *privatekey, + const char *privkeyblob, size_t privkeyblob_len, + const char *passphrase) +{ + if(privatekey) + return os400_pub_privkey_file(session, method, method_len, + pubkeydata, pubkeydata_len, + privatekey, + passphrase); + else + return os400_pub_privkey_blob(session, method, method_len, + pubkeydata, pubkeydata_len, + privkeyblob, privkeyblob_len, + passphrase); +} + +static int os400_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *passphrase) +{ + ssh2_rsa_ctx *ctx = init_crypto_ctx(NULL); + int ret; + + if(!ctx) + return -1; + ret = load_rsa_private_file(session, filename, passphrase, + rsapkcs1privkey, rsapkcs8privkey, + (void *)ctx); + if(ret) { + ssh2_os400qc3_crypto_dtor(ctx); + ctx = NULL; + } + *rsa = ctx; + return ret; +} + +static int os400_rsa_new_priv_from_blob(ssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + const char *blob, size_t blob_len, + const char *passphrase) +{ + ssh2_rsa_ctx *ctx = init_crypto_ctx(NULL); + unsigned char *data = NULL; + size_t datalen = 0; + int ret; + + if(!ctx) + return -1; + + /* Try with "ENCRYPTED PRIVATE KEY" PEM armor. + --> PKCS#8 EncryptedPrivateKeyInfo */ + ret = ssh2_pem_parse_blob(session, + beginencprivkeyhdr, endencprivkeyhdr, + blob, blob_len, + passphrase, + &data, &datalen); + + /* Try with "PRIVATE KEY" PEM armor. + --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ + if(ret) + ret = ssh2_pem_parse_blob(session, + beginprivkeyhdr, endprivkeyhdr, + blob, blob_len, + passphrase, + &data, &datalen); + + if(!ret) { + /* Process PKCS#8. */ + ret = rsapkcs8privkey(session, + data, datalen, passphrase, (void *)&ctx); + } + else { + /* Try with "RSA PRIVATE KEY" PEM armor. + --> PKCS#1 RSAPrivateKey */ + ret = ssh2_pem_parse_blob(session, + beginrsaprivkeyhdr, endrsaprivkeyhdr, + blob, blob_len, + passphrase, + &data, &datalen); + if(!ret) + ret = rsapkcs1privkey(session, + data, datalen, passphrase, (void *)&ctx); + } + + if(ret) { + /* Try as PKCS#8 DER data. + --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ + ret = rsapkcs8privkey(session, blob, blob_len, + passphrase, (void *)&ctx); + + /* Try as PKCS#1 DER data. + --> PKCS#1 RSAPrivateKey */ + if(ret) + ret = rsapkcs1privkey(session, blob, blob_len, + passphrase, (void *)&ctx); + } + + if(data) + SSH2_FREE(session, data); + + if(ret) { + ssh2_os400qc3_crypto_dtor(ctx); + ctx = NULL; + } + + *rsa = ctx; + return ret; +} + +/* TODO: merge the two callees into one. */ +int ssh2_rsa_new_priv(ssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) +{ + if(filename) + return os400_rsa_new_priv_from_file(rsa, session, + filename, passphrase); + else + return os400_rsa_new_priv_from_blob(rsa, session, + blob, blob_len, passphrase); +} + int ssh2_rsa_sha2_verify(ssh2_rsa_ctx *rsa, size_t hash_len, const unsigned char *sig, size_t sig_len, const unsigned char *m, size_t m_len) diff --git a/src/userauth.c b/src/userauth.c index 2428a424..2ef25be7 100644 --- a/src/userauth.c +++ b/src/userauth.c @@ -918,11 +918,11 @@ static int userauth_hostbased_fromfile(LIBSSH2_SESSION *session, &pubkeydata, &pubkeydata_len, publickey, NULL, 0); else /* Compute public key from private key. */ - rc = ssh2_pub_privkey_file(session, - &session->userauth_host_method, - &session->userauth_host_method_len, - &pubkeydata, &pubkeydata_len, - privatekey, passphrase); + rc = ssh2_pub_privkey(session, + &session->userauth_host_method, + &session->userauth_host_method_len, + &pubkeydata, &pubkeydata_len, + privatekey, NULL, 0, passphrase); if(rc) return rc; /* low-level functions called ssh2_err() */ @@ -1786,26 +1786,20 @@ static int userauth_publickey(LIBSSH2_SESSION *session, privkey_info.passphrase = passphrase; if(session->userauth_pblc_state == ssh2_NB_state_idle) { - if(pubkeyfile || (pubkeyblob_len && pubkeyblob)) + if(pubkeyfile || (pubkeyblob && pubkeyblob_len)) rc = userauth_read_pubkey(session, &session->userauth_pblc_method, &session->userauth_pblc_method_len, &pubkeydata, &pubkeydata_len, pubkeyfile, pubkeyblob, pubkeyblob_len); /* Compute public key from private key. */ - else if(privkeyfile) - rc = ssh2_pub_privkey_file(session, - &session->userauth_pblc_method, - &session->userauth_pblc_method_len, - &pubkeydata, &pubkeydata_len, - privkeyfile, passphrase); - else if(privkeyblob_len && privkeyblob) - rc = ssh2_pub_privkey_blob(session, - &session->userauth_pblc_method, - &session->userauth_pblc_method_len, - &pubkeydata, &pubkeydata_len, - privkeyblob, privkeyblob_len, - passphrase); + else if(privkeyfile || (privkeyblob && privkeyblob_len)) + rc = ssh2_pub_privkey(session, + &session->userauth_pblc_method, + &session->userauth_pblc_method_len, + &pubkeydata, &pubkeydata_len, + privkeyfile, privkeyblob, privkeyblob_len, + passphrase); else return ssh2_err(session, LIBSSH2_ERROR_FILE, "Invalid data in public and private key."); @@ -2198,18 +2192,18 @@ int libssh2_userauth_publickey_sk( if(privkeyblob_len && privkeyblob) { - if(ssh2_sk_pubkey_blob(session, - &tmp_method, - &tmp_method_len, - &tmp_publickeydata, - &tmp_publickeydata_len, - &sk_info.algorithm, - &sk_info.flags, - &sk_info.application, - &sk_info.key_handle, - &sk_info.handle_len, - privkeyblob, privkeyblob_len, - passphrase)) + if(ssh2_sk_pubkey(session, + &tmp_method, + &tmp_method_len, + &tmp_publickeydata, + &tmp_publickeydata_len, + &sk_info.algorithm, + &sk_info.flags, + &sk_info.application, + &sk_info.key_handle, + &sk_info.handle_len, + NULL, privkeyblob, privkeyblob_len, + passphrase)) return ssh2_err(session, LIBSSH2_ERROR_FILE, "Unable to extract public key from private key."); else if(publickeydata_len == 0 || !publickeydata) { diff --git a/src/wincng.c b/src/wincng.c index 0b36dd92..c5f98d14 100644 --- a/src/wincng.c +++ b/src/wincng.c @@ -899,80 +899,59 @@ static int wcng_key_sha_verify(struct wcng_key_ctx *ctx, ULONG hash_len, return BCRYPT_SUCCESS(ret) ? 0 : -1; } -static int wcng_load_priv_from_file(LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase, - unsigned char **ppbEncoded, - size_t *pcbEncoded, - int tryLoadRSA, int tryLoadDSA) +static int wcng_load_priv(LIBSSH2_SESSION *session, + const char *filename, + const char *privkeyblob, + size_t privkeyblob_len, + const char *passphrase, + unsigned char **ppbEncoded, + size_t *pcbEncoded, + int tryLoadRSA, int tryLoadDSA) { int ret = -1; - FILE *fp; unsigned char *data = NULL; size_t datalen = 0; + FILE *fp = NULL; - fp = ssh2_fopen(filename, "rb"); - if(!fp) - return -1; - -#if LIBSSH2_RSA - if(ret && tryLoadRSA) - ret = ssh2_pem_parse_FILE(session, PEM_RSA_HEADER, PEM_RSA_FOOTER, - fp, passphrase, - &data, &datalen); -#else - (void)tryLoadRSA; -#endif - -#if LIBSSH2_DSA - if(ret && tryLoadDSA) - ret = ssh2_pem_parse_FILE(session, PEM_DSA_HEADER, PEM_DSA_FOOTER, - fp, passphrase, - &data, &datalen); -#else - (void)tryLoadDSA; -#endif - - fclose(fp); - - if(!ret) { - *ppbEncoded = data; - *pcbEncoded = datalen; + if(filename) { + fp = ssh2_fopen(filename, "rb"); + if(!fp) + return -1; } - return ret; -} - -static int wcng_load_priv_from_blob(LIBSSH2_SESSION *session, - const char *privkeyblob, - size_t privkeyblob_len, - const char *passphrase, - unsigned char **ppbEncoded, - size_t *pcbEncoded, - int tryLoadRSA, int tryLoadDSA) -{ - unsigned char *data = NULL; - size_t datalen = 0; - int ret = -1; - #if LIBSSH2_RSA - if(ret && tryLoadRSA) - ret = ssh2_pem_parse_blob(session, PEM_RSA_HEADER, PEM_RSA_FOOTER, - privkeyblob, privkeyblob_len, passphrase, - &data, &datalen); + if(ret && tryLoadRSA) { + if(filename) + ret = ssh2_pem_parse_FILE(session, PEM_RSA_HEADER, PEM_RSA_FOOTER, + fp, passphrase, + &data, &datalen); + else + ret = ssh2_pem_parse_blob(session, PEM_RSA_HEADER, PEM_RSA_FOOTER, + privkeyblob, privkeyblob_len, passphrase, + &data, &datalen); + } #else (void)tryLoadRSA; #endif #if LIBSSH2_DSA - if(ret && tryLoadDSA) - ret = ssh2_pem_parse_blob(session, PEM_DSA_HEADER, PEM_DSA_FOOTER, - privkeyblob, privkeyblob_len, passphrase, - &data, &datalen); + if(ret && tryLoadDSA) { + if(filename) + ret = ssh2_pem_parse_FILE(session, PEM_DSA_HEADER, PEM_DSA_FOOTER, + fp, passphrase, + &data, &datalen); + else + ret = ssh2_pem_parse_blob(session, PEM_DSA_HEADER, PEM_DSA_FOOTER, + privkeyblob, privkeyblob_len, passphrase, + &data, &datalen); + } #else (void)tryLoadDSA; #endif + if(fp) + fclose(fp); + if(!ret) { *ppbEncoded = data; *pcbEncoded = datalen; @@ -1330,35 +1309,17 @@ static int wcng_rsa_new_private_parse(ssh2_rsa_ctx **rsa, return 0; } -int ssh2_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +int ssh2_rsa_new_priv(ssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) { unsigned char *pbEncoded; size_t cbEncoded; - int ret; - ret = wcng_load_priv_from_file(session, filename, passphrase, - &pbEncoded, &cbEncoded, 1, 0); - if(ret) - return -1; - - return wcng_rsa_new_private_parse(rsa, session, pbEncoded, cbEncoded); -} - -int ssh2_rsa_new_priv_from_blob(ssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) -{ - unsigned char *pbEncoded; - size_t cbEncoded; - int ret; - - ret = wcng_load_priv_from_blob(session, blob, blob_len, passphrase, - &pbEncoded, &cbEncoded, 1, 0); - if(ret) + if(wcng_load_priv(session, filename, blob, blob_len, passphrase, + &pbEncoded, &cbEncoded, 1, 0)) return -1; return wcng_rsa_new_private_parse(rsa, session, pbEncoded, cbEncoded); @@ -1617,35 +1578,17 @@ static int wcng_dsa_new_private_parse(ssh2_dsa_ctx **dsa, return ret; } -int ssh2_dsa_new_priv_from_file(ssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase) +int ssh2_dsa_new_priv(ssh2_dsa_ctx **dsa, + LIBSSH2_SESSION *session, + const char *filename, + const char *blob, size_t blob_len, + const char *passphrase) { unsigned char *pbEncoded; size_t cbEncoded; - int ret; - ret = wcng_load_priv_from_file(session, filename, passphrase, - &pbEncoded, &cbEncoded, 0, 1); - if(ret) - return -1; - - return wcng_dsa_new_private_parse(dsa, session, pbEncoded, cbEncoded); -} - -int ssh2_dsa_new_priv_from_blob(ssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *blob, size_t blob_len, - const char *passphrase) -{ - unsigned char *pbEncoded; - size_t cbEncoded; - int ret; - - ret = wcng_load_priv_from_blob(session, blob, blob_len, passphrase, - &pbEncoded, &cbEncoded, 0, 1); - if(ret) + if(wcng_load_priv(session, filename, blob, blob_len, passphrase, + &pbEncoded, &cbEncoded, 0, 1)) return -1; return wcng_dsa_new_private_parse(dsa, session, pbEncoded, cbEncoded); @@ -2517,32 +2460,41 @@ cleanup: } /* - * Creates a new private key given a file path and password + * Creates a new private key given a file or blob and password. + * ECDSA private key files use the decoding defined in PROTOCOL.key + * in the OpenSSH source tree. */ -int ssh2_ecdsa_new_priv_from_file(OUT ssh2_ecdsa_ctx **ec_ctx, - IN LIBSSH2_SESSION *session, - IN const char *filename, - IN const char *passphrase) +int ssh2_ecdsa_new_priv(OUT ssh2_ecdsa_ctx **ec_ctx, + IN LIBSSH2_SESSION *session, + IN const char *filename, + IN const char *blob, IN size_t blob_len, + IN const char *passphrase) { int result; - - FILE *fp = NULL; struct string_buf *decrypted = NULL; + FILE *fp = NULL; /* Validate parameters */ - if(!ec_ctx || !session || !filename) + if(!ec_ctx || !session || (!filename && !blob)) return LIBSSH2_ERROR_INVAL; *ec_ctx = NULL; - fp = ssh2_fopen(filename, "rb"); - if(!fp) { - result = ssh2_err(session, LIBSSH2_ERROR_INVAL, - "Opening the private key file failed"); - goto cleanup; - } + if(filename) { + fp = ssh2_fopen(filename, "rb"); + if(!fp) { + result = ssh2_err(session, LIBSSH2_ERROR_FILE, + "Opening the private key file failed"); + goto cleanup; + } + + result = ssh2_openssh_pem_parse_FILE(session, fp, + passphrase, &decrypted); + } + else + result = ssh2_openssh_pem_parse_blob(session, blob, blob_len, + passphrase, &decrypted); - result = ssh2_openssh_pem_parse_FILE(session, fp, passphrase, &decrypted); if(result) goto cleanup; @@ -2559,40 +2511,6 @@ cleanup: return result; } -/* - * Creates a new private key given a file data and password. - * ECDSA private key files use the decoding defined in PROTOCOL.key - * in the OpenSSH source tree. - */ -int ssh2_ecdsa_new_priv_from_blob(OUT ssh2_ecdsa_ctx **ec_ctx, - IN LIBSSH2_SESSION *session, - IN const char *blob, IN size_t blob_len, - IN const char *passphrase) -{ - int result; - struct string_buf *decrypted = NULL; - - /* Validate parameters */ - if(!ec_ctx || !session || !blob) - return LIBSSH2_ERROR_INVAL; - - *ec_ctx = NULL; - - result = ssh2_openssh_pem_parse_blob(session, blob, blob_len, - passphrase, &decrypted); - if(result) - goto cleanup; - - result = wcng_ecdsa_new_private_parse(ec_ctx, session, - decrypted->data, decrypted->len); - -cleanup: - if(decrypted) - ssh2_string_buf_free(session, decrypted); - - return result; -} - /* * Computes the ECDSA signature of a previously-hashed message */ @@ -2833,41 +2751,19 @@ cleanup: return ret; } -int ssh2_pub_privkey_file(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) +int ssh2_pub_privkey(LIBSSH2_SESSION *session, + char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + const char *privatekey, + const char *privkeyblob, size_t privkeyblob_len, + const char *passphrase) { unsigned char *pbEncoded; size_t cbEncoded; - int ret; - ret = wcng_load_priv_from_file(session, - privatekey, passphrase, - &pbEncoded, &cbEncoded, 1, 1); - if(ret) - return -1; - - return wcng_pub_privkey_file_parse(session, method, method_len, - pubkeydata, pubkeydata_len, - pbEncoded, cbEncoded); -} - -int ssh2_pub_privkey_blob(LIBSSH2_SESSION *session, - char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privkeyblob, size_t privkeyblob_len, - const char *passphrase) -{ - unsigned char *pbEncoded; - size_t cbEncoded; - int ret; - - ret = wcng_load_priv_from_blob(session, - privkeyblob, privkeyblob_len, passphrase, - &pbEncoded, &cbEncoded, 1, 1); - if(ret) + if(wcng_load_priv(session, + privatekey, privkeyblob, privkeyblob_len, passphrase, + &pbEncoded, &cbEncoded, 1, 1)) return -1; return wcng_pub_privkey_file_parse(session, method, method_len,