1
0
mirror of https://github.com/libssh2/libssh2.git synced 2025-07-29 13:01:14 +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

85
docs/libssh2_sign_sk.3 Normal file
View File

@ -0,0 +1,85 @@
.TH libssh2_sign_sk 3 "1 Jun 2022" "libssh2 1.10.0" "libssh2 manual"
.SH NAME
libssh2_sign_sk - Create a signature from a FIDO2 authenticator.
.SH SYNOPSIS
#include <libssh2.h>
.nf
int libssh2_sign_sk(LIBSSH2_SESSION *session,
unsigned char **sig,
size_t *sig_len,
const unsigned char *data,
size_t data_len,
void **abstract);
typedef struct _LIBSSH2_PRIVKEY_SK {
int algorithm;
uint8_t flags;
const char *application;
const unsigned char *key_handle;
size_t handle_len;
LIBSSH2_USERAUTH_SK_SIGN_FUNC((*sign_callback));
void **orig_abstract;
} LIBSSH2_PRIVKEY_SK;
.SH DESCRIPTION
\fIsession\fP - Session instance as returned by
.BR libssh2_session_init_ex(3)
\fIsig\fP - A pointer to a buffer in which to place the signature. The caller
is responsible for freeing the signature with LIBSSH2_FREE.
\fIsig_len\fP - A pointer to the length of the sig parameter.
\fIdata\fP - The data to sign.
\fIdata_len\fP - The length of the data parameter.
\fIabstract\fP - A pointer to a pointer to a LIBSSH2_PRIVKEY_SK. See
description below.
Create a signature from a FIDO2 authenticator, using either the
sk-ssh-ed25519@openssh.com or sk-ecdsa-sha2-nistp256@openssh.com key
exchange algorithms.
The abstract parameter is a pointer to a pointer due to the internal workings
of libssh2. The LIBSSH2_PRIVKEY_SK must be completely filled out, and the
caller is responsible for all memory management of its fields.
\fIalgorithm\fP - The signing algorithm to use. Possible values are
LIBSSH2_HOSTKEY_TYPE_ED25519 and LIBSSH2_HOSTKEY_TYPE_ECDSA_256.
\fIflags\fP - A bitmask specifying options for the authenticator. When
LIBSSH2_SK_PRESENCE_REQUIRED is set, the authenticator requires a touch. When
LIBSSH2_SK_VERIFICATION_REQUIRED is set, the authenticator requires a PIN.
Many servers and authenticators do not work properly when
LIBSSH2_SK_PRESENCE_REQUIRED is not set.
\fIapplication\fP - A user-defined string to use as the RP name for the
authenticator. Usually "ssh:".
\fIkey_handle\fP - The key handle to use for the authenticator's allow list.
\fIhandle_len\fP - The length of the key_handle parameter.
\fIabstract\fP - User-defined data. When a PIN is required, use this to pass in
the PIN, or a function pointer to retrieve the PIN.
\fIkey_handle\fP The decoded key handle from the private key file.
\fIhandle_len\fP The length of the key_handle parameter.
\fIsign_callback\fP - Responsible for communicating with the hardware
authenticator to generate a signature. On success, the signature information
must be placed in the `\fIsig_info\fP sig_info parameter and the callback must
return 0. On failure, it should return a negative number. See
.BR libssh2_userauth_publickey_sk(3)
for more information.
\fIorig_abstract\fP - User-defined data. When a PIN is required, use this to
pass in the PIN, or a function pointer to retrieve the PIN.
.SH RETURN VALUE
Return 0 on success or negative on failure.
.SH SEE ALSO
.BR libssh2_userauth_publickey_sk(3)

View File

@ -0,0 +1,133 @@
.TH libssh2_userauth_publickey_sk 3 "1 Jun 2022" "libssh2 1.10.0" "libssh2 manual"
.SH NAME
libssh2_userauth_publickey_sk - authenticate a session with a FIDO2 authenticator
.SH SYNOPSIS
#include <libssh2.h>
.nf
int libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
const char *username,
size_t username_len,
const char *privatekeydata,
size_t privatekeydata_len,
const char *passphrase,
LIBSSH2_USERAUTH_SK_SIGN_FUNC
((*sign_callback)),
void **abstract);
.SH CALLBACK
.nf
#define LIBSSH2_SK_PRESENCE_REQUIRED 0x01
#define LIBSSH2_SK_VERIFICATION_REQUIRED 0x04
typedef struct _LIBSSH2_SK_SIG_INFO {
uint8_t flags;
uint32_t counter;
unsigned char *sig_r;
size_t sig_r_len;
unsigned char *sig_s;
size_t sig_s_len;
} LIBSSH2_SK_SIG_INFO;
int name(LIBSSH2_SESSION *session, LIBSSH2_SK_SIG_INFO *sig_info,
const unsigned char *data, size_t data_len, int algorithm,
uint8_t flags, const char *application,
const unsigned char *key_handle, size_t handle_len,
void **abstract);
.fi
.SH DESCRIPTION
\fIsession\fP - Session instance as returned by
.BR libssh2_session_init_ex(3)
\fIusername\fP - Name of user to attempt authentication for.
\fIusername_len\fP - Length of username parameter.
\fIprivatekeydata\fP - Buffer containing the contents of a private key file.
\fIprivatekeydata_len\fP - Length of private key data.
\fIpassphrase\fP - Passphrase to use when decoding private key file.
\fIsign_callback\fP - Callback to communicate with FIDO2 authenticator.
\fIabstract\fP - User-provided data to pass to callback.
Attempt FIDO2 authentication. using either the sk-ssh-ed25519@openssh.com or
sk-ecdsa-sha2-nistp256@openssh.com key exchange algorithms.
This function is only supported when libssh2 is backed by OpenSSL.
.SH CALLBACK DESCRIPTION
\fIsession\fP - Session instance as returned by
.BR libssh2_session_init_ex(3)
\fIsig_info\fP - Filled in by the callback with the signature and accompanying
information from the authenticator.
\fIdata\fP - The data to sign.
\fIdata_len\fP - The length of the data parameter.
\fIalgorithm\fP - The signing algorithm to use. Possible values are
LIBSSH2_HOSTKEY_TYPE_ED25519 and LIBSSH2_HOSTKEY_TYPE_ECDSA_256.
\fIflags\fP - A bitmask specifying options for the authenticator. When
LIBSSH2_SK_PRESENCE_REQUIRED is set, the authenticator requires a touch. When
LIBSSH2_SK_VERIFICATION_REQUIRED is set, the authenticator requires a PIN.
Many servers and authenticators do not work properly when
LIBSSH2_SK_PRESENCE_REQUIRED is not set.
\fIapplication\fP - A user-defined string to use as the RP name for the
authenticator. Usually "ssh:".
\fIkey_handle\fP - The key handle to use for the authenticator's allow list.
\fIhandle_len\fP - The length of the key_handle parameter.
\fIabstract\fP - User-defined data. When a PIN is required, use this to pass in
the PIN, or a function pointer to retrieve the PIN.
The \fIsign_callback\fP is responsible for communicating with the hardware
authenticator to generate a signature. On success, the signature information
must be placed in the `\fIsig_info\fP sig_info parameter and the callback must
return 0. On failure, it should return a negative number.
The fields of the LIBSSH2_SK_SIG_INFO are as follows.
\fIflags\fP - A bitmask specifying options for the authenticator. This should
be read from the authenticator and not merely copied from the flags parameter
to the callback.
\fIcounter\fP - A value returned from the authenticator.
\fIsig_r\fP - For Ed25519 signatures, this contains the entire signature, as
returned directly from the authenticator. For ECDSA signatures, this contains
the r component of the signature in a big-endian binary representation. For
both algorithms, use LIBSSH2_ALLOC to allocate memory. It will be freed by the
caller.
\fIsig_r_len\fP - The length of the sig_r parameter.
\fIsig_s\fP - For ECDSA signatures, this contains the s component of the
signature in a big-endian binary representation. Use LIBSSH2_ALLOC to allocate
memory. It will be freed by the caller. For Ed25519 signatures, set this to
NULL.
\fIsig_s_len\fP - The length of the sig_s parameter.
.SH RETURN VALUE
Return 0 on success or negative on failure. It returns
LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
.SH ERRORS
Some of the errors this function may return include:
\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
\fILIBSSH2_ERROR_AUTHENTICATION_FAILED\fP - failed, invalid username/key.
.SH SEE ALSO
.BR libssh2_session_init_ex(3)

View File

@ -283,6 +283,15 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
unsigned int length;
} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
typedef struct _LIBSSH2_SK_SIG_INFO {
uint8_t flags;
uint32_t counter;
unsigned char *sig_r;
size_t sig_r_len;
unsigned char *sig_s;
size_t sig_s_len;
} LIBSSH2_SK_SIG_INFO;
/* 'publickey' authentication callback */
#define LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC(name) \
int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \
@ -295,6 +304,17 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, \
LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract)
/* SK authentication callback */
#define LIBSSH2_USERAUTH_SK_SIGN_FUNC(name) \
int name(LIBSSH2_SESSION *session, LIBSSH2_SK_SIG_INFO *sig_info, \
const unsigned char *data, size_t data_len, int algorithm, uint8_t flags, \
const char *application, const unsigned char *key_handle, size_t handle_len, \
void **abstract)
/* Flags for SK authentication */
#define LIBSSH2_SK_PRESENCE_REQUIRED 0x01
#define LIBSSH2_SK_VERIFICATION_REQUIRED 0x04
/* Callbacks for special SSH packets */
#define LIBSSH2_IGNORE_FUNC(name) \
void name(LIBSSH2_SESSION *session, const char *message, int message_len, \
@ -368,6 +388,25 @@ typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
typedef struct _LIBSSH2_KNOWNHOSTS LIBSSH2_KNOWNHOSTS;
typedef struct _LIBSSH2_AGENT LIBSSH2_AGENT;
/* SK signature callback */
typedef struct _LIBSSH2_PRIVKEY_SK {
int algorithm;
uint8_t flags;
const char *application;
const unsigned char *key_handle;
size_t handle_len;
LIBSSH2_USERAUTH_SK_SIGN_FUNC((*sign_callback));
void **orig_abstract;
} LIBSSH2_PRIVKEY_SK;
int
libssh2_sign_sk(LIBSSH2_SESSION *session,
unsigned char **sig,
size_t *sig_len,
const unsigned char *data,
size_t data_len,
void **abstract);
typedef struct _LIBSSH2_POLLFD {
unsigned char type; /* LIBSSH2_POLLFD_* below */
@ -711,6 +750,17 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session,
(unsigned int)strlen(username), \
(response_callback))
LIBSSH2_API int
libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
const char *username,
size_t username_len,
const char *privatekeydata,
size_t privatekeydata_len,
const char *passphrase,
LIBSSH2_USERAUTH_SK_SIGN_FUNC
((*sign_callback)),
void **abstract);
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
long timeout);

View File

@ -147,12 +147,23 @@ _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ecdsactx,
const unsigned char *k,
size_t k_len,
libssh2_curve_type type);
int
_libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
LIBSSH2_SESSION * session,
const char *filename,
unsigned const char *passphrase);
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
_libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx,
const unsigned char *r, size_t r_len,
@ -182,6 +193,16 @@ int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx,
size_t filedata_len,
unsigned const char *passphrase);
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);
libssh2_curve_type
_libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx);
@ -211,6 +232,16 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx **ed_ctx,
LIBSSH2_SESSION *session,
const char *filename, const uint8_t *passphrase);
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
_libssh2_ed25519_new_public(libssh2_ed25519_ctx **ed_ctx,
LIBSSH2_SESSION *session,
@ -229,6 +260,17 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx **ed_ctx,
size_t filedata_len,
unsigned const char *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);
#endif /* LIBSSH2_ED25519 */
@ -259,6 +301,20 @@ int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
const char *passphrase);
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);
/**
* @function _libssh2_supported_key_sign_algorithms
* @abstract Returns supported algorithms used for upgrading public

View File

@ -627,6 +627,26 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
"Method unimplemented in libgcrypt backend");
}
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)
{
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to extract public SK key from private key file: "
"Method unimplemented in libgcrypt backend");
}
void _libssh2_init_aes_ctr(void)
{
/* no implementation */

View File

@ -741,6 +741,26 @@ _libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
return ret;
}
int
_libssh2_mbedtls_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)
{
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to extract public SK key from private key file: "
"Method unimplemented in mbedTLS backend");
}
void _libssh2_init_aes_ctr(void)
{
/* no implementation */

View File

@ -342,6 +342,10 @@ typedef enum {
pk, pk_len, pw) \
_libssh2_mbedtls_pub_priv_keyfilememory(s, m, m_len, p, p_len, \
pk, pk_len, pw)
#define _libssh2_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \
f, kh, kh_len, pk, pk_len, pw) \
_libssh2_mbedtls_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \
f, kh, kh_len, pk, pk_len, pw)
/*******************************************************************/

View File

@ -243,6 +243,30 @@ void _libssh2_store_str(unsigned char **buf, const char *str, size_t len)
}
}
/* _libssh2_store_bignum2_bytes
*/
void _libssh2_store_bignum2_bytes(unsigned char **buf,
const unsigned char *bytes,
size_t len)
{
int extraByte = 0;
const unsigned char *p;
for(p = bytes; len > 0 && *p == 0; --len, ++p) {}
extraByte = (len > 0 && (p[0] & 0x80) != 0);
_libssh2_store_u32(buf, len + extraByte);
if(extraByte) {
*buf[0] = 0;
*buf += 1;
}
if(len > 0) {
memcpy(*buf, p, len);
*buf += len;
}
}
/* Base64 Conversion */
static const short base64_reverse_table[256] = {

View File

@ -85,6 +85,9 @@ libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf);
void _libssh2_htonu32(unsigned char *buf, uint32_t val);
void _libssh2_store_u32(unsigned char **buf, uint32_t value);
void _libssh2_store_str(unsigned char **buf, const char *str, size_t len);
void _libssh2_store_bignum2_bytes(unsigned char **buf,
const unsigned char *bytes,
size_t len);
void *_libssh2_calloc(LIBSSH2_SESSION *session, size_t size);
void _libssh2_explicit_zero(void *buf, size_t size);

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 */
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,7 +3751,18 @@ _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(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,
@ -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)
{

View File

@ -2359,6 +2359,26 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
return ret;
}
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)
{
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to extract public SK key from private key file: "
"Method unimplemented in OS/400 QC3 backend");
}
int
_libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
const unsigned char *sig, unsigned long sig_len,

View File

@ -890,7 +890,106 @@ sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
return 0;
}
int
libssh2_sign_sk(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
const unsigned char *data, size_t data_len, void **abstract)
{
int rc = LIBSSH2_ERROR_DECRYPT;
LIBSSH2_PRIVKEY_SK *sk_info = (LIBSSH2_PRIVKEY_SK *) (*abstract);
LIBSSH2_SK_SIG_INFO sig_info = { 0 };
if(sk_info->handle_len <= 0) {
return LIBSSH2_ERROR_DECRYPT;
}
rc = sk_info->sign_callback(session,
&sig_info,
data,
data_len,
sk_info->algorithm,
sk_info->flags,
sk_info->application,
sk_info->key_handle,
sk_info->handle_len,
sk_info->orig_abstract);
if(rc == 0 && sig_info.sig_r_len > 0 && sig_info.sig_r) {
unsigned char *p = NULL;
if(sig_info.sig_s_len > 0 && sig_info.sig_s) {
/* sig length, sig_r, sig_s, flags, counter, plus 4 bytes for each
component's length, and up to 1 extra byte for each component */
*sig_len = 4 + 5 + sig_info.sig_r_len + 5 + sig_info.sig_s_len + 5;
*sig = LIBSSH2_ALLOC(session, *sig_len);
if(*sig) {
unsigned char *x = *sig;
p = *sig;
_libssh2_store_u32(&p, 0);
_libssh2_store_bignum2_bytes(&p,
sig_info.sig_r,
sig_info.sig_r_len);
_libssh2_store_bignum2_bytes(&p,
sig_info.sig_s,
sig_info.sig_s_len);
*sig_len = p - *sig;
_libssh2_store_u32(&x, *sig_len - 4);
}
else {
_libssh2_debug(session,
LIBSSH2_ERROR_ALLOC,
"Unable to allocate ecdsa-sk signature.");
rc = LIBSSH2_ERROR_ALLOC;
}
}
else {
/* sig, flags, counter, plus 4 bytes for sig length. */
*sig_len = 4 + sig_info.sig_r_len + 1 + 4;
*sig = LIBSSH2_ALLOC(session, *sig_len);
if(*sig) {
p = *sig;
_libssh2_store_str(&p,
(const char *)sig_info.sig_r,
sig_info.sig_r_len);
}
else {
_libssh2_debug(session,
LIBSSH2_ERROR_ALLOC,
"Unable to allocate ed25519-sk signature.");
rc = LIBSSH2_ERROR_ALLOC;
}
}
if(p) {
*p = sig_info.flags;
++p;
_libssh2_store_u32(&p, sig_info.counter);
*sig_len = p - *sig;
}
LIBSSH2_FREE(session, sig_info.sig_r);
if(sig_info.sig_s != NULL) {
LIBSSH2_FREE(session, sig_info.sig_s);
}
}
else {
_libssh2_debug(session,
LIBSSH2_ERROR_DECRYPT,
"sign_callback failed or returned invalid signature.");
*sig_len = 0;
}
return rc;
}
/* userauth_hostbased_fromfile
* Authenticate using a keypair found in the named files
@ -1603,16 +1702,32 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
plain_method_len((const char *)session->userauth_pblc_method,
session->userauth_pblc_method_len);
if(strncmp((const char *)session->userauth_pblc_method,
"sk-ecdsa-sha2-nistp256@openssh.com",
session->userauth_pblc_method_len) == 0 ||
strncmp((const char *)session->userauth_pblc_method,
"sk-ssh-ed25519@openssh.com",
session->userauth_pblc_method_len) == 0) {
_libssh2_store_u32(&s,
4 + session->userauth_pblc_method_len +
sig_len);
_libssh2_store_str(&s, (const char *)session->userauth_pblc_method,
session->userauth_pblc_method_len);
memcpy(s, sig, sig_len);
s += sig_len;
}
else {
_libssh2_store_u32(&s,
4 + session->userauth_pblc_method_len + 4 +
sig_len);
_libssh2_store_str(&s, (const char *)session->userauth_pblc_method,
session->userauth_pblc_method_len);
_libssh2_store_str(&s, (const char *)sig, sig_len);
}
LIBSSH2_FREE(session, session->userauth_pblc_method);
session->userauth_pblc_method = NULL;
_libssh2_store_str(&s, (const char *)sig, sig_len);
LIBSSH2_FREE(session, sig);
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
@ -2164,3 +2279,68 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session,
response_callback));
return rc;
}
/* libssh2_userauth_publickey_sk
* Authenticate using an external callback function
*/
LIBSSH2_API int
libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
const char *username,
size_t username_len,
const char *privatekeydata,
size_t privatekeydata_len,
const char *passphrase,
LIBSSH2_USERAUTH_SK_SIGN_FUNC
((*sign_callback)),
void **abstract)
{
unsigned char *pubkeydata = NULL;
size_t pubkeydata_len = 0;
LIBSSH2_PRIVKEY_SK sk_info = { 0 };
void *sign_abstract = &sk_info;
int rc;
sk_info.sign_callback = sign_callback;
sk_info.orig_abstract = abstract;
if(privatekeydata_len && privatekeydata) {
if(_libssh2_sk_pub_keyfilememory(session,
&session->userauth_pblc_method,
&session->userauth_pblc_method_len,
&pubkeydata, &pubkeydata_len,
&(sk_info.algorithm),
&(sk_info.flags),
&(sk_info.application),
&(sk_info.key_handle),
&(sk_info.handle_len),
privatekeydata, privatekeydata_len,
passphrase))
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to extract public key "
"from private key.");
}
else {
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
"Invalid data in public and private key.");
}
rc = _libssh2_userauth_publickey(session, username, username_len,
pubkeydata, pubkeydata_len,
libssh2_sign_sk, &sign_abstract);
while(rc == LIBSSH2_ERROR_EAGAIN) {
rc = _libssh2_userauth_publickey(session, username, username_len,
pubkeydata, pubkeydata_len,
libssh2_sign_sk, &sign_abstract);
}
if(pubkeydata)
LIBSSH2_FREE(session, pubkeydata);
if(sk_info.application) {
LIBSSH2_FREE(session, (void *)sk_info.application);
}
return rc;
}

View File

@ -1834,6 +1834,26 @@ _libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
#endif /* HAVE_LIBCRYPT32 */
}
int
_libssh2_wincng_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)
{
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to extract public SK key from private key file: "
"Method unimplemented in Windows CNG backend");
}
/*******************************************************************/
/*
* Windows CNG backend: Cipher functions

View File

@ -304,7 +304,10 @@ typedef struct __libssh2_wincng_key_ctx {
pk, pk_len, pw) \
_libssh2_wincng_pub_priv_keyfilememory(s, m, m_len, p, p_len, \
pk, pk_len, pw)
#define _libssh2_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \
f, kh, kh_len, pk, pk_len, pw) \
_libssh2_wincng_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \
f, kh, kh_len, pk, pk_len, pw)
/*******************************************************************/
/*

View File

@ -19,8 +19,8 @@ static void kbd_callback(const char *name, int name_len,
fprintf(stdout, "Kb-int name: %.*s\n", name_len, name);
fprintf(stdout, "Kb-int instruction: %.*s\n", instruct_len, instruct);
for(i = 0; i < num_prompts; ++i) {
fprintf(stdout, "Kb-int prompt %d: %.*s\n", i, prompts[i].length,
prompts[i].text);
fprintf(stdout, "Kb-int prompt %d: %.*s\n", i,
(int)prompts[i].length, prompts[i].text);
}
if(num_prompts == 1) {

View File

@ -21,8 +21,8 @@ static void kbd_callback(const char *name, int name_len,
fprintf(stdout, "Kb-int name: %.*s\n", name_len, name);
fprintf(stdout, "Kb-int instruction: %.*s\n", instruct_len, instruct);
for(i = 0; i < num_prompts; ++i) {
fprintf(stdout, "Kb-int prompt %d: %.*s\n", i, prompts[i].length,
prompts[i].text);
fprintf(stdout, "Kb-int prompt %d: %.*s\n", i,
(int)prompts[i].length, prompts[i].text);
}
if(num_prompts == 1) {