1
0
mirror of https://github.com/libssh2/libssh2.git synced 2025-11-20 02:42:09 +03:00

Support for sk-ecdsa-sha2-nistp256 and sk-ssh-ed25519 keys, FIDO (#698)

Notes:
Add support for sk-ecdsa-sha2-nistp256@openssh.com and sk-ssh-ed25519@openssh.com key exchange for FIDO auth using the OpenSSL backend. Stub API for other backends.

Credit:
Michael Buckley
This commit is contained in:
Michael Buckley
2022-09-29 09:05:34 -07:00
committed by GitHub
parent ef292424bb
commit ed439a29bb
16 changed files with 1380 additions and 29 deletions

View File

@@ -57,6 +57,23 @@ read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session,
size_t filedata_len,
unsigned const char *passphrase);
static int
_libssh2_sk_pub_openssh_keyfilememory(LIBSSH2_SESSION *session,
void **key_ctx,
const char *key_type,
unsigned 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 *privatekeydata,
size_t privatekeydata_len,
unsigned const char *passphrase);
static unsigned char *
write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes)
{
@@ -1498,6 +1515,34 @@ _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx,
return rc;
}
int _libssh2_ecdsa_new_private_frommemory_sk(libssh2_ecdsa_ctx ** ec_ctx,
unsigned char *flags,
const char **application,
const unsigned char **key_handle,
size_t *handle_len,
LIBSSH2_SESSION * session,
const char *filedata,
size_t filedata_len,
unsigned const char *passphrase)
{
int algorithm;
return _libssh2_sk_pub_openssh_keyfilememory(session,
(void **)ec_ctx,
"sk-ecdsa-sha2-nistp256@openssh.com",
NULL,
NULL,
NULL,
NULL,
&algorithm,
flags,
application,
key_handle,
handle_len,
filedata,
filedata_len,
passphrase);
}
#endif /* LIBSSH2_ECDSA */
@@ -1780,6 +1825,160 @@ clean_exit:
return -1;
}
static int
gen_publickey_from_sk_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
struct string_buf *decrypted,
unsigned char **method,
size_t *method_len,
unsigned char **pubkeydata,
size_t *pubkeydata_len,
unsigned char *flags,
const char **application,
const unsigned char **key_handle,
size_t *handle_len,
libssh2_ed25519_ctx **out_ctx)
{
const char *key_type = "sk-ssh-ed25519@openssh.com";
libssh2_ed25519_ctx *ctx = NULL;
unsigned char *method_buf = NULL;
unsigned char *key = NULL;
int ret = 0;
unsigned char *pub_key, *app;
size_t key_len = 0, app_len = 0, tmp_len = 0;
unsigned char *p;
_libssh2_debug(session,
LIBSSH2_TRACE_AUTH,
"Computing sk-ED25519 keys from private key data");
if(_libssh2_get_string(decrypted, &pub_key, &tmp_len) ||
tmp_len != LIBSSH2_ED25519_KEY_LEN) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Wrong public key length");
return -1;
}
if(_libssh2_get_string(decrypted, &app, &app_len)) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"No SK application.");
return -1;
}
if(flags != NULL && _libssh2_get_byte(decrypted, flags)) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"No SK flags.");
return -1;
}
if(key_handle != NULL && handle_len != NULL) {
unsigned char *handle = NULL;
if(_libssh2_get_string(decrypted, &handle, handle_len)) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"No SK key_handle.");
return -1;
}
if(*handle_len > 0) {
*key_handle = LIBSSH2_ALLOC(session, *handle_len);
if(key_handle) {
memcpy((void *)*key_handle, handle, *handle_len);
}
}
}
ctx = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
(const unsigned char *)pub_key,
LIBSSH2_ED25519_KEY_LEN);
if(ret == 0) {
_libssh2_debug(session,
LIBSSH2_TRACE_AUTH,
"Computing public key from ED25519 "
"private key envelope");
/* sk-ssh-ed25519@openssh.com. */
method_buf = LIBSSH2_ALLOC(session, strlen(key_type));
if(method_buf == NULL) {
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for ED25519 key");
goto clean_exit;
}
/* Key form is: type_len(4) + type(26) + pub_key_len(4) +
pub_key(32) + application_len(4) + application(X). */
key_len = LIBSSH2_ED25519_KEY_LEN + 38 + app_len;
key = LIBSSH2_CALLOC(session, key_len);
if(key == NULL) {
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for ED25519 key");
goto clean_exit;
}
p = key;
_libssh2_store_str(&p, key_type, strlen(key_type));
_libssh2_store_str(&p, (const char *)pub_key, LIBSSH2_ED25519_KEY_LEN);
_libssh2_store_str(&p, (const char *)app, app_len);
if(application != NULL && app_len > 0) {
*application = (const char *)LIBSSH2_ALLOC(session, app_len + 1);
_libssh2_explicit_zero((void *)*application, app_len + 1);
memcpy((void *)*application, app, app_len);
}
memcpy(method_buf, key_type, strlen(key_type));
if(method != NULL)
*method = method_buf;
else
LIBSSH2_FREE(session, method_buf);
if(method_len != NULL)
*method_len = strlen(key_type);
if(pubkeydata != NULL)
*pubkeydata = key;
else if(key != NULL)
LIBSSH2_FREE(session, key);
if(pubkeydata_len != NULL)
*pubkeydata_len = key_len;
if(out_ctx != NULL)
*out_ctx = ctx;
else if(ctx != NULL)
_libssh2_ed25519_free(ctx);
return 0;
}
clean_exit:
if(ctx)
_libssh2_ed25519_free(ctx);
if(method_buf)
LIBSSH2_FREE(session, method_buf);
if(key)
LIBSSH2_FREE(session, key);
if(application != NULL && *application != NULL) {
LIBSSH2_FREE(session, (void *)application);
*application = NULL;
}
if(key_handle != NULL && *key_handle != NULL) {
LIBSSH2_FREE(session, (void *)key_handle);
*key_handle = NULL;
}
return -1;
}
int
_libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx,
LIBSSH2_SESSION * session,
@@ -1847,6 +2046,82 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx,
return rc;
}
int
_libssh2_ed25519_new_private_sk(libssh2_ed25519_ctx **ed_ctx,
unsigned char *flags,
const char **application,
const unsigned char **key_handle,
size_t *handle_len,
LIBSSH2_SESSION *session,
const char *filename,
const uint8_t *passphrase)
{
int rc;
FILE *fp;
unsigned char *buf;
struct string_buf *decrypted = NULL;
libssh2_ed25519_ctx *ctx = NULL;
if(session == NULL) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Session is required");
return -1;
}
_libssh2_init_if_needed();
fp = fopen(filename, "r");
if(!fp) {
_libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to open ED25519 SK private key file");
return -1;
}
rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted);
fclose(fp);
if(rc) {
return rc;
}
/* We have a new key file, now try and parse it using supported types */
rc = _libssh2_get_string(decrypted, &buf, NULL);
if(rc != 0 || buf == NULL) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Public key type in decrypted key data not found");
return -1;
}
if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) {
rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session,
decrypted,
NULL,
NULL,
NULL,
NULL,
flags,
application,
key_handle,
handle_len,
&ctx);
}
else {
rc = -1;
}
if(decrypted)
_libssh2_string_buf_free(session, decrypted);
if(rc == 0) {
if(ed_ctx != NULL)
*ed_ctx = ctx;
else if(ctx != NULL)
_libssh2_ed25519_free(ctx);
}
return rc;
}
int
_libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx,
LIBSSH2_SESSION * session,
@@ -1878,6 +2153,35 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx,
passphrase);
}
int
_libssh2_ed25519_new_private_frommemory_sk(libssh2_ed25519_ctx **ed_ctx,
unsigned char *flags,
const char **application,
const unsigned char **key_handle,
size_t *handle_len,
LIBSSH2_SESSION *session,
const char *filedata,
size_t filedata_len,
unsigned const char *passphrase)
{
int algorithm;
return _libssh2_sk_pub_openssh_keyfilememory(session,
(void **)ed_ctx,
"sk-ssh-ed25519@openssh.com",
NULL,
NULL,
NULL,
NULL,
&algorithm,
flags,
application,
key_handle,
handle_len,
filedata,
filedata_len,
passphrase);
}
int
_libssh2_ed25519_new_public(libssh2_ed25519_ctx ** ed_ctx,
LIBSSH2_SESSION * session,
@@ -2318,6 +2622,7 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
size_t *method_len,
unsigned char **pubkeydata,
size_t *pubkeydata_len,
int is_sk,
EVP_PKEY *pk)
{
int rc = 0;
@@ -2351,18 +2656,25 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
group = EC_KEY_get0_group(ec);
type = _libssh2_ecdsa_get_curve_type(ec);
method_buf = LIBSSH2_ALLOC(session, 19);
if(is_sk)
*method_len = 34;
else
*method_len = 19;
method_buf = LIBSSH2_ALLOC(session, *method_len);
if(method_buf == NULL) {
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"out of memory");
}
if(type == LIBSSH2_EC_CURVE_NISTP256)
memcpy(method_buf, "ecdsa-sha2-nistp256", 19);
if(is_sk)
memcpy(method_buf, "sk-ecdsa-sha2-nistp256@openssh.com", *method_len);
else if(type == LIBSSH2_EC_CURVE_NISTP256)
memcpy(method_buf, "ecdsa-sha2-nistp256", *method_len);
else if(type == LIBSSH2_EC_CURVE_NISTP384)
memcpy(method_buf, "ecdsa-sha2-nistp384", 19);
memcpy(method_buf, "ecdsa-sha2-nistp384", *method_len);
else if(type == LIBSSH2_EC_CURVE_NISTP521)
memcpy(method_buf, "ecdsa-sha2-nistp521", 19);
memcpy(method_buf, "ecdsa-sha2-nistp521", *method_len);
else {
_libssh2_debug(session,
LIBSSH2_TRACE_ERROR,
@@ -2393,9 +2705,9 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
goto clean_exit;
}
/* Key form is: type_len(4) + type(19) + domain_len(4) + domain(8) +
pub_key_len(4) + pub_key(~65). */
key_len = 4 + 19 + 4 + 8 + 4 + octal_len;
/* Key form is: type_len(4) + type(method_len) + domain_len(4) + domain(8)
+ pub_key_len(4) + pub_key(~65). */
key_len = 4 + *method_len + 4 + 8 + 4 + octal_len;
key = LIBSSH2_ALLOC(session, key_len);
if(key == NULL) {
rc = -1;
@@ -2406,16 +2718,20 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
p = key;
/* Key type */
_libssh2_store_str(&p, (const char *)method_buf, 19);
_libssh2_store_str(&p, (const char *)method_buf, *method_len);
/* Name domain */
_libssh2_store_str(&p, (const char *)method_buf + 11, 8);
if(is_sk) {
_libssh2_store_str(&p, "nistp256", 8);
}
else {
_libssh2_store_str(&p, (const char *)method_buf + 11, 8);
}
/* Public key */
_libssh2_store_str(&p, (const char *)octal_value, octal_len);
*method = method_buf;
*method_len = 19;
*pubkeydata = key;
*pubkeydata_len = key_len;
@@ -2504,7 +2820,7 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session,
rc = gen_publickey_from_ec_evp(session, method, method_len,
pubkeydata, pubkeydata_len,
pk);
0, pk);
if(pk)
EVP_PKEY_free(pk);
@@ -2524,6 +2840,144 @@ fail:
return rc;
}
static int
gen_publickey_from_sk_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session,
struct string_buf *decrypted,
unsigned char **method,
size_t *method_len,
unsigned char **pubkeydata,
size_t *pubkeydata_len,
uint8_t *flags,
const char **application,
const unsigned char **key_handle,
size_t *handle_len,
libssh2_ecdsa_ctx **ec_ctx)
{
int rc = 0;
size_t curvelen, pointlen, key_len, app_len;
unsigned char *curve, *point_buf, *p, *key, *app;
EC_KEY *ec_key = NULL;
_libssh2_debug(session,
LIBSSH2_TRACE_AUTH,
"Extracting ECDSA-SK public key");
if(_libssh2_get_string(decrypted, &curve, &curvelen) ||
curvelen == 0) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"ECDSA no curve");
return -1;
}
if(_libssh2_get_string(decrypted, &point_buf, &pointlen)) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"ECDSA no point");
return -1;
}
if((rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, point_buf,
pointlen, LIBSSH2_EC_CURVE_NISTP256)) != 0) {
rc = -1;
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"ECDSA could not create key");
goto fail;
}
if(_libssh2_get_string(decrypted, &app, &app_len)) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"No SK application.");
goto fail;
}
if(flags != NULL && _libssh2_get_byte(decrypted, flags)) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"No SK flags.");
goto fail;
}
if(key_handle != NULL && handle_len != NULL) {
unsigned char *handle = NULL;
if(_libssh2_get_string(decrypted, &handle, handle_len)) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"No SK key_handle.");
goto fail;
}
if(*handle_len > 0) {
*key_handle = LIBSSH2_ALLOC(session, *handle_len);
if(*key_handle) {
memcpy((void *)*key_handle, handle, *handle_len);
}
}
}
if(rc == 0 && ec_key != NULL && pubkeydata != NULL && method != NULL) {
EVP_PKEY *pk = EVP_PKEY_new();
EVP_PKEY_set1_EC_KEY(pk, ec_key);
rc = gen_publickey_from_ec_evp(session, method, method_len,
pubkeydata, pubkeydata_len,
1, pk);
if(pk)
EVP_PKEY_free(pk);
}
if(rc == 0 && pubkeydata != NULL) {
key_len = *pubkeydata_len + app_len + 4;
key = LIBSSH2_ALLOC(session, key_len);
if(key == NULL) {
rc = -1;
goto fail;
}
p = key + *pubkeydata_len;
memcpy(key, *pubkeydata, *pubkeydata_len);
_libssh2_store_str(&p, (const char *)app, app_len);
if(application != NULL && app_len > 0) {
*application = (const char *)LIBSSH2_ALLOC(session, app_len + 1);
_libssh2_explicit_zero((void *)*application, app_len + 1);
memcpy((void *)*application, app, app_len);
}
LIBSSH2_FREE(session, *pubkeydata);
*pubkeydata_len = key_len;
if(pubkeydata != NULL)
*pubkeydata = key;
else if(key != NULL)
LIBSSH2_FREE(session, key);
}
if(ec_ctx != NULL)
*ec_ctx = ec_key;
else
EC_KEY_free(ec_key);
return rc;
fail:
if(ec_key != NULL)
EC_KEY_free(ec_key);
if(application != NULL && *application != NULL) {
LIBSSH2_FREE(session, (void *)application);
*application = NULL;
}
if(key_handle != NULL && *key_handle != NULL) {
LIBSSH2_FREE(session, (void *)key_handle);
*key_handle = NULL;
}
return rc;
}
static int
_libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx,
LIBSSH2_SESSION * session,
@@ -2583,6 +3037,72 @@ _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx,
return rc;
}
static int
_libssh2_ecdsa_new_openssh_private_sk(libssh2_ecdsa_ctx ** ec_ctx,
uint8_t *flags,
const char **application,
const unsigned char **key_handle,
size_t *handle_len,
LIBSSH2_SESSION * session,
const char *filename,
unsigned const char *passphrase)
{
FILE *fp;
int rc;
unsigned char *buf = NULL;
struct string_buf *decrypted = NULL;
if(session == NULL) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Session is required");
return -1;
}
_libssh2_init_if_needed();
fp = fopen(filename, "r");
if(!fp) {
_libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to open OpenSSH ECDSA private key file");
return -1;
}
rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted);
fclose(fp);
if(rc) {
return rc;
}
/* We have a new key file, now try and parse it using supported types */
rc = _libssh2_get_string(decrypted, &buf, NULL);
if(rc != 0 || buf == NULL) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Public key type in decrypted key data not found");
return -1;
}
if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) {
rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session,
decrypted,
NULL, 0,
NULL, 0,
flags,
application,
key_handle,
handle_len,
ec_ctx);
}
else {
rc = -1;
}
if(decrypted)
_libssh2_string_buf_free(session, decrypted);
return rc;
}
int
_libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
LIBSSH2_SESSION * session,
@@ -2605,6 +3125,40 @@ _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
return rc;
}
int
_libssh2_ecdsa_new_private_sk(libssh2_ecdsa_ctx ** ec_ctx,
unsigned char *flags,
const char **application,
const unsigned char **key_handle,
size_t *handle_len,
LIBSSH2_SESSION * session,
const char *filename,
unsigned const char *passphrase)
{
int rc;
pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey;
_libssh2_init_if_needed();
rc = read_private_key_from_file((void **) ec_ctx, read_ec,
filename, passphrase);
if(rc) {
return _libssh2_ecdsa_new_openssh_private_sk(ec_ctx,
flags,
application,
key_handle,
handle_len,
session,
filename,
passphrase);
}
return rc;
}
/*
* _libssh2_ecdsa_create_key
*
@@ -3078,7 +3632,7 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
#if LIBSSH2_ECDSA
case EVP_PKEY_EC :
st = gen_publickey_from_ec_evp(
session, method, method_len, pubkeydata, pubkeydata_len, pk);
session, method, method_len, pubkeydata, pubkeydata_len, 0, pk);
break;
#endif
@@ -3153,6 +3707,23 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session,
(libssh2_ed25519_ctx**)key_ctx);
}
}
if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) {
if(key_type == NULL ||
strcmp("sk-ssh-ed25519@openssh.com", key_type) == 0) {
rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session,
decrypted,
method,
method_len,
pubkeydata,
pubkeydata_len,
NULL,
NULL,
NULL,
NULL,
(libssh2_ed25519_ctx**)key_ctx);
}
}
#endif
#if LIBSSH2_RSA
if(strcmp("ssh-rsa", (const char *)buf) == 0) {
@@ -3180,14 +3751,25 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session,
{
libssh2_curve_type type;
if(_libssh2_ecdsa_curve_type_from_name((const char *)buf, &type) == 0) {
if(key_type == NULL || strcmp("ssh-ecdsa", key_type) == 0) {
rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type,
decrypted,
if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) {
rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session, decrypted,
method, method_len,
pubkeydata,
pubkeydata_len,
NULL,
NULL, NULL,
NULL,
(libssh2_ecdsa_ctx**)key_ctx);
}
else if(_libssh2_ecdsa_curve_type_from_name((const char *)buf, &type)
== 0) {
if(key_type == NULL || strcmp("ssh-ecdsa", key_type) == 0) {
rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type,
decrypted,
method, method_len,
pubkeydata,
pubkeydata_len,
(libssh2_ecdsa_ctx**)key_ctx);
}
}
}
@@ -3204,6 +3786,104 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session,
return rc;
}
static int
_libssh2_sk_pub_openssh_keyfilememory(LIBSSH2_SESSION *session,
void **key_ctx,
const char *key_type,
unsigned 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 *privatekeydata,
size_t privatekeydata_len,
unsigned const char *passphrase)
{
int rc;
unsigned char *buf = NULL;
struct string_buf *decrypted = NULL;
if(key_ctx != NULL)
*key_ctx = NULL;
if(session == NULL)
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Session is required");
if(key_type != NULL && strlen(key_type) < 7)
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"type is invalid");
_libssh2_init_if_needed();
rc = _libssh2_openssh_pem_parse_memory(session, passphrase,
privatekeydata,
privatekeydata_len, &decrypted);
if(rc)
return rc;
/* We have a new key file, now try and parse it using supported types */
rc = _libssh2_get_string(decrypted, &buf, NULL);
if(rc != 0 || buf == NULL)
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Public key type in decrypted "
"key data not found");
rc = LIBSSH2_ERROR_FILE;
#if LIBSSH2_ED25519
if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) {
*algorithm = LIBSSH2_HOSTKEY_TYPE_ED25519;
if(key_type == NULL ||
strcmp("sk-ssh-ed25519@openssh.com", key_type) == 0) {
rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session,
decrypted,
method,
method_len,
pubkeydata,
pubkeydata_len,
flags,
application,
key_handle,
handle_len,
(libssh2_ed25519_ctx**)key_ctx);
}
}
#endif
#if LIBSSH2_ECDSA
{
if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) {
*algorithm = LIBSSH2_HOSTKEY_TYPE_ECDSA_256;
rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session, decrypted,
method, method_len,
pubkeydata,
pubkeydata_len,
flags,
application,
key_handle,
handle_len,
(libssh2_ecdsa_ctx**)key_ctx);
}
}
#endif
if(rc == LIBSSH2_ERROR_FILE)
rc = _libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to extract public key from private key file: "
"invalid/unrecognized private key file format");
if(decrypted)
_libssh2_string_buf_free(session, decrypted);
return rc;
}
int
read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session,
const char *key_type,
@@ -3286,7 +3966,8 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
#if LIBSSH2_ECDSA
case EVP_PKEY_EC :
st = gen_publickey_from_ec_evp(session, method, method_len,
pubkeydata, pubkeydata_len, pk);
pubkeydata, pubkeydata_len,
0, pk);
break;
#endif /* LIBSSH2_ECDSA */
default :
@@ -3302,6 +3983,58 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
return st;
}
int
_libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session,
unsigned 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 *privatekeydata,
size_t privatekeydata_len,
const char *passphrase)
{
int st = -1;
BIO* bp;
EVP_PKEY* pk;
_libssh2_debug(session,
LIBSSH2_TRACE_AUTH,
"Computing public key from private key.");
bp = BIO_new_mem_buf((char *)privatekeydata, privatekeydata_len);
if(!bp)
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory when"
"computing public key");
BIO_reset(bp);
pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase);
BIO_free(bp);
if(pk == NULL) {
/* Try OpenSSH format */
st = _libssh2_sk_pub_openssh_keyfilememory(session, NULL, NULL,
method,
method_len,
pubkeydata,
pubkeydata_len,
algorithm,
flags,
application,
key_handle,
handle_len,
privatekeydata,
privatekeydata_len,
(unsigned const char *)passphrase);
}
return st;
}
void
_libssh2_dh_init(_libssh2_dh_ctx *dhctx)
{