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:
85
docs/libssh2_sign_sk.3
Normal file
85
docs/libssh2_sign_sk.3
Normal 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)
|
133
docs/libssh2_userauth_publickey_sk.3
Normal file
133
docs/libssh2_userauth_publickey_sk.3
Normal 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)
|
@ -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);
|
||||
|
||||
|
56
src/crypto.h
56
src/crypto.h
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
|
24
src/misc.c
24
src/misc.c
@ -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] = {
|
||||
|
@ -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);
|
||||
|
||||
|
769
src/openssl.c
769
src/openssl.c
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
192
src/userauth.c
192
src/userauth.c
@ -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);
|
||||
|
||||
_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);
|
||||
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;
|
||||
}
|
||||
|
20
src/wincng.c
20
src/wincng.c
@ -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
|
||||
|
@ -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)
|
||||
|
||||
/*******************************************************************/
|
||||
/*
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
Reference in New Issue
Block a user