/* * hostkey_method_ssh_rsa_signv * * Construct a signature from an array of vectors */ static int hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session, unsigned char **signature, size_t *signature_len, int veccount, const struct iovec datavec[], void **abstract) { libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); int ret; int i; unsigned char hash[SHA_DIGEST_LENGTH]; libssh2_sha1_ctx ctx; 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); ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH, signature, signature_len); if (ret) { return -1; } return 0; }
/* * 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; }
/* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange * Diffie Hellman Key Exchange, Group Agnostic */ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session, _libssh2_bn *g, _libssh2_bn *p, int group_order, unsigned char packet_type_init, unsigned char packet_type_reply, unsigned char *midhash, unsigned long midhash_len) { unsigned char *e_packet = NULL, *s_packet = NULL, *tmp, h_sig_comp[SHA_DIGEST_LENGTH], c; unsigned long e_packet_len, s_packet_len, tmp_len; int ret = 0; _libssh2_bn_ctx *ctx = _libssh2_bn_ctx_new(); _libssh2_bn *x = _libssh2_bn_init(); /* Random from client */ _libssh2_bn *e = _libssh2_bn_init(); /* g^x mod p */ _libssh2_bn *f = _libssh2_bn_init(); /* g^(Random from server) mod p */ _libssh2_bn *k = _libssh2_bn_init(); /* The shared secret: f^x mod p */ unsigned char *s, *f_value, *k_value = NULL, *h_sig; unsigned long f_value_len, k_value_len, h_sig_len; libssh2_sha1_ctx exchange_hash; /* Generate x and e */ _libssh2_bn_rand(x, group_order, 0, -1); _libssh2_bn_mod_exp(e, g, x, p, ctx); /* Send KEX init */ e_packet_len = _libssh2_bn_bytes(e) + 6; /* packet_type(1) + String Length(4) + leading 0(1) */ if (_libssh2_bn_bits(e) % 8) { /* Leading 00 not needed */ e_packet_len--; } e_packet = LIBSSH2_ALLOC(session, e_packet_len); if (!e_packet) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Out of memory error", 0); ret = -1; goto clean_exit; } e_packet[0] = packet_type_init; libssh2_htonu32(e_packet + 1, e_packet_len - 5); if (_libssh2_bn_bits(e) % 8) { _libssh2_bn_to_bin(e, e_packet + 5); } else { e_packet[5] = 0; _libssh2_bn_to_bin(e, e_packet + 6); } #ifdef LIBSSH2_DEBUG_KEX _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d", (int)packet_type_init); #endif if (libssh2_packet_write(session, e_packet, e_packet_len)) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEX init message", 0); ret = -11; goto clean_exit; } if (session->burn_optimistic_kexinit) { /* The first KEX packet to come along will be the guess initially sent by the server * That guess turned out to be wrong so we need to silently ignore it */ int burn_type; #ifdef LIBSSH2_DEBUG_KEX _libssh2_debug(session, LIBSSH2_DBG_KEX, "Waiting for badly guessed KEX packet (to be ignored)"); #endif burn_type = libssh2_packet_burn(session); if (burn_type <= 0) { /* Failed to receive a packet */ ret = -1; goto clean_exit; } session->burn_optimistic_kexinit = 0; #ifdef LIBSSH2_DEBUG_KEX _libssh2_debug(session, LIBSSH2_DBG_KEX, "Burnt packet of type: %02x", (unsigned int)burn_type); #endif } /* Wait for KEX reply */ if (libssh2_packet_require(session, packet_type_reply, &s_packet, &s_packet_len)) { libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for KEX reply", 0); ret = -1; goto clean_exit; } /* Parse KEXDH_REPLY */ s = s_packet + 1; session->server_hostkey_len = libssh2_ntohu32(s); s += 4; session->server_hostkey = LIBSSH2_ALLOC(session, session->server_hostkey_len); if (!session->server_hostkey) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for a copy of the host key", 0); ret = -1; goto clean_exit; } memcpy(session->server_hostkey, s, session->server_hostkey_len); s += session->server_hostkey_len; #if LIBSSH2_MD5 { libssh2_md5_ctx fingerprint_ctx; libssh2_md5_init(&fingerprint_ctx); libssh2_md5_update(fingerprint_ctx, session->server_hostkey, session->server_hostkey_len); libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5); } #ifdef LIBSSH2_DEBUG_KEX { char fingerprint[50], *fprint = fingerprint; int i; for(i = 0; i < 16; i++, fprint += 3) { snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); } *(--fprint) = '\0'; _libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's MD5 Fingerprint: %s", fingerprint); } #endif /* LIBSSH2_DEBUG_KEX */ #endif /* ! LIBSSH2_MD5 */ { libssh2_sha1_ctx fingerprint_ctx; libssh2_sha1_init(&fingerprint_ctx); libssh2_sha1_update (fingerprint_ctx, session->server_hostkey, session->server_hostkey_len); libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1); } #ifdef LIBSSH2_DEBUG_KEX { char fingerprint[64], *fprint = fingerprint; int i; for(i = 0; i < 20; i++, fprint += 3) { snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); } *(--fprint) = '\0'; _libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's SHA1 Fingerprint: %s", fingerprint); } #endif /* LIBSSH2_DEBUG_KEX */ if (session->hostkey->init(session, session->server_hostkey, session->server_hostkey_len, &session->server_hostkey_abstract)) { libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, "Unable to initialize hostkey importer", 0); ret = -1; goto clean_exit; } f_value_len = libssh2_ntohu32(s); s += 4; f_value = s; s += f_value_len; _libssh2_bn_from_bin(f, f_value_len, f_value); h_sig_len = libssh2_ntohu32(s); s += 4; h_sig = s; /* Compute the shared secret */ _libssh2_bn_mod_exp(k, f, x, p, ctx); k_value_len = _libssh2_bn_bytes(k) + 5; if (_libssh2_bn_bits(k) % 8) { /* don't need leading 00 */ k_value_len--; } k_value = LIBSSH2_ALLOC(session, k_value_len); if (!k_value) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate buffer for K", 0); ret = -1; goto clean_exit; } libssh2_htonu32(k_value, k_value_len - 4); if (_libssh2_bn_bits(k) % 8) { _libssh2_bn_to_bin(k, k_value + 4); } else { k_value[4] = 0; _libssh2_bn_to_bin(k, k_value + 5); } libssh2_sha1_init(&exchange_hash); if (session->local.banner) { libssh2_htonu32(h_sig_comp, strlen((char *)session->local.banner) - 2); libssh2_sha1_update(exchange_hash, h_sig_comp, 4); libssh2_sha1_update(exchange_hash, (char *)session->local.banner, strlen((char *)session->local.banner) - 2); } else { libssh2_htonu32(h_sig_comp, sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); libssh2_sha1_update(exchange_hash, h_sig_comp, 4); libssh2_sha1_update(exchange_hash, LIBSSH2_SSH_DEFAULT_BANNER, sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); } libssh2_htonu32(h_sig_comp, strlen((char *)session->remote.banner)); libssh2_sha1_update(exchange_hash, h_sig_comp, 4); libssh2_sha1_update(exchange_hash, session->remote.banner, strlen((char *)session->remote.banner)); libssh2_htonu32(h_sig_comp, session->local.kexinit_len); libssh2_sha1_update(exchange_hash, h_sig_comp, 4); libssh2_sha1_update(exchange_hash, session->local.kexinit, session->local.kexinit_len); libssh2_htonu32(h_sig_comp, session->remote.kexinit_len); libssh2_sha1_update(exchange_hash, h_sig_comp, 4); libssh2_sha1_update(exchange_hash, session->remote.kexinit, session->remote.kexinit_len); libssh2_htonu32(h_sig_comp, session->server_hostkey_len); libssh2_sha1_update(exchange_hash, h_sig_comp, 4); libssh2_sha1_update(exchange_hash, session->server_hostkey, session->server_hostkey_len); if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) { /* diffie-hellman-group-exchange hashes additional fields */ #ifdef LIBSSH2_DH_GEX_NEW libssh2_htonu32(h_sig_comp, LIBSSH2_DH_GEX_MINGROUP); libssh2_htonu32(h_sig_comp + 4, LIBSSH2_DH_GEX_OPTGROUP); libssh2_htonu32(h_sig_comp + 8, LIBSSH2_DH_GEX_MAXGROUP); libssh2_sha1_update(exchange_hash, h_sig_comp, 12); #else libssh2_htonu32(h_sig_comp, LIBSSH2_DH_GEX_OPTGROUP); libssh2_sha1_update(exchange_hash, h_sig_comp, 4); #endif } if (midhash) { libssh2_sha1_update(exchange_hash, midhash, midhash_len); } libssh2_sha1_update(exchange_hash, e_packet + 1, e_packet_len - 1); libssh2_htonu32(h_sig_comp, f_value_len); libssh2_sha1_update(exchange_hash, h_sig_comp, 4); libssh2_sha1_update(exchange_hash, f_value, f_value_len); libssh2_sha1_update(exchange_hash, k_value, k_value_len); libssh2_sha1_final(exchange_hash, h_sig_comp); if (session->hostkey->sig_verify(session, h_sig, h_sig_len, h_sig_comp, 20, &session->server_hostkey_abstract)) { libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, "Unable to verify hostkey signature", 0); ret = -1; goto clean_exit; } #ifdef LIBSSH2_DEBUG_KEX _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message"); #endif c = SSH_MSG_NEWKEYS; if (libssh2_packet_write(session, &c, 1)) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send NEWKEYS message", 0); ret = -1; goto clean_exit; } if (libssh2_packet_require(session, SSH_MSG_NEWKEYS, &tmp, &tmp_len)) { libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for NEWKEYS", 0); ret = -1; goto clean_exit; } /* The first key exchange has been performed, switch to active crypt/comp/mac mode */ session->state |= LIBSSH2_STATE_NEWKEYS; #ifdef LIBSSH2_DEBUG_KEX _libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message"); #endif /* This will actually end up being just packet_type(1) for this packet type anyway */ LIBSSH2_FREE(session, tmp); if (!session->session_id) { session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH); if (!session->session_id) { ret = -1; goto clean_exit; } memcpy(session->session_id, h_sig_comp, SHA_DIGEST_LENGTH); session->session_id_len = SHA_DIGEST_LENGTH; #ifdef LIBSSH2_DEBUG_KEX _libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated"); #endif } /* Cleanup any existing cipher */ if (session->local.crypt->dtor) { session->local.crypt->dtor(session, &session->local.crypt_abstract); } /* Calculate IV/Secret/Key for each direction */ if (session->local.crypt->init) { unsigned char *iv = NULL, *secret = NULL; int free_iv = 0, free_secret = 0; LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->local.crypt->iv_len, "A"); LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->local.crypt->secret_len, "C"); if (session->local.crypt->init(session, session->local.crypt, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract)) { LIBSSH2_FREE(session, iv); LIBSSH2_FREE(session, secret); ret = -1; goto clean_exit; } if (free_iv) { memset(iv, 0, session->local.crypt->iv_len); LIBSSH2_FREE(session, iv); } if (free_secret) { memset(secret, 0, session->local.crypt->secret_len); LIBSSH2_FREE(session, secret); } } #ifdef LIBSSH2_DEBUG_KEX _libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server IV and Key calculated"); #endif if (session->remote.crypt->dtor) { /* Cleanup any existing cipher */ session->remote.crypt->dtor(session, &session->remote.crypt_abstract); } if (session->remote.crypt->init) { unsigned char *iv = NULL, *secret = NULL; int free_iv = 0, free_secret = 0; LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->remote.crypt->iv_len, "B"); LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->remote.crypt->secret_len, "D"); if (session->remote.crypt->init(session, session->remote.crypt, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract)) { LIBSSH2_FREE(session, iv); LIBSSH2_FREE(session, secret); ret = -1; goto clean_exit; } if (free_iv) { memset(iv, 0, session->remote.crypt->iv_len); LIBSSH2_FREE(session, iv); } if (free_secret) { memset(secret, 0, session->remote.crypt->secret_len); LIBSSH2_FREE(session, secret); } } #ifdef LIBSSH2_DEBUG_KEX _libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client IV and Key calculated"); #endif if (session->local.mac->dtor) { session->local.mac->dtor(session, &session->local.mac_abstract); } if (session->local.mac->init) { unsigned char *key = NULL; int free_key = 0; LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->local.mac->key_len, "E"); session->local.mac->init(session, key, &free_key, &session->local.mac_abstract); if (free_key) { memset(key, 0, session->local.mac->key_len); LIBSSH2_FREE(session, key); } } #ifdef LIBSSH2_DEBUG_KEX _libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server HMAC Key calculated"); #endif if (session->remote.mac->dtor) { session->remote.mac->dtor(session, &session->remote.mac_abstract); } if (session->remote.mac->init) { unsigned char *key = NULL; int free_key = 0; LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->remote.mac->key_len, "F"); session->remote.mac->init(session, key, &free_key, &session->remote.mac_abstract); if (free_key) { memset(key, 0, session->remote.mac->key_len); LIBSSH2_FREE(session, key); } } #ifdef LIBSSH2_DEBUG_KEX _libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client HMAC Key calculated"); #endif clean_exit: _libssh2_bn_free(x); _libssh2_bn_free(e); _libssh2_bn_free(f); _libssh2_bn_free(k); _libssh2_bn_ctx_free(ctx); if (e_packet) { LIBSSH2_FREE(session, e_packet); } if (s_packet) { LIBSSH2_FREE(session, s_packet); } if (k_value) { LIBSSH2_FREE(session, k_value); } if (session->server_hostkey) { LIBSSH2_FREE(session, session->server_hostkey); session->server_hostkey = NULL; } return ret; }