/* * hostkey_method_ssh_dss_signv * * Construct a signature from an array of vectors */ static int hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session, unsigned char **signature, size_t *signature_len, int veccount, const struct iovec datavec[], void **abstract) { libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); unsigned char hash[SHA_DIGEST_LENGTH]; libssh2_sha1_ctx ctx; int i; *signature = LIBSSH2_CALLOC(session, 2 * SHA_DIGEST_LENGTH); if (!*signature) { return -1; } *signature_len = 2 * SHA_DIGEST_LENGTH; libssh2_sha1_init(&ctx); for(i = 0; i < veccount; i++) { libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); } libssh2_sha1_final(ctx, hash); if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) { LIBSSH2_FREE(session, *signature); return -1; } return 0; }
int _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, const unsigned char *hash, unsigned long hash_len, unsigned char **signature, size_t *signature_len) { int r_len, s_len; int rc = 0; size_t out_buffer_len = 0; unsigned char *sp; const BIGNUM *pr = NULL, *ps = NULL; unsigned char *temp_buffer = NULL; unsigned char *out_buffer = NULL; ECDSA_SIG *sig = ECDSA_do_sign(hash, hash_len, ec_ctx); if(sig == NULL) return -1; #ifdef HAVE_OPAQUE_STRUCTS ECDSA_SIG_get0(sig, &pr, &ps); #else pr = sig->r; ps = sig->s; #endif r_len = BN_num_bytes(pr) + 1; s_len = BN_num_bytes(ps) + 1; temp_buffer = malloc(r_len + s_len + 8); if(temp_buffer == NULL) { rc = -1; goto clean_exit; } sp = temp_buffer; sp = write_bn(sp, pr, r_len); sp = write_bn(sp, ps, s_len); out_buffer_len = (size_t)(sp - temp_buffer); out_buffer = LIBSSH2_CALLOC(session, out_buffer_len); if(out_buffer == NULL) { rc = -1; goto clean_exit; } memcpy(out_buffer, temp_buffer, out_buffer_len); *signature = out_buffer; *signature_len = out_buffer_len; clean_exit: if(temp_buffer != NULL) free(temp_buffer); if(sig) ECDSA_SIG_free(sig); return rc; }
/* * hostkey_method_ssh_ed25519_init * * Initialize the server hostkey working area with e/n pair */ static int hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session, const unsigned char *hostkey_data, size_t hostkey_data_len, void **abstract) { const unsigned char *s; unsigned long len, key_len; EVP_PKEY *public_key = NULL; libssh2_ed25519_ctx *ctx = NULL; if(*abstract) { hostkey_method_ssh_ed25519_dtor(session, abstract); *abstract = NULL; } if(hostkey_data_len < 15) { return -1; } s = hostkey_data; len = _libssh2_ntohu32(s); s += 4; if(len != 11 || strncmp((char *) s, "ssh-ed25519", 11) != 0) { return -1; } s += 11; //public key key_len = _libssh2_ntohu32(s); s += 4; public_key = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, (const unsigned char*)s, key_len); if(public_key == NULL) { return _libssh2_error(session, LIBSSH2_ERROR_PROTO, "could not create ED25519 public key"); } ctx = LIBSSH2_CALLOC(session, sizeof(libssh2_ed25519_ctx)); if(ctx == NULL) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "could not alloc public/private key"); } ctx->public_key = public_key; *abstract = ctx; return 0; }
/* * libssh2_agent_init * * Init an ssh-agent handle. Returns the pointer to the handle. * */ LIBSSH2_API LIBSSH2_AGENT * libssh2_agent_init(LIBSSH2_SESSION *session) { LIBSSH2_AGENT *agent; agent = LIBSSH2_CALLOC(session, sizeof *agent); if (!agent) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for agent connection"); return NULL; } agent->fd = LIBSSH2_INVALID_SOCKET; agent->session = session; _libssh2_list_init(&agent->head); return agent; }
static int knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, const char *host, const char *salt, const char *key_type_name, size_t key_type_len, const char *key, size_t keylen, const char *comment, size_t commentlen, int typemask, struct libssh2_knownhost **store) { struct known_host *entry; size_t hostlen = strlen(host); int rc; char *ptr; unsigned int ptrlen; /* make sure we have a key type set */ if(!(typemask & LIBSSH2_KNOWNHOST_KEY_MASK)) return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, "No key type set"); if(!(entry = LIBSSH2_CALLOC(hosts->session, sizeof(struct known_host)))) return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for known host " "entry"); entry->typemask = typemask; switch(entry->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) { case LIBSSH2_KNOWNHOST_TYPE_PLAIN: case LIBSSH2_KNOWNHOST_TYPE_CUSTOM: entry->name = LIBSSH2_ALLOC(hosts->session, hostlen+1); if(!entry->name) { rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for host name"); goto error; } memcpy(entry->name, host, hostlen+1); entry->name_len = hostlen; break; case LIBSSH2_KNOWNHOST_TYPE_SHA1: rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, host, hostlen); if(rc) goto error; entry->name = ptr; entry->name_len = ptrlen; rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, salt, strlen(salt)); if(rc) goto error; entry->salt = ptr; entry->salt_len = ptrlen; break; default: rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, "Unknown host name type"); goto error; } if(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64) { /* the provided key is base64 encoded already */ if(!keylen) keylen = strlen(key); entry->key = LIBSSH2_ALLOC(hosts->session, keylen+1); if(!entry->key) { rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for key"); goto error; } memcpy(entry->key, key, keylen+1); entry->key[keylen]=0; /* force a terminating zero trailer */ } else { /* key is raw, we base64 encode it and store it as such */ size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen, &ptr); if(!nlen) { rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for " "base64-encoded key"); goto error; } entry->key = ptr; } if (key_type_name && ((typemask & LIBSSH2_KNOWNHOST_KEY_MASK) == LIBSSH2_KNOWNHOST_KEY_UNKNOWN)) { entry->key_type_name = LIBSSH2_ALLOC(hosts->session, key_type_len+1); if (!entry->key_type_name) { rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for key type"); goto error; } memcpy(entry->key_type_name, key_type_name, key_type_len); entry->key_type_name[key_type_len]=0; entry->key_type_len = key_type_len; } if (comment) { entry->comment = LIBSSH2_ALLOC(hosts->session, commentlen+1); if(!entry->comment) { rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for comment"); goto error; } memcpy(entry->comment, comment, commentlen+1); entry->comment[commentlen]=0; /* force a terminating zero trailer */ entry->comment_len = commentlen; } else { entry->comment = NULL; } /* add this new host to the big list of known hosts */ _libssh2_list_add(&hosts->head, &entry->node); if(store) *store = knownhost_to_external(entry); return LIBSSH2_ERROR_NONE; error: free_host(hosts->session, entry); return rc; }
/* * libssh2_packet_queue_listener * * Queue a connection request for a listener */ static inline int packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, unsigned long datalen, packet_queue_listener_state_t *listen_state) { /* * Look for a matching listener */ /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1); unsigned char *p; LIBSSH2_LISTENER *listn = _libssh2_list_first(&session->listeners); char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; int rc; (void) datalen; if (listen_state->state == libssh2_NB_state_idle) { unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5; listen_state->sender_channel = _libssh2_ntohu32(s); s += 4; listen_state->initial_window_size = _libssh2_ntohu32(s); s += 4; listen_state->packet_size = _libssh2_ntohu32(s); s += 4; listen_state->host_len = _libssh2_ntohu32(s); s += 4; listen_state->host = s; s += listen_state->host_len; listen_state->port = _libssh2_ntohu32(s); s += 4; listen_state->shost_len = _libssh2_ntohu32(s); s += 4; listen_state->shost = s; s += listen_state->shost_len; listen_state->sport = _libssh2_ntohu32(s); _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Remote received connection from %s:%ld to %s:%ld", listen_state->shost, listen_state->sport, listen_state->host, listen_state->port); listen_state->state = libssh2_NB_state_allocated; } if (listen_state->state != libssh2_NB_state_sent) { while (listn) { if ((listn->port == (int) listen_state->port) && (strlen(listn->host) == listen_state->host_len) && (memcmp (listn->host, listen_state->host, listen_state->host_len) == 0)) { /* This is our listener */ LIBSSH2_CHANNEL *channel = NULL; listen_state->channel = NULL; if (listen_state->state == libssh2_NB_state_allocated) { if (listn->queue_maxsize && (listn->queue_maxsize <= listn->queue_size)) { /* Queue is full */ failure_code = SSH_OPEN_RESOURCE_SHORTAGE; _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Listener queue full, ignoring"); listen_state->state = libssh2_NB_state_sent; break; } channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL)); if (!channel) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for " "new connection"); failure_code = SSH_OPEN_RESOURCE_SHORTAGE; listen_state->state = libssh2_NB_state_sent; break; } listen_state->channel = channel; channel->session = session; channel->channel_type_len = sizeof("forwarded-tcpip") - 1; channel->channel_type = LIBSSH2_ALLOC(session, channel-> channel_type_len + 1); if (!channel->channel_type) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new" " connection"); LIBSSH2_FREE(session, channel); failure_code = SSH_OPEN_RESOURCE_SHORTAGE; listen_state->state = libssh2_NB_state_sent; break; } memcpy(channel->channel_type, "forwarded-tcpip", channel->channel_type_len + 1); channel->remote.id = listen_state->sender_channel; channel->remote.window_size_initial = LIBSSH2_CHANNEL_WINDOW_DEFAULT; channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT; channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT; channel->local.id = _libssh2_channel_nextid(session); channel->local.window_size_initial = listen_state->initial_window_size; channel->local.window_size = listen_state->initial_window_size; channel->local.packet_size = listen_state->packet_size; _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Connection queued: channel %lu/%lu " "win %lu/%lu packet %lu/%lu", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, channel->local.packet_size, channel->remote.packet_size); p = listen_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; _libssh2_store_u32(&p, channel->remote.id); _libssh2_store_u32(&p, channel->local.id); _libssh2_store_u32(&p, channel->remote.window_size_initial); _libssh2_store_u32(&p, channel->remote.packet_size); listen_state->state = libssh2_NB_state_created; } if (listen_state->state == libssh2_NB_state_created) { rc = _libssh2_transport_send(session, listen_state->packet, 17, NULL, 0); if (rc == LIBSSH2_ERROR_EAGAIN) return rc; else if (rc) { listen_state->state = libssh2_NB_state_idle; return _libssh2_error(session, rc, "Unable to send channel " "open confirmation"); } /* Link the channel into the end of the queue list */ if (listen_state->channel) { _libssh2_list_add(&listn->queue, &listen_state->channel->node); listn->queue_size++; } listen_state->state = libssh2_NB_state_idle; return 0; } } listn = _libssh2_list_next(&listn->node); } listen_state->state = libssh2_NB_state_sent; } /* We're not listening to you */ p = listen_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; _libssh2_store_u32(&p, listen_state->sender_channel); _libssh2_store_u32(&p, failure_code); _libssh2_store_str(&p, FwdNotReq, sizeof(FwdNotReq) - 1); _libssh2_htonu32(p, 0); rc = _libssh2_transport_send(session, listen_state->packet, packet_len, NULL, 0); if (rc == LIBSSH2_ERROR_EAGAIN) { return rc; } else if (rc) { listen_state->state = libssh2_NB_state_idle; return _libssh2_error(session, rc, "Unable to send open failure"); } listen_state->state = libssh2_NB_state_idle; return 0; }
/* * packet_x11_open * * Accept a forwarded X11 connection */ static inline int packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, unsigned long datalen, packet_x11_open_state_t *x11open_state) { int failure_code = SSH_OPEN_CONNECT_FAILED; /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); unsigned char *p; LIBSSH2_CHANNEL *channel = x11open_state->channel; int rc; (void) datalen; if (x11open_state->state == libssh2_NB_state_idle) { unsigned char *s = data + (sizeof("x11") - 1) + 5; x11open_state->sender_channel = _libssh2_ntohu32(s); s += 4; x11open_state->initial_window_size = _libssh2_ntohu32(s); s += 4; x11open_state->packet_size = _libssh2_ntohu32(s); s += 4; x11open_state->shost_len = _libssh2_ntohu32(s); s += 4; x11open_state->shost = s; s += x11open_state->shost_len; x11open_state->sport = _libssh2_ntohu32(s); _libssh2_debug(session, LIBSSH2_TRACE_CONN, "X11 Connection Received from %s:%ld on channel %lu", x11open_state->shost, x11open_state->sport, x11open_state->sender_channel); x11open_state->state = libssh2_NB_state_allocated; } if (session->x11) { if (x11open_state->state == libssh2_NB_state_allocated) { channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL)); if (!channel) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "allocate a channel for new connection"); failure_code = SSH_OPEN_RESOURCE_SHORTAGE; goto x11_exit; } channel->session = session; channel->channel_type_len = sizeof("x11") - 1; channel->channel_type = LIBSSH2_ALLOC(session, channel->channel_type_len + 1); if (!channel->channel_type) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "allocate a channel for new connection"); LIBSSH2_FREE(session, channel); failure_code = SSH_OPEN_RESOURCE_SHORTAGE; goto x11_exit; } memcpy(channel->channel_type, "x11", channel->channel_type_len + 1); channel->remote.id = x11open_state->sender_channel; channel->remote.window_size_initial = LIBSSH2_CHANNEL_WINDOW_DEFAULT; channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT; channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT; channel->local.id = _libssh2_channel_nextid(session); channel->local.window_size_initial = x11open_state->initial_window_size; channel->local.window_size = x11open_state->initial_window_size; channel->local.packet_size = x11open_state->packet_size; _libssh2_debug(session, LIBSSH2_TRACE_CONN, "X11 Connection established: channel %lu/%lu " "win %lu/%lu packet %lu/%lu", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, channel->local.packet_size, channel->remote.packet_size); p = x11open_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; _libssh2_store_u32(&p, channel->remote.id); _libssh2_store_u32(&p, channel->local.id); _libssh2_store_u32(&p, channel->remote.window_size_initial); _libssh2_store_u32(&p, channel->remote.packet_size); x11open_state->state = libssh2_NB_state_created; } if (x11open_state->state == libssh2_NB_state_created) { rc = _libssh2_transport_send(session, x11open_state->packet, 17, NULL, 0); if (rc == LIBSSH2_ERROR_EAGAIN) { return rc; } else if (rc) { x11open_state->state = libssh2_NB_state_idle; return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open " "confirmation"); } /* Link the channel into the session */ _libssh2_list_add(&session->channels, &channel->node); /* * Pass control to the callback, they may turn right around and * free the channel, or actually use it */ LIBSSH2_X11_OPEN(channel, (char *)x11open_state->shost, x11open_state->sport); x11open_state->state = libssh2_NB_state_idle; return 0; } } else failure_code = SSH_OPEN_RESOURCE_SHORTAGE; /* fall-trough */ x11_exit: p = x11open_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; _libssh2_store_u32(&p, x11open_state->sender_channel); _libssh2_store_u32(&p, failure_code); _libssh2_store_str(&p, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1); _libssh2_htonu32(p, 0); rc = _libssh2_transport_send(session, x11open_state->packet, packet_len, NULL, 0); if (rc == LIBSSH2_ERROR_EAGAIN) { return rc; } else if (rc) { x11open_state->state = libssh2_NB_state_idle; return _libssh2_error(session, rc, "Unable to send open failure"); } x11open_state->state = libssh2_NB_state_idle; return 0; }