1
0
mirror of https://github.com/libssh2/libssh2.git synced 2026-10-24 03:48:58 +03:00

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 6a951168ce #2362
Follow-up to fe9442be4d #2359
Follow-up to 5b94157f1c #2354

Closes #2379
This commit is contained in:
Viktor Szakats
2026-07-21 15:23:45 +02:00
parent 16879e47b8
commit b560cb4c7b
11 changed files with 701 additions and 1067 deletions

View File

@@ -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`.

View File

@@ -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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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");
}

View File

@@ -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;
}

View File

@@ -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"

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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,