diff options
Diffstat (limited to 'libs/libssh2/src/userauth.c')
-rw-r--r-- | libs/libssh2/src/userauth.c | 963 |
1 files changed, 639 insertions, 324 deletions
diff --git a/libs/libssh2/src/userauth.c b/libs/libssh2/src/userauth.c index 949dc1c660..e7578759f3 100644 --- a/libs/libssh2/src/userauth.c +++ b/libs/libssh2/src/userauth.c @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2005 Mikhail Gusarov <dottedmag@dottedmag.net> - * Copyright (c) 2009-2014 by Daniel Stenberg +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Mikhail Gusarov <dottedmag@dottedmag.net> + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,14 +35,13 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" #include <ctype.h> -#include <stdio.h> - -#include <assert.h> /* Needed for struct iovec on some platforms */ #ifdef HAVE_SYS_UIO_H @@ -52,8 +51,9 @@ #include "transport.h" #include "session.h" #include "userauth.h" +#include "userauth_kbd_packet.h" -/* libssh2_userauth_list +/* userauth_list * * List authentication methods * Will yield successful login if "none" happens to be allowable for this user @@ -63,11 +63,13 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len) { - static const unsigned char reply_codes[3] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; + unsigned char reply_codes[4] = + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, + SSH_MSG_USERAUTH_BANNER, 0 }; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" + method_len(4) = 27 */ unsigned long methods_len; + unsigned int banner_len; unsigned char *s; int rc; @@ -134,6 +136,57 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, return NULL; } + if(session->userauth_list_data[0] == SSH_MSG_USERAUTH_BANNER) { + if(session->userauth_list_data_len < 5) { + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Unexpected packet size"); + return NULL; + } + banner_len = _libssh2_ntohu32(session->userauth_list_data + 1); + if(banner_len > session->userauth_list_data_len - 5) { + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Unexpected userauth banner size"); + return NULL; + } + session->userauth_banner = LIBSSH2_ALLOC(session, banner_len + 1); + if(!session->userauth_banner) { + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for userauth_banner"); + return NULL; + } + memcpy(session->userauth_banner, session->userauth_list_data + 5, + banner_len); + session->userauth_banner[banner_len] = '\0'; + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Banner: %s", + session->userauth_banner)); + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + /* SSH_MSG_USERAUTH_BANNER has been handled */ + reply_codes[2] = 0; + rc = _libssh2_packet_requirev(session, reply_codes, + &session->userauth_list_data, + &session->userauth_list_data_len, 0, + NULL, 0, + &session->userauth_list_packet_requirev_state); + if(rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block requesting userauth list"); + return NULL; + } + else if(rc || (session->userauth_list_data_len < 1)) { + _libssh2_error(session, rc, "Failed getting response"); + session->userauth_list_state = libssh2_NB_state_idle; + return NULL; + } + } + if(session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) { /* Wow, who'dve thought... */ _libssh2_error(session, LIBSSH2_ERROR_NONE, "No error"); @@ -163,13 +216,13 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, memmove(session->userauth_list_data, session->userauth_list_data + 5, methods_len); session->userauth_list_data[methods_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Permitted auth methods: %s", - session->userauth_list_data); + session->userauth_list_data)); } session->userauth_list_state = libssh2_NB_state_idle; - return (char *) session->userauth_list_data; + return (char *)session->userauth_list_data; } /* libssh2_userauth_list @@ -189,6 +242,30 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user, return ptr; } +/* libssh2_userauth_banner + * + * Retrieve banner message from server, if available. + * When no such message is sent by server or if no authentication attempt has + * been made, this function returns LIBSSH2_ERROR_MISSING_AUTH_BANNER. + */ +LIBSSH2_API int +libssh2_userauth_banner(LIBSSH2_SESSION *session, char **banner) +{ + if(!session) + return LIBSSH2_ERROR_MISSING_USERAUTH_BANNER; + + if(!session->userauth_banner) { + return _libssh2_error(session, + LIBSSH2_ERROR_MISSING_USERAUTH_BANNER, + "Missing userauth banner"); + } + + if(banner) + *banner = session->userauth_banner; + + return LIBSSH2_ERROR_NONE; +} + /* * libssh2_userauth_authenticated * @@ -198,7 +275,7 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user, LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION * session) { - return (session->state & LIBSSH2_STATE_AUTHENTICATED)?1:0; + return (session->state & LIBSSH2_STATE_AUTHENTICATED) ? 1 : 0; } @@ -251,8 +328,8 @@ userauth_password(LIBSSH2_SESSION *session, _libssh2_store_u32(&s, password_len); /* 'password' is sent separately */ - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting to login using password authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting to login using password authentication")); session->userauth_pswd_state = libssh2_NB_state_created; } @@ -279,7 +356,7 @@ userauth_password(LIBSSH2_SESSION *session, session->userauth_pswd_state = libssh2_NB_state_sent; } - password_response: +password_response: if((session->userauth_pswd_state == libssh2_NB_state_sent) || (session->userauth_pswd_state == libssh2_NB_state_sent1) @@ -306,8 +383,8 @@ userauth_password(LIBSSH2_SESSION *session, } if(session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password authentication successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Password authentication successful")); LIBSSH2_FREE(session, session->userauth_pswd_data); session->userauth_pswd_data = NULL; session->state |= LIBSSH2_STATE_AUTHENTICATED; @@ -316,8 +393,8 @@ userauth_password(LIBSSH2_SESSION *session, } else if(session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_FAILURE) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password authentication failed"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Password authentication failed")); LIBSSH2_FREE(session, session->userauth_pswd_data); session->userauth_pswd_data = NULL; session->userauth_pswd_state = libssh2_NB_state_idle; @@ -348,8 +425,8 @@ userauth_password(LIBSSH2_SESSION *session, if((session->userauth_pswd_state == libssh2_NB_state_sent1) || (session->userauth_pswd_state == libssh2_NB_state_sent2)) { if(session->userauth_pswd_state == libssh2_NB_state_sent1) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password change required"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Password change required")); LIBSSH2_FREE(session, session->userauth_pswd_data); session->userauth_pswd_data = NULL; } @@ -490,7 +567,7 @@ memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, { unsigned char *pubkey = NULL, *sp1, *sp2, *tmp; size_t pubkey_len = pubkeyfiledata_len; - unsigned int tmp_len; + size_t tmp_len; if(pubkeyfiledata_len <= 1) { return _libssh2_error(session, LIBSSH2_ERROR_FILE, @@ -518,7 +595,7 @@ memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, } sp1 = memchr(pubkey, ' ', pubkey_len); - if(sp1 == NULL) { + if(!sp1) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data"); @@ -527,16 +604,17 @@ memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, sp1++; sp2 = memchr(sp1, ' ', pubkey_len - (sp1 - pubkey)); - if(sp2 == NULL) { + if(!sp2) { /* Assume that the id string is missing, but that it's okay */ sp2 = pubkey + pubkey_len; } - if(libssh2_base64_decode(session, (char **) &tmp, &tmp_len, - (char *) sp1, sp2 - sp1)) { + if(_libssh2_base64_decode(session, (char **)&tmp, &tmp_len, + (const char *)sp1, + sp2 - sp1)) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid key data, not base64 encoded"); + "Invalid key data, not base64 encoded"); } /* Wasting some bytes here (okay, more than some), but since it's likely @@ -573,10 +651,10 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, char c; unsigned char *pubkey = NULL, *sp1, *sp2, *tmp; size_t pubkey_len = 0, sp_len; - unsigned int tmp_len; + size_t tmp_len; - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s", - pubkeyfile); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s", + pubkeyfile)); /* Read Public Key */ fd = fopen(pubkeyfile, FOPEN_READTEXT); if(!fd) { @@ -621,7 +699,7 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, } sp1 = memchr(pubkey, ' ', pubkey_len); - if(sp1 == NULL) { + if(!sp1) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data"); @@ -629,15 +707,16 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, sp1++; - sp_len = sp1 > pubkey ? (sp1 - pubkey) - 1 : 0; + sp_len = sp1 > pubkey ? (sp1 - pubkey) : 0; sp2 = memchr(sp1, ' ', pubkey_len - sp_len); - if(sp2 == NULL) { + if(!sp2) { /* Assume that the id string is missing, but that it's okay */ sp2 = pubkey + pubkey_len; } - if(libssh2_base64_decode(session, (char **) &tmp, &tmp_len, - (char *) sp1, sp2 - sp1)) { + if(_libssh2_base64_decode(session, (char **)&tmp, &tmp_len, + (const char *)sp1, + sp2 - sp1)) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid key data, not base64 encoded"); @@ -659,7 +738,7 @@ static int memory_read_privatekey(LIBSSH2_SESSION * session, const LIBSSH2_HOSTKEY_METHOD ** hostkey_method, void **hostkey_abstract, - const unsigned char *method, int method_len, + const unsigned char *method, size_t method_len, const char *privkeyfiledata, size_t privkeyfiledata_len, const char *passphrase) { @@ -687,7 +766,7 @@ memory_read_privatekey(LIBSSH2_SESSION * session, (unsigned char *) passphrase, hostkey_abstract)) { return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to initialize private key from file"); + "Unable to initialize private key from memory"); } return 0; @@ -700,14 +779,14 @@ static int file_read_privatekey(LIBSSH2_SESSION * session, const LIBSSH2_HOSTKEY_METHOD ** hostkey_method, void **hostkey_abstract, - const unsigned char *method, int method_len, + const unsigned char *method, size_t method_len, const char *privkeyfile, const char *passphrase) { const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods(); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading private key file: %s", - privkeyfile); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Loading private key file: %s", privkeyfile)); *hostkey_method = NULL; *hostkey_abstract = NULL; while(*hostkey_methods_avail && (*hostkey_methods_avail)->name) { @@ -763,7 +842,7 @@ sign_frommemory(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, datavec.iov_len = data_len; if(privkeyobj->signv(session, sig, sig_len, 1, &datavec, - &hostkey_abstract)) { + &hostkey_abstract)) { if(privkeyobj->dtor) { privkeyobj->dtor(session, &hostkey_abstract); } @@ -799,7 +878,7 @@ sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, datavec.iov_len = data_len; if(privkeyobj->signv(session, sig, sig_len, 1, &datavec, - &hostkey_abstract)) { + &hostkey_abstract)) { if(privkeyobj->dtor) { privkeyobj->dtor(session, &hostkey_abstract); } @@ -812,7 +891,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, (uint32_t)(*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) { + 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 @@ -828,11 +1006,6 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, { int rc; -#if !LIBSSH2_RSA - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "RSA is not supported by crypto backend"); -#endif - if(session->userauth_host_state == libssh2_NB_state_idle) { const LIBSSH2_HOSTKEY_METHOD *privkeyobj; unsigned char *pubkeydata = NULL; @@ -863,7 +1036,7 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, &pubkeydata, &pubkeydata_len, privatekey, passphrase); if(rc) - /* libssh2_pub_priv_keyfile calls _libssh2_error() */ + /* libssh2_pub_priv_keyfile() calls _libssh2_error() */ return rc; } @@ -932,8 +1105,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, datavec[2].iov_len = session->userauth_host_packet_len; if(privkeyobj && privkeyobj->signv && - privkeyobj->signv(session, &sig, &sig_len, 3, - datavec, &abstract)) { + privkeyobj->signv(session, &sig, &sig_len, 3, + datavec, &abstract)) { LIBSSH2_FREE(session, session->userauth_host_method); session->userauth_host_method = NULL; LIBSSH2_FREE(session, session->userauth_host_packet); @@ -972,8 +1145,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, session->userauth_host_packet + session->userauth_host_packet_len; _libssh2_store_u32(&session->userauth_host_s, - 4 + session->userauth_host_method_len + - 4 + sig_len); + (uint32_t)(4 + session->userauth_host_method_len + + 4 + sig_len)); _libssh2_store_str(&session->userauth_host_s, (const char *)session->userauth_host_method, session->userauth_host_method_len); @@ -984,8 +1157,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, sig_len); LIBSSH2_FREE(session, sig); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting hostbased authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting hostbased authentication")); session->userauth_host_state = libssh2_NB_state_created; } @@ -1033,8 +1206,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, } if(session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Hostbased authentication successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Hostbased authentication successful")); /* We are us and we've proved it. */ LIBSSH2_FREE(session, session->userauth_host_data); session->userauth_host_data = NULL; @@ -1075,14 +1248,196 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, return rc; } +size_t plain_method(char *method, size_t method_len) +{ + if(!strncmp("ssh-rsa-cert-v01@openssh.com", + method, + method_len)) { + return 7; + } + + if(!strncmp("ecdsa-sha2-nistp256-cert-v01@openssh.com", + method, + method_len) || + !strncmp("ecdsa-sha2-nistp384-cert-v01@openssh.com", + method, + method_len) || + !strncmp("ecdsa-sha2-nistp521-cert-v01@openssh.com", + method, + method_len)) { + return 19; + } + + if(!strncmp("ssh-ed25519-cert-v01@openssh.com", + method, + method_len)) { + return 11; + } + + if(!strncmp("sk-ecdsa-sha2-nistp256-cert-v01@openssh.com", + method, + method_len)) { + const char *new_method = "sk-ecdsa-sha2-nistp256@openssh.com"; + memcpy(method, new_method, strlen(new_method)); + return strlen(new_method); + } + + if(!strncmp("sk-ssh-ed25519-cert-v01@openssh.com", + method, + method_len)) { + const char *new_method = "sk-ssh-ed25519@openssh.com"; + memcpy(method, new_method, strlen(new_method)); + return strlen(new_method); + } + + return method_len; +} + +/** + * @function _libssh2_key_sign_algorithm + * @abstract Upgrades the algorithm used for public key signing RFC 8332 + * @discussion Based on the incoming key_method value, this function + * will upgrade the key method input based on user preferences, + * server support algos and crypto backend support + * @related _libssh2_supported_key_sign_algorithms() + * @param key_method current key method, usually the default key sig method + * @param key_method_len length of the key method buffer + * @result error code or zero on success + */ + +static int +_libssh2_key_sign_algorithm(LIBSSH2_SESSION *session, + unsigned char **key_method, + size_t *key_method_len) +{ + const char *s = NULL; + const char *a = NULL; + const char *match = NULL; + const char *p = NULL; + const char *f = NULL; + char *i = NULL; + size_t p_len = 0; + size_t f_len = 0; + int rc = 0; + size_t match_len = 0; + char *filtered_algs = NULL; + + const char *supported_algs = + _libssh2_supported_key_sign_algorithms(session, + *key_method, + *key_method_len); + + if(!supported_algs || !session->server_sign_algorithms) { + /* no upgrading key algorithm supported, do nothing */ + return LIBSSH2_ERROR_NONE; + } + + filtered_algs = LIBSSH2_ALLOC(session, strlen(supported_algs) + 1); + if(!filtered_algs) { + rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate filtered algs"); + return rc; + } + + s = session->server_sign_algorithms; + i = filtered_algs; + + /* this walks the server algo list and the supported algo list and creates + a filtered list that includes matches */ + + while(s && *s) { + p = strchr(s, ','); + p_len = (p ? (size_t)(p - s) : strlen(s)); + a = supported_algs; + + while(a && *a) { + f = strchr(a, ','); + f_len = (f ? (size_t)(f - a) : strlen(a)); + + if(f_len == p_len && memcmp(a, s, p_len) == 0) { + + if(i != filtered_algs) { + memcpy(i, ",", 1); + i += 1; + } + + memcpy(i, s, p_len); + i += p_len; + } + + a = f ? (f + 1) : NULL; + } + + s = p ? (p + 1) : NULL; + } + + filtered_algs[i - filtered_algs] = '\0'; + if(session->sign_algo_prefs) { + s = session->sign_algo_prefs; + } + else { + s = supported_algs; + } + + /* now that we have the possible supported algos, match based on the prefs + or what is supported by the crypto backend, look for a match */ + + while(s && *s && !match) { + p = strchr(s, ','); + p_len = (p ? (size_t)(p - s) : strlen(s)); + a = filtered_algs; + + while(a && *a && !match) { + f = strchr(a, ','); + f_len = (f ? (size_t)(f - a) : strlen(a)); + + if(f_len == p_len && memcmp(a, s, p_len) == 0) { + /* found a match, upgrade key method */ + match = s; + match_len = p_len; + } + else { + a = f ? (f + 1) : NULL; + } + } + + s = p ? (p + 1) : NULL; + } + + if(match) { + if(*key_method) + LIBSSH2_FREE(session, *key_method); + + *key_method = LIBSSH2_ALLOC(session, match_len); + if(key_method) { + memcpy(*key_method, match, match_len); + *key_method_len = match_len; + } + else { + *key_method_len = 0; + rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate key method upgrade"); + } + } + else { + /* no match was found */ + rc = _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, + "No signing signature matched"); + } + + if(filtered_algs) + LIBSSH2_FREE(session, filtered_algs); + + return rc; +} int _libssh2_userauth_publickey(LIBSSH2_SESSION *session, const char *username, - unsigned int username_len, + size_t username_len, const unsigned char *pubkeydata, - unsigned long pubkeydata_len, + size_t pubkeydata_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC ((*sign_callback)), void *abstract) @@ -1093,6 +1448,10 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, }; int rc; unsigned char *s; + int auth_attempts = 0; + +retry_auth: + auth_attempts++; if(session->userauth_pblc_state == libssh2_NB_state_idle) { @@ -1118,9 +1477,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata); if(session->userauth_pblc_method_len > pubkeydata_len - 4) - /* the method length simply cannot be longer than the entire - passed in data, so we use this to detect crazy input - data */ + /* the method length cannot be longer than the entire passed + in data, so we use this to detect crazy input data */ return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid public key"); @@ -1135,15 +1493,27 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, memcpy(session->userauth_pblc_method, pubkeydata + 4, session->userauth_pblc_method_len); } - /* - * The length of the method name read from plaintext prefix in the - * file must match length embedded in the key. - * TODO: The data should match too but we don't check that. Should we? - */ - else if(session->userauth_pblc_method_len != - _libssh2_ntohu32(pubkeydata)) - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid public key"); + + /* upgrade key signing algo if it is supported and + * it is our first auth attempt, otherwise fallback to + * the key default algo */ + if(auth_attempts == 1) { + rc = _libssh2_key_sign_algorithm(session, + &session->userauth_pblc_method, + &session->userauth_pblc_method_len); + + if(rc) + return rc; + } + + if(session->userauth_pblc_method_len && + session->userauth_pblc_method) { + _libssh2_debug((session, + LIBSSH2_TRACE_KEX, + "Signing using %.*s", + session->userauth_pblc_method_len, + session->userauth_pblc_method)); + } /* * 45 = packet_type(1) + username_len(4) + servicename_len(4) + @@ -1189,8 +1559,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, session->userauth_pblc_method_len); _libssh2_store_str(&s, (const char *)pubkeydata, pubkeydata_len); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting publickey authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting publickey authentication")); session->userauth_pblc_state = libssh2_NB_state_created; } @@ -1237,8 +1607,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, } if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Pubkey authentication prematurely successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Pubkey authentication prematurely successful")); /* * God help any SSH server that allows an UNVERIFIED * public key to validate the user @@ -1301,6 +1671,17 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); } + else if(rc == LIBSSH2_ERROR_ALGO_UNSUPPORTED && auth_attempts == 1) { + /* try again with the default key algo */ + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + session->userauth_pblc_state = libssh2_NB_state_idle; + + rc = LIBSSH2_ERROR_NONE; + goto retry_auth; + } else if(rc) { LIBSSH2_FREE(session, session->userauth_pblc_method); session->userauth_pblc_method = NULL; @@ -1340,20 +1721,40 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, s = session->userauth_pblc_packet + session->userauth_pblc_packet_len; session->userauth_pblc_b = NULL; - _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); + session->userauth_pblc_method_len = + plain_method((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, + (uint32_t)(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, + (uint32_t)(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, - "Attempting publickey authentication -- phase 2"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting publickey authentication -- phase 2")); session->userauth_pblc_s = s; session->userauth_pblc_state = libssh2_NB_state_sent2; @@ -1399,8 +1800,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, } if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Publickey authentication successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Publickey authentication successful")); /* We are us and we've proved it. */ LIBSSH2_FREE(session, session->userauth_pblc_data); session->userauth_pblc_data = NULL; @@ -1418,10 +1819,10 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, "username/public key combination"); } - /* - * userauth_publickey_frommemory - * Authenticate using a keypair from memory - */ +/* + * userauth_publickey_frommemory + * Authenticate using a keypair from memory + */ static int userauth_publickey_frommemory(LIBSSH2_SESSION *session, const char *username, @@ -1438,11 +1839,6 @@ userauth_publickey_frommemory(LIBSSH2_SESSION *session, void *abstract = &privkey_file; int rc; -#if !LIBSSH2_RSA - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "RSA is not supported by crypto backend"); -#endif - privkey_file.filename = privatekeydata; privkey_file.passphrase = passphrase; @@ -1457,15 +1853,14 @@ userauth_publickey_frommemory(LIBSSH2_SESSION *session, } else if(privatekeydata_len && privatekeydata) { /* Compute public key from private key. */ - if(_libssh2_pub_priv_keyfilememory(session, + rc = _libssh2_pub_priv_keyfilememory(session, &session->userauth_pblc_method, &session->userauth_pblc_method_len, &pubkeydata, &pubkeydata_len, privatekeydata, privatekeydata_len, - passphrase)) - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key."); + passphrase); + if(rc) + return rc; } else { return _libssh2_error(session, LIBSSH2_ERROR_FILE, @@ -1500,11 +1895,6 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session, void *abstract = &privkey_file; int rc; -#if !LIBSSH2_RSA - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "RSA is not supported by crypto backend"); -#endif - privkey_file.filename = privatekey; privkey_file.passphrase = passphrase; @@ -1554,7 +1944,7 @@ libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, { int rc; - if(NULL == passphrase) + if(!passphrase) /* if given a NULL pointer, make it point to a zero-length string to save us from having to check this all over */ passphrase = ""; @@ -1582,7 +1972,7 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, { int rc; - if(NULL == passphrase) + if(!passphrase) /* if given a NULL pointer, make it point to a zero-length string to save us from having to check this all over */ passphrase = ""; @@ -1603,7 +1993,7 @@ libssh2_userauth_publickey(LIBSSH2_SESSION *session, const unsigned char *pubkeydata, size_t pubkeydata_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), + ((*sign_callback)), void **abstract) { int rc; @@ -1630,16 +2020,16 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, const char *username, unsigned int username_len, LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC - ((*response_callback))) + ((*response_callback))) { unsigned char *s; + int rc; static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 }; - unsigned int language_tag_len; unsigned int i; if(session->userauth_kybd_state == libssh2_NB_state_idle) { @@ -1690,8 +2080,8 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, /* submethods */ _libssh2_store_u32(&s, 0); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting keyboard-interactive authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting keyboard-interactive authentication")); session->userauth_kybd_state = libssh2_NB_state_created; } @@ -1739,9 +2129,9 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, } if(session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Keyboard-interactive " - "authentication successful"); + "authentication successful")); LIBSSH2_FREE(session, session->userauth_kybd_data); session->userauth_kybd_data = NULL; session->state |= LIBSSH2_STATE_AUTHENTICATED; @@ -1750,8 +2140,8 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, } if(session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Keyboard-interactive authentication failed"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Keyboard-interactive authentication failed")); LIBSSH2_FREE(session, session->userauth_kybd_data); session->userauth_kybd_data = NULL; session->userauth_kybd_state = libssh2_NB_state_idle; @@ -1762,230 +2152,34 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, } /* server requested PAM-like conversation */ - s = session->userauth_kybd_data + 1; - - if(session->userauth_kybd_data_len >= 5) { - /* string name (ISO-10646 UTF-8) */ - session->userauth_kybd_auth_name_len = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "to get length"); + if(userauth_keyboard_interactive_decode_info_request(session) + < 0) { goto cleanup; } - if(session->userauth_kybd_auth_name_len) { - session->userauth_kybd_auth_name = - LIBSSH2_ALLOC(session, - session->userauth_kybd_auth_name_len); - if(!session->userauth_kybd_auth_name) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive 'name' " - "request field"); - goto cleanup; - } - if(s + session->userauth_list_data_len <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_auth_name, s, - session->userauth_kybd_auth_name_len); - s += session->userauth_kybd_auth_name_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth name"); - goto cleanup; - } - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string instruction (ISO-10646 UTF-8) */ - session->userauth_kybd_auth_instruction_len = - _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth instruction length"); - goto cleanup; - } - - if(session->userauth_kybd_auth_instruction_len) { - session->userauth_kybd_auth_instruction = - LIBSSH2_ALLOC(session, - session->userauth_kybd_auth_instruction_len); - if(!session->userauth_kybd_auth_instruction) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive 'instruction' " - "request field"); - goto cleanup; - } - if(s + session->userauth_kybd_auth_instruction_len <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_auth_instruction, s, - session->userauth_kybd_auth_instruction_len); - s += session->userauth_kybd_auth_instruction_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth instruction"); - goto cleanup; - } - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string language tag (as defined in [RFC-3066]) */ - language_tag_len = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth language tag length"); - goto cleanup; - } - - if(s + language_tag_len <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* ignoring this field as deprecated */ - s += language_tag_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth language tag"); - goto cleanup; - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* int num-prompts */ - session->userauth_kybd_num_prompts = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth num keyboard prompts"); - goto cleanup; - } - - if(session->userauth_kybd_num_prompts > 100) { - _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, - "Too many replies for " - "keyboard-interactive prompts"); - goto cleanup; - } - - if(session->userauth_kybd_num_prompts) { - session->userauth_kybd_prompts = - LIBSSH2_CALLOC(session, - sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * - session->userauth_kybd_num_prompts); - if(!session->userauth_kybd_prompts) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive prompts array"); - goto cleanup; - } - - session->userauth_kybd_responses = - LIBSSH2_CALLOC(session, - sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * - session->userauth_kybd_num_prompts); - if(!session->userauth_kybd_responses) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive responses array"); - goto cleanup; - } - - for(i = 0; i < session->userauth_kybd_num_prompts; i++) { - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string prompt[1] (ISO-10646 UTF-8) */ - session->userauth_kybd_prompts[i].length = - _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard " - "prompt length"); - goto cleanup; - } - - session->userauth_kybd_prompts[i].text = - LIBSSH2_CALLOC(session, - session->userauth_kybd_prompts[i]. - length); - if(!session->userauth_kybd_prompts[i].text) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive prompt message"); - goto cleanup; - } - - if(s + session->userauth_kybd_prompts[i].length <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_prompts[i].text, s, - session->userauth_kybd_prompts[i].length); - s += session->userauth_kybd_prompts[i].length; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard prompt"); - goto cleanup; - } - if(s < session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* boolean echo[1] */ - session->userauth_kybd_prompts[i].echo = *s++; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard prompt echo"); - goto cleanup; - } - } - } - - response_callback(session->userauth_kybd_auth_name, - session->userauth_kybd_auth_name_len, + response_callback((const char *)session->userauth_kybd_auth_name, + (int)session->userauth_kybd_auth_name_len, + (const char *) session->userauth_kybd_auth_instruction, - session->userauth_kybd_auth_instruction_len, + (int)session->userauth_kybd_auth_instruction_len, session->userauth_kybd_num_prompts, session->userauth_kybd_prompts, session->userauth_kybd_responses, &session->abstract); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Keyboard-interactive response callback function" - " invoked"); + " invoked")); session->userauth_kybd_packet_len = - 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */ - + 4 /* int num-responses */ + 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */ + + 4 /* int num-responses */ ; for(i = 0; i < session->userauth_kybd_num_prompts; i++) { /* string response[1] (ISO-10646 UTF-8) */ if(session->userauth_kybd_responses[i].length <= - (SIZE_MAX - 4 - session->userauth_kybd_packet_len) ) { + (SIZE_MAX - 4 - session->userauth_kybd_packet_len)) { session->userauth_kybd_packet_len += 4 + session->userauth_kybd_responses[i].length; } @@ -2040,7 +2234,7 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, session->userauth_kybd_auth_failure = 0; } - cleanup: +cleanup: /* * It's safe to clean all the data here, because unallocated pointers * are filled by zeroes @@ -2100,7 +2294,7 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *user, unsigned int user_len, LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC - ((*response_callback))) + ((*response_callback))) { int rc; BLOCK_ADJUST(rc, session, @@ -2108,3 +2302,124 @@ 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 unsigned char *publickeydata, + size_t publickeydata_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase, + LIBSSH2_USERAUTH_SK_SIGN_FUNC + ((*sign_callback)), + void **abstract) +{ + int rc = LIBSSH2_ERROR_NONE; + + unsigned char *tmp_method = NULL; + size_t tmp_method_len = 0; + + unsigned char *tmp_publickeydata = NULL; + size_t tmp_publickeydata_len = 0; + + unsigned char *pubkeydata = NULL; + size_t pubkeydata_len = 0; + + LIBSSH2_PRIVKEY_SK sk_info = { 0 }; + void *sign_abstract = &sk_info; + + sk_info.sign_callback = sign_callback; + sk_info.orig_abstract = abstract; + + if(privatekeydata_len && privatekeydata) { + + if(_libssh2_sk_pub_keyfilememory(session, + &tmp_method, + &tmp_method_len, + &tmp_publickeydata, + &tmp_publickeydata_len, + &(sk_info.algorithm), + &(sk_info.flags), + &(sk_info.application), + &(sk_info.key_handle), + &(sk_info.handle_len), + privatekeydata, privatekeydata_len, + passphrase)) { + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public key " + "from private key."); + } + else if(publickeydata_len == 0 || !publickeydata) { + session->userauth_pblc_method = tmp_method; + session->userauth_pblc_method_len = tmp_method_len; + + pubkeydata_len = tmp_publickeydata_len; + pubkeydata = tmp_publickeydata; + } + else { + const char *ecdsa = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"; + const char *ed25519 = "sk-ssh-ed25519-cert-v01@openssh.com"; + + if(tmp_method) { + LIBSSH2_FREE(session, tmp_method); + } + + if(!strncmp((char *)publickeydata, ecdsa, strlen(ecdsa))) { + session->userauth_pblc_method_len = strlen(ecdsa); + session->userauth_pblc_method = + LIBSSH2_ALLOC(session, session->userauth_pblc_method_len); + + memcpy(session->userauth_pblc_method, ecdsa, + session->userauth_pblc_method_len); + } + else if(!strncmp((char *)publickeydata, ed25519, + strlen(ed25519))) { + session->userauth_pblc_method_len = strlen(ed25519); + session->userauth_pblc_method = + LIBSSH2_ALLOC(session, session->userauth_pblc_method_len); + + memcpy(session->userauth_pblc_method, ed25519, + session->userauth_pblc_method_len); + } + + rc = memory_read_publickey(session, + &session->userauth_pblc_method, + &session->userauth_pblc_method_len, + &pubkeydata, &pubkeydata_len, + (char *)publickeydata, + publickeydata_len); + } + } + else { + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Invalid data in public and private key."); + } + + if(rc == LIBSSH2_ERROR_NONE) { + 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(tmp_publickeydata) + LIBSSH2_FREE(session, tmp_publickeydata); + + if(sk_info.application) { + LIBSSH2_FREE(session, (void *)sk_info.application); + } + + return rc; +} |