예제 #1
0
파일: kex.c 프로젝트: OpenKod/src
static u_char *
derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen,
    const u_char *shared_secret, u_int slen)
{
	Buffer b;
	struct ssh_digest_ctx *hashctx;
	char c = id;
	u_int have;
	size_t mdsz;
	u_char *digest;

	if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0)
		fatal("bad kex md size %zu", mdsz);
	digest = xmalloc(roundup(need, mdsz));

	buffer_init(&b);
	buffer_append(&b, shared_secret, slen);

	/* K1 = HASH(K || H || "A" || session_id) */
	if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL)
		fatal("%s: ssh_digest_start failed", __func__);
	if (ssh_digest_update_buffer(hashctx, &b) != 0 ||
	    ssh_digest_update(hashctx, hash, hashlen) != 0 ||
	    ssh_digest_update(hashctx, &c, 1) != 0 ||
	    ssh_digest_update(hashctx, kex->session_id,
	    kex->session_id_len) != 0)
		fatal("%s: ssh_digest_update failed", __func__);
	if (ssh_digest_final(hashctx, digest, mdsz) != 0)
		fatal("%s: ssh_digest_final failed", __func__);
	ssh_digest_free(hashctx);

	/*
	 * expand key:
	 * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
	 * Key = K1 || K2 || ... || Kn
	 */
	for (have = mdsz; need > have; have += mdsz) {
		if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL)
			fatal("%s: ssh_digest_start failed", __func__);
		if (ssh_digest_update_buffer(hashctx, &b) != 0 ||
		    ssh_digest_update(hashctx, hash, hashlen) != 0 ||
		    ssh_digest_update(hashctx, digest, have) != 0)
			fatal("%s: ssh_digest_update failed", __func__);
		if (ssh_digest_final(hashctx, digest + have, mdsz) != 0)
			fatal("%s: ssh_digest_final failed", __func__);
		ssh_digest_free(hashctx);
	}
	buffer_free(&b);
#ifdef DEBUG_KEX
	fprintf(stderr, "key '%c'== ", c);
	dump_digest("key", digest, need);
#endif
	return digest;
}
예제 #2
0
파일: kex.c 프로젝트: djmdjm/libopenssh
int
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
    u_int8_t cookie[8], u_int8_t id[16])
{
	u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
	struct ssh_digest_ctx *hashctx = NULL;
	size_t len;
	int r;

	len = BN_num_bytes(host_modulus);
	if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
		return SSH_ERR_KEY_BITS_MISMATCH;
	if (BN_bn2bin(host_modulus, nbuf) <= 0 ||
	    (hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
	    ssh_digest_update(hashctx, nbuf, len) != 0 ||
	    ssh_digest_update(hashctx, cookie, 8) != 0 ||
	    ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) {
		r = SSH_ERR_LIBCRYPTO_ERROR;
		goto out;
	}
	memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));
	r = 0;
 out:
	ssh_digest_free(hashctx);
	explicit_bzero(nbuf, sizeof(nbuf));
	explicit_bzero(obuf, sizeof(obuf));
	return r;
}
예제 #3
0
파일: hmac.c 프로젝트: randombit/hacrypto
int
ssh_hmac_final(struct ssh_hmac_ctx *ctx, u_char *d, size_t dlen)
{
	size_t len;

	len = ssh_digest_bytes(ctx->alg);
	if (dlen < len ||
	    ssh_digest_final(ctx->digest, ctx->buf, len))
		return -1;
	/* switch to octx */
	if (ssh_digest_copy_state(ctx->octx, ctx->digest) < 0 ||
	    ssh_digest_update(ctx->digest, ctx->buf, len) < 0 ||
	    ssh_digest_final(ctx->digest, d, dlen) < 0)
		return -1;
	return 0;
}
예제 #4
0
파일: kex.c 프로젝트: OpenKod/src
void
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
    u_int8_t cookie[8], u_int8_t id[16])
{
	u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
	int len;
	struct ssh_digest_ctx *hashctx;

	if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL)
		fatal("%s: ssh_digest_start", __func__);

	len = BN_num_bytes(host_modulus);
	if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
		fatal("%s: bad host modulus (len %d)", __func__, len);
	BN_bn2bin(host_modulus, nbuf);
	if (ssh_digest_update(hashctx, nbuf, len) != 0)
		fatal("%s: ssh_digest_update failed", __func__);

	len = BN_num_bytes(server_modulus);
	if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
		fatal("%s: bad server modulus (len %d)", __func__, len);
	BN_bn2bin(server_modulus, nbuf);
	if (ssh_digest_update(hashctx, nbuf, len) != 0 ||
	    ssh_digest_update(hashctx, cookie, 8) != 0)
		fatal("%s: ssh_digest_update failed", __func__);
	if (ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0)
		fatal("%s: ssh_digest_final failed", __func__);
	memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));

	explicit_bzero(nbuf, sizeof(nbuf));
	explicit_bzero(obuf, sizeof(obuf));
}
예제 #5
0
int
ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
{
	struct ssh_digest_ctx *ctx = ssh_digest_start(alg);

	if (ctx == NULL)
		return SSH_ERR_INVALID_ARGUMENT;
	if (ssh_digest_update(ctx, m, mlen) != 0 ||
	    ssh_digest_final(ctx, d, dlen) != 0)
		return SSH_ERR_INVALID_ARGUMENT;
	ssh_digest_free(ctx);
	return 0;
}
예제 #6
0
/*
 * Computes the proper response to a RSA challenge, and sends the response to
 * the server.
 */
static void
respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
{
	u_char buf[32], response[16];
	struct ssh_digest_ctx *md;
	int i, len;

	/* Decrypt the challenge using the private key. */
	/* XXX think about Bleichenbacher, too */
	if (rsa_private_decrypt(challenge, challenge, prv) != 0)
		packet_disconnect(
		    "respond_to_rsa_challenge: rsa_private_decrypt failed");

	/* Compute the response. */
	/* The response is MD5 of decrypted challenge plus session id. */
	len = BN_num_bytes(challenge);
	if (len <= 0 || (u_int)len > sizeof(buf))
		packet_disconnect(
		    "respond_to_rsa_challenge: bad challenge length %d", len);

	memset(buf, 0, sizeof(buf));
	BN_bn2bin(challenge, buf + sizeof(buf) - len);
	if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
	    ssh_digest_update(md, buf, 32) < 0 ||
	    ssh_digest_update(md, session_id, 16) < 0 ||
	    ssh_digest_final(md, response, sizeof(response)) < 0)
		fatal("%s: md5 failed", __func__);
	ssh_digest_free(md);

	debug("Sending response to host key RSA challenge.");

	/* Send the response back to the server. */
	packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
	for (i = 0; i < 16; i++)
		packet_put_char(response[i]);
	packet_send();
	packet_write_wait();

	explicit_bzero(buf, sizeof(buf));
	explicit_bzero(response, sizeof(response));
	explicit_bzero(&md, sizeof(md));
}
예제 #7
0
파일: kex.c 프로젝트: djmdjm/libopenssh
static int
derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
    const u_char *shared_secret, u_int slen, u_char **keyp)
{
	struct kex *kex = ssh->kex;
	struct sshbuf *b = NULL;
	struct ssh_digest_ctx *hashctx = NULL;
	char c = id;
	u_int have;
	size_t mdsz;
	u_char *digest;
	int r;

	if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0)
		return SSH_ERR_INVALID_ARGUMENT;
	if ((digest = calloc(1, roundup(need, mdsz))) == NULL ||
	    (b = sshbuf_new()) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}
	if ((r = sshbuf_put(b, shared_secret, slen)) < 0)
		goto out;

	/* K1 = HASH(K || H || "A" || session_id) */
	if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
	    ssh_digest_update_buffer(hashctx, b) != 0 ||
	    ssh_digest_update(hashctx, hash, hashlen) != 0 ||
	    ssh_digest_update(hashctx, &c, 1) != 0 ||
	    ssh_digest_update(hashctx, kex->session_id,
	    kex->session_id_len) != 0 ||
	    ssh_digest_final(hashctx, digest, mdsz) != 0) {
		r = SSH_ERR_LIBCRYPTO_ERROR;
		goto out;
	}
	ssh_digest_free(hashctx);
	hashctx = NULL;

	/*
	 * expand key:
	 * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
	 * Key = K1 || K2 || ... || Kn
	 */
	for (have = mdsz; need > have; have += mdsz) {
		if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
		    ssh_digest_update_buffer(hashctx, b) != 0 ||
		    ssh_digest_update(hashctx, hash, hashlen) != 0 ||
		    ssh_digest_update(hashctx, digest, have) != 0 ||
		    ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
			r = SSH_ERR_LIBCRYPTO_ERROR;
			goto out;
		}
		ssh_digest_free(hashctx);
		hashctx = NULL;
	}
#ifdef DEBUG_KEX
	fprintf(stderr, "key '%c'== ", c);
	dump_digest("key", digest, need);
#endif
	*keyp = digest;
	digest = NULL;
	r = 0;
 out:
	if (digest)
		free(digest);
	if (b)
		sshbuf_free(b);
	ssh_digest_free(hashctx);
	return r;
}
예제 #8
0
// TODO: can we send multiple authrequests at the same time, so that we don’t
// need multiple round-trips but still support multiple security keys
static void
input_userauth_u2f_info_response(int type, u_int32_t seq, void *ctxt)
{
	int authenticated = 0;
    Authctxt *authctxt = ctxt;
	u_char digest[ssh_digest_bytes(SSH_DIGEST_SHA256)];
    debug("input_userauth_u2f_info_response\n");
    u_int len;
	char *clientdata;
	u_char *cdecoded;
	int cdecodedlen;
    char *resp = packet_get_string(&len);
    debug("u2f resp len (server): %d\n", len);
    debug("u2f resp (server): %s\n", resp);
    packet_check_eom();

	char *sig = extract_json_string(resp, "signatureData");
	if (sig == NULL)
		fatal("could not extract signature");
	// TODO: free sig

	debug("signature is *%s*", sig);
	if (*sig == '\0')
		fatal("u2f authentication failed: empty signature. Probably the key is not registered (i.e. your key handle/pubkey do not exist on the key you are using)");

	// TODO: is there a macro for this size?
	u_char decoded[strlen(sig) * 3 / 4];
	int decodedlen = urlsafe_base64_decode(sig, decoded, sizeof(decoded));
	// Ensure that the user presence byte, the counter and at least one byte of
	// signature are present.
	if (decodedlen <= (sizeof(u_char) + sizeof(u_int32_t)))
		fatal("decoded signature too short");
	if ((decoded[0] & 0x01) != 0x01)
		fatal("user presence bit not set");
	u_int32_t counter = ntohl(*((u_int32_t*)&decoded[1]));
	debug("usage counter = %d\n", counter);

	struct sha_digest_ctx *sha256ctx = ssh_digest_start(SSH_DIGEST_SHA256);
	u2f_sha256(digest, appid, strlen(appid));
	ssh_digest_update(sha256ctx, digest, sizeof(digest));
	ssh_digest_update(sha256ctx, decoded, sizeof(u_char));
	ssh_digest_update(sha256ctx, decoded+1, 4 * sizeof(u_char));

	if ((clientdata = extract_json_string(resp, "clientData")) == NULL) {
		fatal("U2F response JSON lacks the \"clientData\" key.");
	}

	cdecoded = xmalloc(strlen(clientdata) * 3 / 4);
	cdecodedlen = urlsafe_base64_decode(clientdata, cdecoded, strlen(clientdata) * 3 / 4);
	u2f_sha256(digest, cdecoded, cdecodedlen);
	ssh_digest_update(sha256ctx, digest, sizeof(digest));
	ssh_digest_final(sha256ctx, digest, sizeof(digest));
	debug("hashed sig");

	authenticated = PRIVSEP(verify_u2f_user(
		authctxt->u2f_key, digest, sizeof(digest), decoded+5, decodedlen-5));

	authctxt->postponed = 0;
	dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
	userauth_finish(authctxt, authenticated, "u2f", NULL);
}
예제 #9
0
void u2f_sha256(u_char *dest, u_char *src, size_t srclen) {
	struct ssh_digest_ctx *ctx = ssh_digest_start(SSH_DIGEST_SHA256);
	ssh_digest_update(ctx, src, srclen);
	ssh_digest_final(ctx, dest, ssh_digest_bytes(SSH_DIGEST_SHA256));
}