mirror of
https://github.com/libssh2/libssh2.git
synced 2025-11-21 14:00:51 +03:00
ssh-ed25519: Support PKIX + calc pubkey from private (#416)
Files: openssl.c/h Author: Zenju Notes: Adds support for PKIX key reading by fixing: _libssh2_pub_priv_keyfile() is missing the code to extract the ed25519 public key from a given private key _libssh2_ed25519_new_private_frommemory is only parsing the openssh key format but does not understand PKIX (as retrieved via PEM_read_bio_PrivateKey)
This commit is contained in:
170
src/openssl.c
170
src/openssl.c
@@ -759,7 +759,6 @@ _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
|
|||||||
|
|
||||||
pem_read_bio_func read_rsa =
|
pem_read_bio_func read_rsa =
|
||||||
(pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
|
(pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
|
||||||
(void) session;
|
|
||||||
|
|
||||||
_libssh2_init_if_needed();
|
_libssh2_init_if_needed();
|
||||||
|
|
||||||
@@ -831,7 +830,7 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session,
|
|||||||
|
|
||||||
_libssh2_debug(session,
|
_libssh2_debug(session,
|
||||||
LIBSSH2_TRACE_AUTH,
|
LIBSSH2_TRACE_AUTH,
|
||||||
"Computing public key from RSA private key envelop");
|
"Computing public key from RSA private key envelope");
|
||||||
|
|
||||||
rsa = EVP_PKEY_get1_RSA(pk);
|
rsa = EVP_PKEY_get1_RSA(pk);
|
||||||
if(rsa == NULL) {
|
if(rsa == NULL) {
|
||||||
@@ -1110,7 +1109,6 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
|||||||
|
|
||||||
pem_read_bio_func read_rsa =
|
pem_read_bio_func read_rsa =
|
||||||
(pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
|
(pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
|
||||||
(void) session;
|
|
||||||
|
|
||||||
_libssh2_init_if_needed();
|
_libssh2_init_if_needed();
|
||||||
|
|
||||||
@@ -1136,7 +1134,6 @@ _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
|
|||||||
|
|
||||||
pem_read_bio_func read_dsa =
|
pem_read_bio_func read_dsa =
|
||||||
(pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
|
(pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
|
||||||
(void) session;
|
|
||||||
|
|
||||||
_libssh2_init_if_needed();
|
_libssh2_init_if_needed();
|
||||||
|
|
||||||
@@ -1222,7 +1219,7 @@ gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session,
|
|||||||
|
|
||||||
_libssh2_debug(session,
|
_libssh2_debug(session,
|
||||||
LIBSSH2_TRACE_AUTH,
|
LIBSSH2_TRACE_AUTH,
|
||||||
"Computing public key from DSA private key envelop");
|
"Computing public key from DSA private key envelope");
|
||||||
|
|
||||||
dsa = EVP_PKEY_get1_DSA(pk);
|
dsa = EVP_PKEY_get1_DSA(pk);
|
||||||
if(dsa == NULL) {
|
if(dsa == NULL) {
|
||||||
@@ -1412,7 +1409,6 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
|||||||
|
|
||||||
pem_read_bio_func read_dsa =
|
pem_read_bio_func read_dsa =
|
||||||
(pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
|
(pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
|
||||||
(void) session;
|
|
||||||
|
|
||||||
_libssh2_init_if_needed();
|
_libssh2_init_if_needed();
|
||||||
|
|
||||||
@@ -1441,7 +1437,6 @@ _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx,
|
|||||||
|
|
||||||
pem_read_bio_func read_ec =
|
pem_read_bio_func read_ec =
|
||||||
(pem_read_bio_func) &PEM_read_bio_ECPrivateKey;
|
(pem_read_bio_func) &PEM_read_bio_ECPrivateKey;
|
||||||
(void) session;
|
|
||||||
|
|
||||||
_libssh2_init_if_needed();
|
_libssh2_init_if_needed();
|
||||||
|
|
||||||
@@ -1526,24 +1521,10 @@ _libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_x25519_ctx **out_ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(out_ctx != NULL) {
|
if(out_ctx != NULL) {
|
||||||
ctx = malloc(sizeof(libssh2_x25519_ctx));
|
ctx = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, priv,
|
||||||
if(ctx == NULL)
|
|
||||||
goto cleanExit;
|
|
||||||
|
|
||||||
ctx->private_key =
|
|
||||||
EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL,
|
|
||||||
(const unsigned char *)priv,
|
|
||||||
LIBSSH2_ED25519_KEY_LEN);
|
LIBSSH2_ED25519_KEY_LEN);
|
||||||
|
if(!ctx)
|
||||||
ctx->public_key =
|
|
||||||
EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
|
|
||||||
(const unsigned char *)pub,
|
|
||||||
LIBSSH2_ED25519_KEY_LEN);
|
|
||||||
|
|
||||||
if(ctx->public_key == NULL || ctx->private_key == NULL) {
|
|
||||||
_libssh2_x25519_free(ctx);
|
|
||||||
goto cleanExit;
|
goto cleanExit;
|
||||||
}
|
|
||||||
|
|
||||||
*out_ctx = ctx;
|
*out_ctx = ctx;
|
||||||
}
|
}
|
||||||
@@ -1567,6 +1548,72 @@ cleanExit:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
gen_publickey_from_ed_evp(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char **method,
|
||||||
|
size_t *method_len,
|
||||||
|
unsigned char **pubkeydata,
|
||||||
|
size_t *pubkeydata_len,
|
||||||
|
EVP_PKEY *pk)
|
||||||
|
{
|
||||||
|
const char methodName[] = "ssh-ed25519";
|
||||||
|
unsigned char *methodBuf = NULL;
|
||||||
|
size_t rawKeyLen = 0;
|
||||||
|
unsigned char *keyBuf = NULL;
|
||||||
|
size_t bufLen = 0;
|
||||||
|
unsigned char *bufPos = NULL;
|
||||||
|
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||||
|
"Computing public key from ED private key envelope");
|
||||||
|
|
||||||
|
methodBuf = LIBSSH2_ALLOC(session, sizeof(methodName) - 1);
|
||||||
|
if(!methodBuf) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for private key data");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
memcpy(methodBuf, methodName, sizeof(methodName) - 1);
|
||||||
|
|
||||||
|
if(EVP_PKEY_get_raw_public_key(pk, NULL, &rawKeyLen) != 1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"EVP_PKEY_get_raw_public_key failed");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Key form is: type_len(4) + type(11) + pub_key_len(4) + pub_key(32). */
|
||||||
|
bufLen = 4 + sizeof(methodName) - 1 + 4 + rawKeyLen;
|
||||||
|
bufPos = keyBuf = LIBSSH2_ALLOC(session, bufLen);
|
||||||
|
if(!keyBuf) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for private key data");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
_libssh2_store_str(&bufPos, methodName, sizeof(methodName) - 1);
|
||||||
|
_libssh2_store_u32(&bufPos, rawKeyLen);
|
||||||
|
|
||||||
|
if(EVP_PKEY_get_raw_public_key(pk, bufPos, &rawKeyLen) != 1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"EVP_PKEY_get_raw_public_key failed");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
*method = methodBuf;
|
||||||
|
*method_len = sizeof(methodName) - 1;
|
||||||
|
*pubkeydata = keyBuf;
|
||||||
|
*pubkeydata_len = bufLen;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if(methodBuf)
|
||||||
|
LIBSSH2_FREE(session, methodBuf);
|
||||||
|
if(keyBuf)
|
||||||
|
LIBSSH2_FREE(session, keyBuf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
|
gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
|
||||||
struct string_buf *decrypted,
|
struct string_buf *decrypted,
|
||||||
@@ -1603,26 +1650,12 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
|
|||||||
goto clean_exit;
|
goto clean_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = _libssh2_ed25519_new_ctx();
|
|
||||||
if(ctx == NULL) {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
||||||
"Unable to allocate memory for ed25519 key");
|
|
||||||
ret = -1;
|
|
||||||
goto clean_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* first 32 bytes of priv_key is the private key, the last 32 bytes are
|
/* first 32 bytes of priv_key is the private key, the last 32 bytes are
|
||||||
the public key */
|
the public key */
|
||||||
ctx->private_key =
|
ctx = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
|
||||||
EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
|
|
||||||
(const unsigned char *)priv_key,
|
(const unsigned char *)priv_key,
|
||||||
LIBSSH2_ED25519_KEY_LEN);
|
LIBSSH2_ED25519_KEY_LEN);
|
||||||
|
|
||||||
ctx->public_key =
|
|
||||||
EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
|
|
||||||
(const unsigned char *)pub_key,
|
|
||||||
LIBSSH2_ED25519_KEY_LEN);
|
|
||||||
|
|
||||||
/* comment */
|
/* comment */
|
||||||
if(_libssh2_get_string(decrypted, &buf, &tmp_len)) {
|
if(_libssh2_get_string(decrypted, &buf, &tmp_len)) {
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
@@ -1661,7 +1694,7 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
|
|||||||
_libssh2_debug(session,
|
_libssh2_debug(session,
|
||||||
LIBSSH2_TRACE_AUTH,
|
LIBSSH2_TRACE_AUTH,
|
||||||
"Computing public key from ED25519 "
|
"Computing public key from ED25519 "
|
||||||
"private key envelop");
|
"private key envelope");
|
||||||
|
|
||||||
method_buf = LIBSSH2_ALLOC(session, 11); /* ssh-ed25519. */
|
method_buf = LIBSSH2_ALLOC(session, 11); /* ssh-ed25519. */
|
||||||
if(method_buf == NULL) {
|
if(method_buf == NULL) {
|
||||||
@@ -1795,6 +1828,24 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx,
|
|||||||
size_t filedata_len,
|
size_t filedata_len,
|
||||||
unsigned const char *passphrase)
|
unsigned const char *passphrase)
|
||||||
{
|
{
|
||||||
|
libssh2_ed25519_ctx *ctx = NULL;
|
||||||
|
|
||||||
|
_libssh2_init_if_needed();
|
||||||
|
|
||||||
|
if(read_private_key_from_memory((void **)&ctx,
|
||||||
|
(pem_read_bio_func)
|
||||||
|
&PEM_read_bio_PrivateKey,
|
||||||
|
filedata, filedata_len, passphrase) == 0) {
|
||||||
|
if(EVP_PKEY_id(ctx) != EVP_PKEY_ED25519) {
|
||||||
|
_libssh2_ed25519_free(ctx);
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Private key is not an ED25519 key");
|
||||||
|
}
|
||||||
|
|
||||||
|
*ed_ctx = ctx;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return read_openssh_private_key_from_memory((void **)ed_ctx, session,
|
return read_openssh_private_key_from_memory((void **)ed_ctx, session,
|
||||||
"ssh-ed25519",
|
"ssh-ed25519",
|
||||||
filedata, filedata_len,
|
filedata, filedata_len,
|
||||||
@@ -1808,38 +1859,26 @@ _libssh2_ed25519_new_public(libssh2_ed25519_ctx ** ed_ctx,
|
|||||||
const uint8_t key_len)
|
const uint8_t key_len)
|
||||||
{
|
{
|
||||||
libssh2_ed25519_ctx *ctx = NULL;
|
libssh2_ed25519_ctx *ctx = NULL;
|
||||||
EVP_PKEY *public_key = NULL;
|
|
||||||
|
|
||||||
if(ed_ctx == NULL)
|
if(ed_ctx == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
public_key =
|
ctx = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
|
||||||
EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
|
raw_pub_key, key_len);
|
||||||
(const unsigned char *)raw_pub_key,
|
if(!ctx)
|
||||||
key_len);
|
|
||||||
if(public_key == NULL) {
|
|
||||||
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
"could not create ED25519 public key");
|
"could not create ED25519 public key");
|
||||||
}
|
|
||||||
|
|
||||||
ctx = _libssh2_ed25519_new_ctx();
|
|
||||||
if(ctx == NULL) {
|
|
||||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
||||||
"could not alloc public/private key");
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->public_key = public_key;
|
|
||||||
|
|
||||||
if(ed_ctx != NULL)
|
if(ed_ctx != NULL)
|
||||||
*ed_ctx = ctx;
|
*ed_ctx = ctx;
|
||||||
else if(ctx != NULL)
|
else if(ctx)
|
||||||
_libssh2_ed25519_free(ctx);
|
_libssh2_ed25519_free(ctx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* LIBSSH2_ED25519 */
|
#endif /* LIBSSH2_ED25519 */
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
||||||
libssh2_rsa_ctx * rsactx,
|
libssh2_rsa_ctx * rsactx,
|
||||||
@@ -2234,7 +2273,7 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
|
|||||||
|
|
||||||
_libssh2_debug(session,
|
_libssh2_debug(session,
|
||||||
LIBSSH2_TRACE_AUTH,
|
LIBSSH2_TRACE_AUTH,
|
||||||
"Computing public key from EC private key envelop");
|
"Computing public key from EC private key envelope");
|
||||||
|
|
||||||
bn_ctx = BN_CTX_new();
|
bn_ctx = BN_CTX_new();
|
||||||
if(bn_ctx == NULL)
|
if(bn_ctx == NULL)
|
||||||
@@ -2492,7 +2531,6 @@ _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey;
|
pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey;
|
||||||
(void) session;
|
|
||||||
|
|
||||||
_libssh2_init_if_needed();
|
_libssh2_init_if_needed();
|
||||||
|
|
||||||
@@ -2665,7 +2703,7 @@ _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session,
|
|||||||
unsigned char *sig = NULL;
|
unsigned char *sig = NULL;
|
||||||
|
|
||||||
if(md_ctx != NULL) {
|
if(md_ctx != NULL) {
|
||||||
if(EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, ctx->private_key) != 1)
|
if(EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, ctx) != 1)
|
||||||
goto clean_exit;
|
goto clean_exit;
|
||||||
if(EVP_DigestSign(md_ctx, NULL, &sig_len, message, message_len) != 1)
|
if(EVP_DigestSign(md_ctx, NULL, &sig_len, message, message_len) != 1)
|
||||||
goto clean_exit;
|
goto clean_exit;
|
||||||
@@ -2782,7 +2820,7 @@ _libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s,
|
|||||||
if(NULL == md_ctx)
|
if(NULL == md_ctx)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, ctx->public_key);
|
ret = EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, ctx);
|
||||||
if(ret != 1)
|
if(ret != 1)
|
||||||
goto clean_exit;
|
goto clean_exit;
|
||||||
|
|
||||||
@@ -2959,6 +2997,12 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch(pktype) {
|
switch(pktype) {
|
||||||
|
#if LIBSSH2_ED25519
|
||||||
|
case EVP_PKEY_ED25519 :
|
||||||
|
st = gen_publickey_from_ed_evp(
|
||||||
|
session, method, method_len, pubkeydata, pubkeydata_len, pk);
|
||||||
|
break;
|
||||||
|
#endif /* LIBSSH2_ED25519 */
|
||||||
case EVP_PKEY_RSA :
|
case EVP_PKEY_RSA :
|
||||||
st = gen_publickey_from_rsa_evp(
|
st = gen_publickey_from_rsa_evp(
|
||||||
session, method, method_len, pubkeydata, pubkeydata_len, pk);
|
session, method, method_len, pubkeydata, pubkeydata_len, pk);
|
||||||
@@ -3171,6 +3215,12 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch(pktype) {
|
switch(pktype) {
|
||||||
|
#if LIBSSH2_ED25519
|
||||||
|
case EVP_PKEY_ED25519 :
|
||||||
|
st = gen_publickey_from_ed_evp(
|
||||||
|
session, method, method_len, pubkeydata, pubkeydata_len, pk);
|
||||||
|
break;
|
||||||
|
#endif /* LIBSSH2_ED25519 */
|
||||||
case EVP_PKEY_RSA :
|
case EVP_PKEY_RSA :
|
||||||
st = gen_publickey_from_rsa_evp(session, method, method_len,
|
st = gen_publickey_from_rsa_evp(session, method, method_len,
|
||||||
pubkeydata, pubkeydata_len, pk);
|
pubkeydata, pubkeydata_len, pk);
|
||||||
|
|||||||
@@ -322,26 +322,11 @@ libssh2_curve_type;
|
|||||||
#endif /* LIBSSH2_ECDSA */
|
#endif /* LIBSSH2_ECDSA */
|
||||||
|
|
||||||
#if LIBSSH2_ED25519
|
#if LIBSSH2_ED25519
|
||||||
|
#define libssh2_ed25519_ctx EVP_PKEY
|
||||||
|
#define libssh2_x25519_ctx EVP_PKEY
|
||||||
|
|
||||||
typedef struct {
|
#define _libssh2_ed25519_free(ctx) EVP_PKEY_free(ctx)
|
||||||
EVP_PKEY *public_key;
|
#define _libssh2_x25519_free(ctx) EVP_PKEY_free(ctx)
|
||||||
EVP_PKEY *private_key;
|
|
||||||
} libssh2_curve25519_keys;
|
|
||||||
|
|
||||||
#define libssh2_ed25519_ctx libssh2_curve25519_keys
|
|
||||||
#define libssh2_x25519_ctx libssh2_curve25519_keys
|
|
||||||
|
|
||||||
#define _libssh2_ed25519_new_ctx() calloc(1, sizeof(libssh2_ed25519_ctx))
|
|
||||||
#define _libssh2_ed25519_free(ctx) do { \
|
|
||||||
if(ctx) { \
|
|
||||||
if(ctx->public_key) EVP_PKEY_free(ctx->public_key); \
|
|
||||||
if(ctx->private_key) EVP_PKEY_free(ctx->private_key); \
|
|
||||||
free(ctx); \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define _libssh2_x25519_free(ctx) _libssh2_ed25519_free(ctx)
|
|
||||||
|
|
||||||
#endif /* ED25519 */
|
#endif /* ED25519 */
|
||||||
|
|
||||||
#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
|
#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
|
||||||
|
|||||||
Reference in New Issue
Block a user