Ejemplo n.º 1
0
/*
 * 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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
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;
}