static int agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) { HWND hwnd; char mapname[23]; HANDLE filemap; unsigned char *p; unsigned char *p2; int id; COPYDATASTRUCT cds; if (!transctx || 4 + transctx->request_len > PAGEANT_MAX_MSGLEN) return _libssh2_error(agent->session, LIBSSH2_ERROR_INVAL, "illegal input"); hwnd = FindWindow("Pageant", "Pageant"); if (!hwnd) return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "found no pageant"); sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId()); filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, PAGEANT_MAX_MSGLEN, mapname); if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "failed setting up pageant filemap"); p2 = p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); _libssh2_store_str(&p2, (const char *)transctx->request, transctx->request_len); cds.dwData = PAGEANT_COPYDATA_ID; cds.cbData = 1 + strlen(mapname); cds.lpData = mapname; id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds); if (id > 0) { transctx->response_len = _libssh2_ntohu32(p); if (transctx->response_len > PAGEANT_MAX_MSGLEN) { UnmapViewOfFile(p); CloseHandle(filemap); return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "agent setup fail"); } transctx->response = LIBSSH2_ALLOC(agent->session, transctx->response_len); if (!transctx->response) { UnmapViewOfFile(p); CloseHandle(filemap); return _libssh2_error(agent->session, LIBSSH2_ERROR_ALLOC, "agent malloc"); } memcpy(transctx->response, p + 4, transctx->response_len); } UnmapViewOfFile(p); CloseHandle(filemap); return 0; }
/* * 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; }
static int agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, const unsigned char *data, size_t data_len, void **abstract) { LIBSSH2_AGENT *agent = (LIBSSH2_AGENT *) (*abstract); agent_transaction_ctx_t transctx = &agent->transctx; struct agent_publickey *identity = agent->identity; ssize_t len = 1 + 4 + identity->external.blob_len + 4 + data_len + 4; ssize_t method_len; unsigned char *s; int rc; /* Create a request to sign the data */ if (transctx->state == agent_NB_state_init) { s = transctx->request = LIBSSH2_ALLOC(session, len); if (!transctx->request) return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "out of memory"); *s++ = SSH2_AGENTC_SIGN_REQUEST; /* key blob */ _libssh2_store_str(&s, (const char *)identity->external.blob, identity->external.blob_len); /* data */ _libssh2_store_str(&s, (const char *)data, data_len); /* flags */ _libssh2_store_u32(&s, 0); transctx->request_len = s - transctx->request; transctx->state = agent_NB_state_request_created; } /* Make sure to be re-called as a result of EAGAIN. */ if (*transctx->request != SSH2_AGENTC_SIGN_REQUEST) return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, "illegal request"); if (!agent->ops) /* if no agent has been connected, bail out */ return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, "agent not connected"); rc = agent->ops->transact(agent, transctx); if (rc) { goto error; } LIBSSH2_FREE(session, transctx->request); transctx->request = NULL; len = transctx->response_len; s = transctx->response; len--; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } if (*s != SSH2_AGENT_SIGN_RESPONSE) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } s++; /* Skip the entire length of the signature */ len -= 4; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } s += 4; /* Skip signing method */ len -= 4; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } method_len = _libssh2_ntohu32(s); s += 4; len -= method_len; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } s += method_len; /* Read the signature */ len -= 4; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } *sig_len = _libssh2_ntohu32(s); s += 4; len -= *sig_len; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } *sig = LIBSSH2_ALLOC(session, *sig_len); if (!*sig) { rc = LIBSSH2_ERROR_ALLOC; goto error; } memcpy(*sig, s, *sig_len); error: LIBSSH2_FREE(session, transctx->request); transctx->request = NULL; LIBSSH2_FREE(session, transctx->response); transctx->response = NULL; return _libssh2_error(session, rc, "agent sign failure"); }
static int gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, unsigned char **method, size_t *method_len, unsigned char **pubkeydata, size_t *pubkeydata_len, EVP_PKEY *pk) { int rc = 0; EC_KEY *ec = NULL; unsigned char *p; unsigned char *method_buf = NULL; unsigned char *key; size_t key_len = 0; unsigned char *octal_value = NULL; size_t octal_len; const EC_POINT *public_key; const EC_GROUP *group; BN_CTX *bn_ctx; libssh2_curve_type type; _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Computing public key from EC private key envelop"); bn_ctx = BN_CTX_new(); if(bn_ctx == NULL) return -1; ec = EVP_PKEY_get1_EC_KEY(pk); if(ec == NULL) { rc = -1; goto clean_exit; } public_key = EC_KEY_get0_public_key(ec); group = EC_KEY_get0_group(ec); type = _libssh2_ecdsa_key_get_curve_type(ec); method_buf = LIBSSH2_ALLOC(session, 19); 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); else if(type == LIBSSH2_EC_CURVE_NISTP384) memcpy(method_buf, "ecdsa-sha2-nistp384", 19); else if(type == LIBSSH2_EC_CURVE_NISTP521) memcpy(method_buf, "ecdsa-sha2-nistp521", 19); else { _libssh2_debug(session, LIBSSH2_TRACE_ERROR, "Unsupported EC private key type"); rc = -1; goto clean_exit; } /* get length */ octal_len = EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx); if(octal_len > EC_MAX_POINT_LEN) { rc = -1; goto clean_exit; } octal_value = malloc(octal_len); if(octal_value == NULL) { rc = -1; goto clean_exit; } /* convert to octal */ if(EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, octal_value, octal_len, bn_ctx) != octal_len) { rc = -1; 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 = LIBSSH2_ALLOC(session, key_len); if(key == NULL) { rc = -1; goto clean_exit; } /* Process key encoding. */ p = key; /* Key type */ _libssh2_store_str(&p, (const char *)method_buf, 19); /* Name domain */ _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; clean_exit: if(ec != NULL) EC_KEY_free(ec); if(bn_ctx != NULL) { BN_CTX_free(bn_ctx); } if(octal_value != NULL) free(octal_value); if(rc == 0) return 0; if(method_buf != NULL) LIBSSH2_FREE(session, method_buf); return -1; }