Beispiel #1
0
static int
openssh_RSA_verify(int type, u_char *hash, u_int hashlen,
    u_char *sigbuf, u_int siglen, RSA *rsa)
{
	u_int ret, rsasize, oidlen = 0, hlen = 0;
	int len, oidmatch, hashmatch;
	const u_char *oid = NULL;
	u_char *decrypted = NULL;

	ret = 0;
	switch (type) {
	case NID_sha1:
		oid = id_sha1;
		oidlen = sizeof(id_sha1);
		hlen = 20;
		break;
	case NID_md5:
		oid = id_md5;
		oidlen = sizeof(id_md5);
		hlen = 16;
		break;
	default:
		goto done;
	}
	if (hashlen != hlen) {
		error("bad hashlen");
		goto done;
	}
	rsasize = RSA_size(rsa);
	if (siglen == 0 || siglen > rsasize) {
		error("bad siglen");
		goto done;
	}
	decrypted = xmalloc(rsasize);
	if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
	    RSA_PKCS1_PADDING)) < 0) {
		error("RSA_public_decrypt failed: %s",
		    ERR_error_string(ERR_get_error(), NULL));
		goto done;
	}
	if (len < 0 || (u_int)len != hlen + oidlen) {
		error("bad decrypted len: %d != %d + %d", len, hlen, oidlen);
		goto done;
	}
	oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
	hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
	if (!oidmatch) {
		error("oid mismatch");
		goto done;
	}
	if (!hashmatch) {
		error("hash mismatch");
		goto done;
	}
	ret = 1;
done:
	if (decrypted)
		xfree(decrypted);
	return ret;
}
Beispiel #2
0
static int
monitor_valid_userblob(u_char *data, u_int datalen)
{
	Buffer b;
	u_char *p;
	char *userstyle, *cp;
	u_int len;
	int fail = 0;

	buffer_init(&b);
	buffer_append(&b, data, datalen);

	if (datafellows & SSH_OLD_SESSIONID) {
		p = buffer_ptr(&b);
		len = buffer_len(&b);
		if ((session_id2 == NULL) ||
		    (len < session_id2_len) ||
		    (timingsafe_bcmp(p, session_id2, session_id2_len) != 0))
			fail++;
		buffer_consume(&b, session_id2_len);
	} else {
		p = buffer_get_string(&b, &len);
		if ((session_id2 == NULL) ||
		    (len != session_id2_len) ||
		    (timingsafe_bcmp(p, session_id2, session_id2_len) != 0))
			fail++;
		free(p);
	}
	if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
		fail++;
	cp = buffer_get_cstring(&b, NULL);
	xasprintf(&userstyle, "%s%s%s", authctxt->user,
	    authctxt->style ? ":" : "",
	    authctxt->style ? authctxt->style : "");
	if (strcmp(userstyle, cp) != 0) {
		logit("wrong user name passed to monitor: "
		    "expected %s != %.100s", userstyle, cp);
		fail++;
	}
	free(userstyle);
	free(cp);
	buffer_skip_string(&b);
	if (datafellows & SSH_BUG_PKAUTH) {
		if (!buffer_get_char(&b))
			fail++;
	} else {
		cp = buffer_get_cstring(&b, NULL);
		if (strcmp("publickey", cp) != 0)
			fail++;
		free(cp);
		if (!buffer_get_char(&b))
			fail++;
		buffer_skip_string(&b);
	}
	buffer_skip_string(&b);
	if (buffer_len(&b) != 0)
		fail++;
	buffer_free(&b);
	return (fail == 0);
}
Beispiel #3
0
static int
openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
    u_char *sigbuf, size_t siglen, RSA *rsa)
{
	size_t ret, rsasize = 0, oidlen = 0, hlen = 0;
	int len, oidmatch, hashmatch;
	const u_char *oid = NULL;
	u_char *decrypted = NULL;

	ret = SSH_ERR_INTERNAL_ERROR;
	switch (hash_alg) {
	case SSH_DIGEST_SHA1:
		oid = id_sha1;
		oidlen = sizeof(id_sha1);
		hlen = 20;
		break;
	default:
		goto done;
	}
	if (hashlen != hlen) {
		ret = SSH_ERR_INVALID_ARGUMENT;
		goto done;
	}
	rsasize = RSA_size(rsa);
	if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
	    siglen == 0 || siglen > rsasize) {
		ret = SSH_ERR_INVALID_ARGUMENT;
		goto done;
	}
	if ((decrypted = malloc(rsasize)) == NULL) {
		ret = SSH_ERR_ALLOC_FAIL;
		goto done;
	}
	if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
	    RSA_PKCS1_PADDING)) < 0) {
		ret = SSH_ERR_LIBCRYPTO_ERROR;
		goto done;
	}
	if (len < 0 || (size_t)len != hlen + oidlen) {
		ret = SSH_ERR_INVALID_FORMAT;
		goto done;
	}
	oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
	hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
	if (!oidmatch || !hashmatch) {
		ret = SSH_ERR_SIGNATURE_INVALID;
		goto done;
	}
	ret = 0;
done:
	if (decrypted) {
		explicit_bzero(decrypted, rsasize);
		free(decrypted);
	}
	return ret;
}
Beispiel #4
0
static int
openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
    u_char *sigbuf, size_t siglen, RSA *rsa)
{
	size_t rsasize = 0, oidlen = 0, hlen = 0;
	int ret, len, oidmatch, hashmatch;
	const u_char *oid = NULL;
	u_char *decrypted = NULL;

	if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0)
		return ret;
	ret = SSH_ERR_INTERNAL_ERROR;
	hlen = ssh_digest_bytes(hash_alg);
	if (hashlen != hlen) {
		ret = SSH_ERR_INVALID_ARGUMENT;
		goto done;
	}
	rsasize = RSA_size(rsa);
	if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
	    siglen == 0 || siglen > rsasize) {
		ret = SSH_ERR_INVALID_ARGUMENT;
		goto done;
	}
	if ((decrypted = malloc(rsasize)) == NULL) {
		ret = SSH_ERR_ALLOC_FAIL;
		goto done;
	}
	if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
	    RSA_PKCS1_PADDING)) < 0) {
		ret = SSH_ERR_LIBCRYPTO_ERROR;
		goto done;
	}
	if (len < 0 || (size_t)len != hlen + oidlen) {
		ret = SSH_ERR_INVALID_FORMAT;
		goto done;
	}
	oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
	hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
	if (!oidmatch || !hashmatch) {
		ret = SSH_ERR_SIGNATURE_INVALID;
		goto done;
	}
	ret = 0;
done:
	if (decrypted) {
		explicit_bzero(decrypted, rsasize);
		free(decrypted);
	}
	return ret;
}
Beispiel #5
0
int
crypt_checkpass(const char *pass, const char *goodhash)
{
	char dummy[_PASSWORD_LEN];
	char *res;

	if (goodhash == NULL) {
		/* fake it */
		bcrypt_newhash(pass, 8, dummy, sizeof(dummy));
		goto fail;
	}

	/* empty password */
	if (strlen(goodhash) == 0 && strlen(pass) == 0)
		return 0;

	if (goodhash[0] == '$' && goodhash[1] == '2') {
		return bcrypt_checkpass(pass, goodhash);
	}

	/* have to do it the hard way */
	res = crypt(pass, goodhash);
	if (strlen(res) != strlen(goodhash) ||
	    timingsafe_bcmp(res, goodhash, strlen(goodhash)) != 0) {
		goto fail;
	}

	return 0;
fail:
	errno = EACCES;
	return -1;
}
Beispiel #6
0
int
aes_key_unwrap(aes_key_wrap_ctx *ctx, const u_int8_t *C, u_int8_t *P, size_t n)
{
	u_int64_t B[2], t;
	u_int8_t A[8], *R;
	size_t i;
	int j;

	memcpy(A, C, 8);		/* A = C[0] */
	memmove(P, C + 8, n * 8);	/* P and C may overlap */

	for (j = 5, t = 6 * n; j >= 0; j--) {
		R = P + (n - 1) * 8;
		for (i = n; i >= 1; i--, t--) {
			/* MSB(64, B) = A */
			memcpy(&B[0], A, 8);
			/* MSB(64, B) = MSB(64, B) ^ t */
			B[0] ^= htobe64(t);
			/* B = MSB(64, B) | R[i] */
			memcpy(&B[1], R, 8);
			/* B = AES-1(K, B) */
			rijndael_decrypt(&ctx->ctx, (caddr_t)B, (caddr_t)B);
			/* A = MSB(64, B) */
			memcpy(A, &B[0], 8);
			/* R[i] = LSB(64, B) */
			memcpy(R, &B[1], 8);

			R -= 8;
		}
	}
	explicit_bzero(B, sizeof B);

	/* check that A is an appropriate initial value */
	return timingsafe_bcmp(A, IV, 8) != 0;
}
Beispiel #7
0
/*
 * Calculate and check confirmation hash from peer. Returns 1 on success
 * 0 on failure/mismatch.
 */
int
jpake_check_confirm(const BIGNUM *k,
    const u_char *peer_id, u_int peer_id_len,
    const u_char *sess_id, u_int sess_id_len,
    const u_char *peer_confirm_hash, u_int peer_confirm_hash_len)
{
	u_char *expected_confirm_hash;
	u_int expected_confirm_hash_len;
	int success = 0;

	/* Calculate and verify expected confirmation hash */
	jpake_confirm_hash(k, peer_id, peer_id_len, sess_id, sess_id_len,
	    &expected_confirm_hash, &expected_confirm_hash_len);

	JPAKE_DEBUG_BUF((expected_confirm_hash, expected_confirm_hash_len,
	    "%s: expected confirm hash", __func__));
	JPAKE_DEBUG_BUF((peer_confirm_hash, peer_confirm_hash_len,
	    "%s: received confirm hash", __func__));

	if (peer_confirm_hash_len != expected_confirm_hash_len)
		error("%s: confirmation length mismatch (my %u them %u)",
		    __func__, expected_confirm_hash_len, peer_confirm_hash_len);
	else if (timingsafe_bcmp(peer_confirm_hash, expected_confirm_hash,
	    expected_confirm_hash_len) == 0)
		success = 1;
	bzero(expected_confirm_hash, expected_confirm_hash_len);
	xfree(expected_confirm_hash);
	debug3("%s: success = %d", __func__, success);
	return success;
}
Beispiel #8
0
int
kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
    const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int raw)
{
	u_char shared_key[CURVE25519_SIZE];
	u_char zero[CURVE25519_SIZE];
	int r;

	crypto_scalarmult_curve25519(shared_key, key, pub);

	/* Check for all-zero shared secret */
	explicit_bzero(zero, CURVE25519_SIZE);
	if (timingsafe_bcmp(zero, shared_key, CURVE25519_SIZE) == 0)
		return SSH_ERR_KEY_INVALID_EC_VALUE;

#ifdef DEBUG_KEXECDH
	dump_digest("shared secret", shared_key, CURVE25519_SIZE);
#endif
	if (raw)
		r = sshbuf_put(out, shared_key, CURVE25519_SIZE);
	else
		r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
	explicit_bzero(shared_key, CURVE25519_SIZE);
	return r;
}
Beispiel #9
0
int
auth_rsa_verify_response(struct sshkey *key, BIGNUM *challenge,
    u_char response[16])
{
	u_char buf[32], mdbuf[16];
	MD5_CTX md;
	int len;

	/* don't allow short keys */
	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
		error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits",
		    BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
		return (0);
	}

	/* The response is MD5 of decrypted challenge plus session id. */
	len = BN_num_bytes(challenge);
	if (len <= 0 || len > 32)
		fatal("auth_rsa_verify_response: bad challenge length %d", len);
	memset(buf, 0, 32);
	BN_bn2bin(challenge, buf + 32 - len);
	MD5_Init(&md);
	MD5_Update(&md, buf, 32);
	MD5_Update(&md, session_id, 16);
	MD5_Final(mdbuf, &md);

	/* Verify that the response is the original challenge. */
	if (timingsafe_bcmp(response, mdbuf, 16) != 0) {
		/* Wrong answer. */
		return (0);
	}
	/* Correct answer. */
	return (1);
}
int
kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
    const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
{
	u_char shared_key[CURVE25519_SIZE];
	int r;

#ifdef USING_WOLFSSL
    int ret, ssize = CURVE25519_SIZE;
    ret = wolfSSL_EC25519_shared_key(shared_key, &ssize,
                                     key, CURVE25519_SIZE,
                                     pub, CURVE25519_SIZE);
    if (ret != 1 || ssize != CURVE25519_SIZE)
        fatal("%s: wolfSSL_EC25519_shared_key failed", __func__);
#else
	/* Check for all-zero public key */
	explicit_bzero(shared_key, CURVE25519_SIZE);
	if (timingsafe_bcmp(pub, shared_key, CURVE25519_SIZE) == 0)
		return SSH_ERR_KEY_INVALID_EC_VALUE;

	crypto_scalarmult_curve25519(shared_key, key, pub);
#endif /* USING_WOLFSSL */
#ifdef DEBUG_KEXECDH
	dump_digest("shared secret", shared_key, CURVE25519_SIZE);
#endif
	sshbuf_reset(out);
	r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
	explicit_bzero(shared_key, CURVE25519_SIZE);
	return r;
}
Beispiel #11
0
static int
monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser,
    char *chost)
{
	Buffer b;
	char *p, *userstyle;
	u_int len;
	int fail = 0;

	buffer_init(&b);
	buffer_append(&b, data, datalen);

	p = buffer_get_string(&b, &len);
	if ((session_id2 == NULL) ||
	    (len != session_id2_len) ||
	    (timingsafe_bcmp(p, session_id2, session_id2_len) != 0))
		fail++;
	free(p);

	if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
		fail++;
	p = buffer_get_cstring(&b, NULL);
	xasprintf(&userstyle, "%s%s%s", authctxt->user,
	    authctxt->style ? ":" : "",
	    authctxt->style ? authctxt->style : "");
	if (strcmp(userstyle, p) != 0) {
		logit("wrong user name passed to monitor: expected %s != %.100s",
		    userstyle, p);
		fail++;
	}
	free(userstyle);
	free(p);
	buffer_skip_string(&b);	/* service */
	p = buffer_get_cstring(&b, NULL);
	if (strcmp(p, "hostbased") != 0)
		fail++;
	free(p);
	buffer_skip_string(&b);	/* pkalg */
	buffer_skip_string(&b);	/* pkblob */

	/* verify client host, strip trailing dot if necessary */
	p = buffer_get_string(&b, NULL);
	if (((len = strlen(p)) > 0) && p[len - 1] == '.')
		p[len - 1] = '\0';
	if (strcmp(p, chost) != 0)
		fail++;
	free(p);

	/* verify client user */
	p = buffer_get_string(&b, NULL);
	if (strcmp(p, cuser) != 0)
		fail++;
	free(p);

	if (buffer_len(&b) != 0)
		fail++;
	buffer_free(&b);
	return (fail == 0);
}
Beispiel #12
0
int test_bcmp() {
  size_t i;
  struct timespec x,y;
  long diff[4];

  memset(a,23,sizeof(a));
  memset(b,23,sizeof(b));
  assert(clock_gettime(CLOCK_MONOTONIC,&x)==0);
  for (i=0; i<100000; ++i) {
    assert(timingsafe_bcmp(a,b,sizeof(a))==0);
  }
  assert(clock_gettime(CLOCK_MONOTONIC,&y)==0);
  diff[0]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec;
  printf("timingsafe_bcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[0]);

  assert(clock_gettime(CLOCK_MONOTONIC,&x)==0);
  for (i=0; i<100000; ++i) {
    assert(bcmp(a,b,sizeof(a))==0);
  }
  assert(clock_gettime(CLOCK_MONOTONIC,&y)==0);
  diff[1]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec;
  printf("   regular bcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[1]);

  a[10]=24;	// now give bcmp an opportunity to exit early

  assert(clock_gettime(CLOCK_MONOTONIC,&x)==0);
  for (i=0; i<100000; ++i) {
    assert(timingsafe_bcmp(a,b,sizeof(a))==1);
  }
  assert(clock_gettime(CLOCK_MONOTONIC,&y)==0);
  diff[2]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec;
  printf("timingsafe_bcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[2]);

  assert(clock_gettime(CLOCK_MONOTONIC,&x)==0);
  for (i=0; i<100000; ++i) {
    assert(bcmp(a,b,sizeof(a))==1);
  }
  assert(clock_gettime(CLOCK_MONOTONIC,&y)==0);
  diff[3]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec;
  printf("   regular bcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[3]);

  /* we expect the timingsafe_bcmp values to be roughly the same (+- 10% for measurement inaccuracies) */
  long delta=diff[0]-diff[2];
  if (delta<0) delta=-delta;
  assert(delta*10<diff[0]);
}
Beispiel #13
0
/* allowed key state */
static int
monitor_allowed_key(u_char *blob, u_int bloblen)
{
	/* make sure key is allowed */
	if (key_blob == NULL || key_bloblen != bloblen ||
	    timingsafe_bcmp(key_blob, blob, key_bloblen))
		return (0);
	return (1);
}
Beispiel #14
0
/*
 * chachapoly_crypt() operates as following:
 * En/decrypt with header key 'aadlen' bytes from 'src', storing result
 * to 'dest'. The ciphertext here is treated as additional authenticated
 * data for MAC calculation.
 * En/decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. Use
 * POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the authentication
 * tag. This tag is written on encryption and verified on decryption.
 */
int
chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
    const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt)
{
	u_char seqbuf[8];
	const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
	u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
	int r = SSH_ERR_INTERNAL_ERROR;

	/*
	 * Run ChaCha20 once to generate the Poly1305 key. The IV is the
	 * packet sequence number.
	 */
	memset(poly_key, 0, sizeof(poly_key));
	POKE_U64(seqbuf, seqnr);
	chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
	chacha_encrypt_bytes(&ctx->main_ctx,
	    poly_key, poly_key, sizeof(poly_key));

	/* If decrypting, check tag before anything else */
	if (!do_encrypt) {
		const u_char *tag = src + aadlen + len;

		poly1305_auth(expected_tag, src, aadlen + len, poly_key);
		if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
			r = SSH_ERR_MAC_INVALID;
			goto out;
		}
	}

	/* Crypt additional data */
	if (aadlen) {
		chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL);
		chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen);
	}

	/* Set Chacha's block counter to 1 */
	chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
	chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen,
	    dest + aadlen, len);

	/* If encrypting, calculate and append tag */
	if (do_encrypt) {
		poly1305_auth(dest + aadlen + len, dest, aadlen + len,
		    poly_key);
	}
	r = 0;
 out:
	explicit_bzero(expected_tag, sizeof(expected_tag));
	explicit_bzero(seqbuf, sizeof(seqbuf));
	explicit_bzero(poly_key, sizeof(poly_key));
	return r;
}
Beispiel #15
0
int
kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
    const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
{
	u_char shared_key[CURVE25519_SIZE];
	int r;

	/* Check for all-zero public key */
	explicit_bzero(shared_key, CURVE25519_SIZE);
	if (timingsafe_bcmp(pub, shared_key, CURVE25519_SIZE) == 0)
		return SSH_ERR_KEY_INVALID_EC_VALUE;

	crypto_scalarmult_curve25519(shared_key, key, pub);
#ifdef DEBUG_KEXECDH
	dump_digest("shared secret", shared_key, CURVE25519_SIZE);
#endif
	sshbuf_reset(out);
	r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
	explicit_bzero(shared_key, CURVE25519_SIZE);
	return r;
}
Beispiel #16
0
/*
 * ESP input callback from the crypto driver.
 */
static int
esp_input_cb(struct cryptop *crp)
{
	IPSEC_DEBUG_DECLARE(char buf[128]);
	u_int8_t lastthree[3], aalg[AH_HMAC_MAXHASHLEN];
	const struct auth_hash *esph;
	const struct enc_xform *espx;
	struct mbuf *m;
	struct cryptodesc *crd;
	struct xform_data *xd;
	struct secasvar *sav;
	struct secasindex *saidx;
	caddr_t ptr;
	uint64_t cryptoid;
	int hlen, skip, protoff, error, alen;

	crd = crp->crp_desc;
	IPSEC_ASSERT(crd != NULL, ("null crypto descriptor!"));

	m = (struct mbuf *) crp->crp_buf;
	xd = (struct xform_data *) crp->crp_opaque;
	sav = xd->sav;
	skip = xd->skip;
	protoff = xd->protoff;
	cryptoid = xd->cryptoid;
	saidx = &sav->sah->saidx;
	esph = sav->tdb_authalgxform;
	espx = sav->tdb_encalgxform;

	/* Check for crypto errors */
	if (crp->crp_etype) {
		if (crp->crp_etype == EAGAIN) {
			/* Reset the session ID */
			if (ipsec_updateid(sav, &crp->crp_sid, &cryptoid) != 0)
				crypto_freesession(cryptoid);
			xd->cryptoid = crp->crp_sid;
			return (crypto_dispatch(crp));
		}
		ESPSTAT_INC(esps_noxform);
		DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
		error = crp->crp_etype;
		goto bad;
	}

	/* Shouldn't happen... */
	if (m == NULL) {
		ESPSTAT_INC(esps_crypto);
		DPRINTF(("%s: bogus returned buffer from crypto\n", __func__));
		error = EINVAL;
		goto bad;
	}
	ESPSTAT_INC(esps_hist[sav->alg_enc]);

	/* If authentication was performed, check now. */
	if (esph != NULL) {
		alen = xform_ah_authsize(esph);
		AHSTAT_INC(ahs_hist[sav->alg_auth]);
		/* Copy the authenticator from the packet */
		m_copydata(m, m->m_pkthdr.len - alen, alen, aalg);
		ptr = (caddr_t) (xd + 1);

		/* Verify authenticator */
		if (timingsafe_bcmp(ptr, aalg, alen) != 0) {
			DPRINTF(("%s: authentication hash mismatch for "
			    "packet in SA %s/%08lx\n", __func__,
			    ipsec_address(&saidx->dst, buf, sizeof(buf)),
			    (u_long) ntohl(sav->spi)));
			ESPSTAT_INC(esps_badauth);
			error = EACCES;
			goto bad;
		}
		m->m_flags |= M_AUTHIPDGM;
		/* Remove trailing authenticator */
		m_adj(m, -alen);
	}

	/* Release the crypto descriptors */
	free(xd, M_XDATA), xd = NULL;
	crypto_freereq(crp), crp = NULL;

	/*
	 * Packet is now decrypted.
	 */
	m->m_flags |= M_DECRYPTED;

	/*
	 * Update replay sequence number, if appropriate.
	 */
	if (sav->replay) {
		u_int32_t seq;

		m_copydata(m, skip + offsetof(struct newesp, esp_seq),
			   sizeof (seq), (caddr_t) &seq);
		SECASVAR_LOCK(sav);
		if (ipsec_updatereplay(ntohl(seq), sav)) {
			SECASVAR_UNLOCK(sav);
			DPRINTF(("%s: packet replay check for %s\n", __func__,
			    ipsec_sa2str(sav, buf, sizeof(buf))));
			ESPSTAT_INC(esps_replay);
			error = EACCES;
			goto bad;
		}
		SECASVAR_UNLOCK(sav);
	}
Beispiel #17
0
/*
 * ESP input callback, called directly by the crypto driver.
 */
int
esp_input_cb(void *op)
{
	u_int8_t lastthree[3], aalg[AH_HMAC_MAX_HASHLEN];
	int s, hlen, roff, skip, protoff, error;
	struct mbuf *m1, *mo, *m;
	struct auth_hash *esph;
	struct tdb_crypto *tc;
	struct cryptop *crp;
	struct m_tag *mtag;
	struct tdb *tdb;
	u_int32_t btsx;
	caddr_t ptr;

	crp = (struct cryptop *) op;

	tc = (struct tdb_crypto *) crp->crp_opaque;
	skip = tc->tc_skip;
	protoff = tc->tc_protoff;
	mtag = (struct m_tag *) tc->tc_ptr;

	m = (struct mbuf *) crp->crp_buf;
	if (m == NULL) {
		/* Shouldn't happen... */
		free(tc, M_XDATA);
		crypto_freereq(crp);
		espstat.esps_crypto++;
		DPRINTF(("esp_input_cb(): bogus returned buffer from crypto\n"));
		return (EINVAL);
	}

	s = spltdb();

	tdb = gettdb(tc->tc_rdomain, tc->tc_spi, &tc->tc_dst, tc->tc_proto);
	if (tdb == NULL) {
		free(tc, M_XDATA);
		espstat.esps_notdb++;
		DPRINTF(("esp_input_cb(): TDB is expired while in crypto"));
		error = EPERM;
		goto baddone;
	}

	esph = (struct auth_hash *) tdb->tdb_authalgxform;

	/* Check for crypto errors */
	if (crp->crp_etype) {
		if (crp->crp_etype == EAGAIN) {
			/* Reset the session ID */
			if (tdb->tdb_cryptoid != 0)
				tdb->tdb_cryptoid = crp->crp_sid;
			splx(s);
			return crypto_dispatch(crp);
		}
		free(tc, M_XDATA);
		espstat.esps_noxform++;
		DPRINTF(("esp_input_cb(): crypto error %d\n", crp->crp_etype));
		error = crp->crp_etype;
		goto baddone;
	}

	/* If authentication was performed, check now. */
	if (esph != NULL) {
		/*
		 * If we have a tag, it means an IPsec-aware NIC did the verification
		 * for us.
		 */
		if (mtag == NULL) {
			/* Copy the authenticator from the packet */
			m_copydata(m, m->m_pkthdr.len - esph->authsize,
			    esph->authsize, aalg);

			ptr = (caddr_t) (tc + 1);

			/* Verify authenticator */
			if (timingsafe_bcmp(ptr, aalg, esph->authsize)) {
				free(tc, M_XDATA);
				DPRINTF(("esp_input_cb(): authentication failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
				espstat.esps_badauth++;
				error = EACCES;
				goto baddone;
			}
		}

		/* Remove trailing authenticator */
		m_adj(m, -(esph->authsize));
	}
	free(tc, M_XDATA);

	/* Replay window checking, if appropriate */
	if ((tdb->tdb_wnd > 0) && (!(tdb->tdb_flags & TDBF_NOREPLAY))) {
		m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
		    (unsigned char *) &btsx);
		btsx = ntohl(btsx);

		switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl),
		    tdb->tdb_wnd, &(tdb->tdb_bitmap), 1)) {
		case 0: /* All's well */
#if NPFSYNC > 0
			pfsync_update_tdb(tdb,0);
#endif
			break;

		case 1:
			DPRINTF(("esp_input_cb(): replay counter wrapped for SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
			espstat.esps_wrap++;
			error = EACCES;
			goto baddone;

		case 2:
		case 3:
			DPRINTF(("esp_input_cb(): duplicate packet received in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
			error = EACCES;
			goto baddone;

		default:
			DPRINTF(("esp_input_cb(): bogus value from checkreplaywindow32() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
			espstat.esps_replay++;
			error = EACCES;
			goto baddone;
		}
	}

	/* Release the crypto descriptors */
	crypto_freereq(crp);

	/* Determine the ESP header length */
	if (tdb->tdb_flags & TDBF_NOREPLAY)
		hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; /* "old" ESP */
	else
		hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; /* "new" ESP */

	/* Find beginning of ESP header */
	m1 = m_getptr(m, skip, &roff);
	if (m1 == NULL)	{
		espstat.esps_hdrops++;
		splx(s);
		DPRINTF(("esp_input_cb(): bad mbuf chain, SA %s/%08x\n",
		    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
		m_freem(m);
		return EINVAL;
	}

	/* Remove the ESP header and IV from the mbuf. */
	if (roff == 0) {
		/* The ESP header was conveniently at the beginning of the mbuf */
		m_adj(m1, hlen);
		if (!(m1->m_flags & M_PKTHDR))
			m->m_pkthdr.len -= hlen;
	} else if (roff + hlen >= m1->m_len) {
		/*
		 * Part or all of the ESP header is at the end of this mbuf, so
		 * first let's remove the remainder of the ESP header from the
		 * beginning of the remainder of the mbuf chain, if any.
		 */
		if (roff + hlen > m1->m_len) {
			/* Adjust the next mbuf by the remainder */
			m_adj(m1->m_next, roff + hlen - m1->m_len);

			/* The second mbuf is guaranteed not to have a pkthdr... */
			m->m_pkthdr.len -= (roff + hlen - m1->m_len);
		}

		/* Now, let's unlink the mbuf chain for a second...*/
		mo = m1->m_next;
		m1->m_next = NULL;

		/* ...and trim the end of the first part of the chain...sick */
		m_adj(m1, -(m1->m_len - roff));
		if (!(m1->m_flags & M_PKTHDR))
			m->m_pkthdr.len -= (m1->m_len - roff);

		/* Finally, let's relink */
		m1->m_next = mo;
	} else {
		/*
		 * The ESP header lies in the "middle" of the mbuf...do an
		 * overlapping copy of the remainder of the mbuf over the ESP
		 * header.
		 */
		bcopy(mtod(m1, u_char *) + roff + hlen,
		    mtod(m1, u_char *) + roff, m1->m_len - (roff + hlen));
		m1->m_len -= hlen;
		m->m_pkthdr.len -= hlen;
	}

	/* Save the last three bytes of decrypted data */
	m_copydata(m, m->m_pkthdr.len - 3, 3, lastthree);

	/* Verify pad length */
	if (lastthree[1] + 2 > m->m_pkthdr.len - skip) {
		espstat.esps_badilen++;
		splx(s);
		DPRINTF(("esp_input_cb(): invalid padding length %d for packet in SA %s/%08x\n", lastthree[1], ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
		m_freem(m);
		return EINVAL;
	}

	/* Verify correct decryption by checking the last padding bytes */
	if (!(tdb->tdb_flags & TDBF_RANDOMPADDING)) {
		if ((lastthree[1] != lastthree[0]) && (lastthree[1] != 0)) {
			espstat.esps_badenc++;
			splx(s);
			DPRINTF(("esp_input(): decryption failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
			m_freem(m);
			return EINVAL;
		}
	}

	/* Trim the mbuf chain to remove the trailing authenticator and padding */
	m_adj(m, -(lastthree[1] + 2));

	/* Restore the Next Protocol field */
	m_copyback(m, protoff, sizeof(u_int8_t), lastthree + 2, M_NOWAIT);

	/* Back to generic IPsec input processing */
	error = ipsec_common_input_cb(m, tdb, skip, protoff, mtag);
	splx(s);
	return (error);

 baddone:
	splx(s);

	if (m != NULL)
		m_freem(m);

	crypto_freereq(crp);

	return (error);
}
Beispiel #18
0
/*
 * ESP input callback from the crypto driver.
 */
static int
esp_input_cb(struct cryptop *crp)
{
	char buf[128];
	u_int8_t lastthree[3], aalg[AH_HMAC_MAXHASHLEN];
	int hlen, skip, protoff, error, alen;
	struct mbuf *m;
	struct cryptodesc *crd;
	struct auth_hash *esph;
	struct enc_xform *espx;
	struct tdb_crypto *tc;
	struct secasvar *sav;
	struct secasindex *saidx;
	caddr_t ptr;

	crd = crp->crp_desc;
	IPSEC_ASSERT(crd != NULL, ("null crypto descriptor!"));

	tc = (struct tdb_crypto *) crp->crp_opaque;
	IPSEC_ASSERT(tc != NULL, ("null opaque crypto data area!"));
	skip = tc->tc_skip;
	protoff = tc->tc_protoff;
	m = (struct mbuf *) crp->crp_buf;

	sav = tc->tc_sav;
	IPSEC_ASSERT(sav != NULL, ("null SA!"));

	saidx = &sav->sah->saidx;
	IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
		saidx->dst.sa.sa_family == AF_INET6,
		("unexpected protocol family %u", saidx->dst.sa.sa_family));

	esph = sav->tdb_authalgxform;
	espx = sav->tdb_encalgxform;

	/* Check for crypto errors */
	if (crp->crp_etype) {
		/* Reset the session ID */
		if (sav->tdb_cryptoid != 0)
			sav->tdb_cryptoid = crp->crp_sid;

		if (crp->crp_etype == EAGAIN)
			return (crypto_dispatch(crp));

		ESPSTAT_INC(esps_noxform);
		DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
		error = crp->crp_etype;
		goto bad;
	}

	/* Shouldn't happen... */
	if (m == NULL) {
		ESPSTAT_INC(esps_crypto);
		DPRINTF(("%s: bogus returned buffer from crypto\n", __func__));
		error = EINVAL;
		goto bad;
	}
	ESPSTAT_INC(esps_hist[sav->alg_enc]);

	/* If authentication was performed, check now. */
	if (esph != NULL) {
		alen = xform_ah_authsize(esph);
		AHSTAT_INC(ahs_hist[sav->alg_auth]);
		/* Copy the authenticator from the packet */
		m_copydata(m, m->m_pkthdr.len - alen, alen, aalg);
		ptr = (caddr_t) (tc + 1);

		/* Verify authenticator */
		if (timingsafe_bcmp(ptr, aalg, alen) != 0) {
			DPRINTF(("%s: authentication hash mismatch for "
			    "packet in SA %s/%08lx\n", __func__,
			    ipsec_address(&saidx->dst, buf, sizeof(buf)),
			    (u_long) ntohl(sav->spi)));
			ESPSTAT_INC(esps_badauth);
			error = EACCES;
			goto bad;
		}

		/* Remove trailing authenticator */
		m_adj(m, -alen);
	}

	/* Release the crypto descriptors */
	free(tc, M_XDATA), tc = NULL;
	crypto_freereq(crp), crp = NULL;

	/*
	 * Packet is now decrypted.
	 */
	m->m_flags |= M_DECRYPTED;

	/*
	 * Update replay sequence number, if appropriate.
	 */
	if (sav->replay) {
		u_int32_t seq;

		m_copydata(m, skip + offsetof(struct newesp, esp_seq),
			   sizeof (seq), (caddr_t) &seq);
		if (ipsec_updatereplay(ntohl(seq), sav)) {
			DPRINTF(("%s: packet replay check for %s\n", __func__,
			    ipsec_logsastr(sav, buf, sizeof(buf))));
			ESPSTAT_INC(esps_replay);
			error = ENOBUFS;
			goto bad;
		}
	}
Beispiel #19
0
static int
monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser,
    char *chost)
{
	struct sshbuf *b;
	char *username, *methodname, *rawhost, *ruser, *userstyle;
	u_char *sid, c;
	size_t len;
	int r, fail = 0;

	if ((b = sshbuf_from(data, datalen)) == NULL)
		fatal("%s: sshbuf_from failed", __func__);
	if ((r = sshbuf_get_string(b, &sid, &len)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));

	if ((session_id2 == NULL) ||
	    (len != session_id2_len) ||
	    (timingsafe_bcmp(sid, session_id2, session_id2_len) != 0))
		fail++;
	free(sid);

	if ((r = sshbuf_get_u8(b, &c)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	if (c != SSH2_MSG_USERAUTH_REQUEST)
		fail++;
	if ((r = sshbuf_get_cstring(b, &username, NULL)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	xasprintf(&userstyle, "%s%s%s", authctxt->user,
	    authctxt->style ? ":" : "",
	    authctxt->style ? authctxt->style : "");
	if (strcmp(userstyle, username) != 0) {
		logit("wrong user name sent to monitor: expected %s != %.100s",
		    userstyle, username);
		fail++;
	}
	free(userstyle);
	free(username);
	if ((r = sshbuf_skip_string(b)) != 0 || /* service */
	    (r = sshbuf_get_cstring(b, &methodname, NULL)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	if (strcmp("hostbased", methodname) != 0)
		fail++;
	free(methodname);
	if ((r = sshbuf_skip_string(b)) != 0 ||	/* pkalg */
	    (r = sshbuf_skip_string(b)) != 0)	/* pkblob */
		fatal("%s: buffer error: %s", __func__, ssh_err(r));

	/* verify client host, strip trailing dot if necessary */
	if ((r = sshbuf_get_cstring(b, &rawhost, NULL)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	if (((len = strlen(rawhost)) > 0) && rawhost[len - 1] == '.')
		rawhost[len - 1] = '\0';
	if (strcmp(rawhost, chost) != 0)
		fail++;
	free(rawhost);

	/* verify client user */
	if ((r = sshbuf_get_cstring(b, &ruser, NULL)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	if (strcmp(ruser, cuser) != 0)
		fail++;
	free(ruser);

	if (sshbuf_len(b) != 0)
		fail++;
	sshbuf_free(b);
	return (fail == 0);
}
Beispiel #20
0
static int
monitor_valid_userblob(u_char *data, u_int datalen)
{
	struct sshbuf *b;
	u_char *p, c;
	const u_char *cp;
	size_t len;
	int r, fail = 0;
	char *username, *methodname, *userstyle;

	if ((b = sshbuf_from(data, datalen)) == NULL)
		fatal("%s: sshbuf_from failed", __func__);

	if (active_state->compat & SSH_OLD_SESSIONID) {
		cp = sshbuf_ptr(b);
		len = sshbuf_len(b);
		if ((session_id2 == NULL) ||
		    (len < session_id2_len) ||
		    (timingsafe_bcmp(cp, session_id2, session_id2_len) != 0))
			fail++;
		if ((r = sshbuf_consume(b, session_id2_len)) != 0)
			fatal("%s: buffer error: %s", __func__, ssh_err(r));
	} else {
		if ((r = sshbuf_get_string(b, &p, &len)) != 0)
			fatal("%s: buffer error: %s", __func__, ssh_err(r));
		if ((session_id2 == NULL) ||
		    (len != session_id2_len) ||
		    (timingsafe_bcmp(p, session_id2, session_id2_len) != 0))
			fail++;
		free(p);
	}
	if ((r = sshbuf_get_u8(b, &c)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	if (c != SSH2_MSG_USERAUTH_REQUEST)
		fail++;
	xasprintf(&userstyle, "%s%s%s", authctxt->user,
	    authctxt->style ? ":" : "",
	    authctxt->style ? authctxt->style : "");
	if ((r = sshbuf_get_cstring(b, &username, NULL)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	if (strcmp(userstyle, username) != 0) {
		logit("wrong user name sent to monitor: expected %s != %.100s",
		    userstyle, username);
		fail++;
	}
	free(username);
	free(userstyle);
	if ((r = sshbuf_skip_string(b)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	if (active_state->compat & SSH_BUG_PKAUTH) {
		if ((r = sshbuf_get_u8(b, &c)) != 0)
			fatal("%s: buffer error: %s", __func__, ssh_err(r));
		if (!c)
			fail++;
	} else {
		if ((r = sshbuf_get_cstring(b, &methodname, NULL)) != 0)
			fatal("%s: buffer error: %s", __func__, ssh_err(r));
		if (strcmp("publickey", methodname) != 0)
			fail++;
		free(methodname);
		if ((r = sshbuf_get_u8(b, &c)) != 0)
			fatal("%s: buffer error: %s", __func__, ssh_err(r));
		if (!c)
			fail++;
		if ((r = sshbuf_skip_string(b)) != 0)
			fatal("%s: buffer error: %s", __func__, ssh_err(r));
	}
	if ((r = sshbuf_skip_string(b)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	if (sshbuf_len(b) != 0)
		fail++;
	sshbuf_free(b);
	return (fail == 0);
}
Beispiel #21
0
int
crypto_verify_32(const unsigned char *x, const unsigned char *y)
{
	return timingsafe_bcmp(x, y, 32) ? -1 : 0;
}
Beispiel #22
0
/*
 * Verify the given hostname, address and host key using DNS.
 * Returns 0 if lookup succeeds, -1 otherwise
 */
int
verify_host_key_dns(const char *hostname, struct sockaddr *address,
    struct sshkey *hostkey, int *flags)
{
	u_int counter;
	int result;
	unsigned int rrset_flags = 0;
	struct rrsetinfo *fingerprints = NULL;

	u_int8_t hostkey_algorithm;
	u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED;
	u_char *hostkey_digest;
	size_t hostkey_digest_len;

	u_int8_t dnskey_algorithm;
	u_int8_t dnskey_digest_type;
	u_char *dnskey_digest;
	size_t dnskey_digest_len;

	*flags = 0;

	debug3("verify_host_key_dns");
	if (hostkey == NULL)
		fatal("No key to look up!");

	if (is_numeric_hostname(hostname)) {
		debug("skipped DNS lookup for numerical hostname");
		return -1;
	}

	/*
	 * Original getrrsetbyname function, found on OpenBSD for example,
	 * doesn't accept any flag and prerequisite for obtaining AD bit in
	 * DNS response is set by "options edns0" in resolv.conf.
	 *
	 * Our version is more clever and use RRSET_FORCE_EDNS0 flag.
	 */
#ifndef HAVE_GETRRSETBYNAME
	rrset_flags |= RRSET_FORCE_EDNS0;
#endif
	result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
	    DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints);

	if (result) {
		verbose("DNS lookup error: %s", dns_result_totext(result));
		return -1;
	}

	if (fingerprints->rri_flags & RRSET_VALIDATED) {
		*flags |= DNS_VERIFY_SECURE;
		debug("found %d secure fingerprints in DNS",
		    fingerprints->rri_nrdatas);
	} else {
		debug("found %d insecure fingerprints in DNS",
		    fingerprints->rri_nrdatas);
	}

	/* Initialize default host key parameters */
	if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
	    &hostkey_digest, &hostkey_digest_len, hostkey)) {
		error("Error calculating host key fingerprint.");
		freerrset(fingerprints);
		return -1;
	}

	if (fingerprints->rri_nrdatas)
		*flags |= DNS_VERIFY_FOUND;

	for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) {
		/*
		 * Extract the key from the answer. Ignore any badly
		 * formatted fingerprints.
		 */
		if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type,
		    &dnskey_digest, &dnskey_digest_len,
		    fingerprints->rri_rdatas[counter].rdi_data,
		    fingerprints->rri_rdatas[counter].rdi_length)) {
			verbose("Error parsing fingerprint from DNS.");
			continue;
		}

		if (hostkey_digest_type != dnskey_digest_type) {
			hostkey_digest_type = dnskey_digest_type;
			free(hostkey_digest);

			/* Initialize host key parameters */
			if (!dns_read_key(&hostkey_algorithm,
			    &hostkey_digest_type, &hostkey_digest,
			    &hostkey_digest_len, hostkey)) {
				error("Error calculating key fingerprint.");
				freerrset(fingerprints);
				return -1;
			}
		}

		/* Check if the current key is the same as the given key */
		if (hostkey_algorithm == dnskey_algorithm &&
		    hostkey_digest_type == dnskey_digest_type) {
			if (hostkey_digest_len == dnskey_digest_len &&
			    timingsafe_bcmp(hostkey_digest, dnskey_digest,
			    hostkey_digest_len) == 0)
				*flags |= DNS_VERIFY_MATCH;
		}
		free(dnskey_digest);
	}

	free(hostkey_digest); /* from sshkey_fingerprint_raw() */
	freerrset(fingerprints);

	if (*flags & DNS_VERIFY_FOUND)
		if (*flags & DNS_VERIFY_MATCH)
			debug("matching host key fingerprint found in DNS");
		else
			debug("mismatching host key fingerprint found in DNS");
	else
		debug("no host key fingerprint found in DNS");

	return 0;
}
Beispiel #23
0
int ssl3_get_finished(SSL *s, int a, int b)
	{
	int al,i,ok;
	long n;
	unsigned char *p;

#ifdef OPENSSL_NO_NEXTPROTONEG
	/* the mac has already been generated when we received the change
	 * cipher spec message and is in s->s3->tmp.peer_finish_md. */
#endif

	n=s->method->ssl_get_message(s,
		a,
		b,
		SSL3_MT_FINISHED,
		64, /* should actually be 36+4 :-) */
		&ok);

	if (!ok) return((int)n);

	/* If this occurs, we have missed a message */
	if (!s->s3->change_cipher_spec)
		{
		al=SSL_AD_UNEXPECTED_MESSAGE;
		SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_GOT_A_FIN_BEFORE_A_CCS);
		goto f_err;
		}
	s->s3->change_cipher_spec=0;

	p = (unsigned char *)s->init_msg;
	i = s->s3->tmp.peer_finish_md_len;

	if (i != n)
		{
		al=SSL_AD_DECODE_ERROR;
		SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_BAD_DIGEST_LENGTH);
		goto f_err;
		}

	if (timingsafe_bcmp(p, s->s3->tmp.peer_finish_md, i) != 0)
		{
		al=SSL_AD_DECRYPT_ERROR;
		SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_DIGEST_CHECK_FAILED);
		goto f_err;
		}

        /* Copy the finished so we can use it for
           renegotiation checks */
        if(s->type == SSL_ST_ACCEPT)
                {
                OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
                memcpy(s->s3->previous_client_finished, 
                    s->s3->tmp.peer_finish_md, i);
                s->s3->previous_client_finished_len=i;
                }
        else
                {
                OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
                memcpy(s->s3->previous_server_finished, 
                    s->s3->tmp.peer_finish_md, i);
                s->s3->previous_server_finished_len=i;
                }

	return(1);
f_err:
	ssl3_send_alert(s,SSL3_AL_FATAL,al);
	return(0);
	}
struct mbuf *
ieee80211_ccmp_decrypt(struct ieee80211com *ic, struct mbuf *m0,
    struct ieee80211_key *k)
{
	struct ieee80211_ccmp_ctx *ctx = k->k_priv;
	struct ieee80211_frame *wh;
	u_int64_t pn, *prsc;
	const u_int8_t *ivp, *src;
	u_int8_t *dst;
	u_int8_t mic0[IEEE80211_CCMP_MICLEN];
	u_int8_t a[16], b[16], s0[16], s[16];
	struct mbuf *n0, *m, *n;
	int hdrlen, left, moff, noff, len;
	u_int16_t ctr;
	int i, j;

	wh = mtod(m0, struct ieee80211_frame *);
	hdrlen = ieee80211_get_hdrlen(wh);
	ivp = (u_int8_t *)wh + hdrlen;

	if (m0->m_pkthdr.len < hdrlen + IEEE80211_CCMP_HDRLEN +
	    IEEE80211_CCMP_MICLEN) {
		m_freem(m0);
		return NULL;
	}
	/* check that ExtIV bit is set */
	if (!(ivp[3] & IEEE80211_WEP_EXTIV)) {
		m_freem(m0);
		return NULL;
	}

	/* retrieve last seen packet number for this frame type/priority */
	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
	    IEEE80211_FC0_TYPE_DATA) {
		u_int8_t tid = ieee80211_has_qos(wh) ?
		    ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
		prsc = &k->k_rsc[tid];
	} else	/* 11w: management frames have their own counters */
		prsc = &k->k_mgmt_rsc;

	/* extract the 48-bit PN from the CCMP header */
	pn = (u_int64_t)ivp[0]       |
	     (u_int64_t)ivp[1] <<  8 |
	     (u_int64_t)ivp[4] << 16 |
	     (u_int64_t)ivp[5] << 24 |
	     (u_int64_t)ivp[6] << 32 |
	     (u_int64_t)ivp[7] << 40;
	if (pn <= *prsc) {
		/* replayed frame, discard */
		ic->ic_stats.is_ccmp_replays++;
		m_freem(m0);
		return NULL;
	}

	MGET(n0, M_DONTWAIT, m0->m_type);
	if (n0 == NULL)
		goto nospace;
	if (m_dup_pkthdr(n0, m0, M_DONTWAIT))
		goto nospace;
	n0->m_pkthdr.len -= IEEE80211_CCMP_HDRLEN + IEEE80211_CCMP_MICLEN;
	n0->m_len = MHLEN;
	if (n0->m_pkthdr.len >= MINCLSIZE) {
		MCLGET(n0, M_DONTWAIT);
		if (n0->m_flags & M_EXT)
			n0->m_len = n0->m_ext.ext_size;
	}
	if (n0->m_len > n0->m_pkthdr.len)
		n0->m_len = n0->m_pkthdr.len;

	/* construct initial B, A and S_0 blocks */
	ieee80211_ccmp_phase1(&ctx->rijndael, wh, pn,
	    n0->m_pkthdr.len - hdrlen, b, a, s0);

	/* copy 802.11 header and clear protected bit */
	memcpy(mtod(n0, caddr_t), wh, hdrlen);
	wh = mtod(n0, struct ieee80211_frame *);
	wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;

	/* construct S_1 */
	ctr = 1;
	a[14] = ctr >> 8;
	a[15] = ctr & 0xff;
	rijndael_encrypt(&ctx->rijndael, a, s);

	/* decrypt frame body and compute MIC */
	j = 0;
	m = m0;
	n = n0;
	moff = hdrlen + IEEE80211_CCMP_HDRLEN;
	noff = hdrlen;
	left = n0->m_pkthdr.len - noff;
	while (left > 0) {
		if (moff == m->m_len) {
			/* nothing left to copy from m */
			m = m->m_next;
			moff = 0;
		}
		if (noff == n->m_len) {
			/* n is full and there's more data to copy */
			MGET(n->m_next, M_DONTWAIT, n->m_type);
			if (n->m_next == NULL)
				goto nospace;
			n = n->m_next;
			n->m_len = MLEN;
			if (left >= MINCLSIZE) {
				MCLGET(n, M_DONTWAIT);
				if (n->m_flags & M_EXT)
					n->m_len = n->m_ext.ext_size;
			}
			if (n->m_len > left)
				n->m_len = left;
			noff = 0;
		}
		len = min(m->m_len - moff, n->m_len - noff);

		src = mtod(m, u_int8_t *) + moff;
		dst = mtod(n, u_int8_t *) + noff;
		for (i = 0; i < len; i++) {
			/* decrypt message */
			dst[i] = src[i] ^ s[j];
			/* update MIC with clear text */
			b[j] ^= dst[i];
			if (++j < 16)
				continue;
			/* we have a full block, encrypt MIC */
			rijndael_encrypt(&ctx->rijndael, b, b);
			/* construct a new S_ctr block */
			ctr++;
			a[14] = ctr >> 8;
			a[15] = ctr & 0xff;
			rijndael_encrypt(&ctx->rijndael, a, s);
			j = 0;
		}

		moff += len;
		noff += len;
		left -= len;
	}
	if (j != 0)	/* partial block, encrypt MIC */
		rijndael_encrypt(&ctx->rijndael, b, b);

	/* finalize MIC, U := T XOR first-M-bytes( S_0 ) */
	for (i = 0; i < IEEE80211_CCMP_MICLEN; i++)
		b[i] ^= s0[i];

	/* check that it matches the MIC in received frame */
	m_copydata(m, moff, IEEE80211_CCMP_MICLEN, mic0);
	if (timingsafe_bcmp(mic0, b, IEEE80211_CCMP_MICLEN) != 0) {
		ic->ic_stats.is_ccmp_dec_errs++;
		m_freem(m0);
		m_freem(n0);
		return NULL;
	}

	/* update last seen packet number (MIC is validated) */
	*prsc = pn;

	m_freem(m0);
	return n0;
 nospace:
	ic->ic_stats.is_rx_nombuf++;
	m_freem(m0);
	if (n0 != NULL)
		m_freem(n0);
	return NULL;
}
Beispiel #25
0
/*
 * Verify the given hostname, address and host key using DNS.
 * Returns 0 if lookup succeeds, -1 otherwise
 */
int
verify_host_key_dns(const char *hostname, struct sockaddr *address,
                    struct sshkey *hostkey, int *flags)
{
    u_int counter;
    int result;
    struct rrsetinfo *fingerprints = NULL;

    u_int8_t hostkey_algorithm;
    u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED;
    u_char *hostkey_digest;
    size_t hostkey_digest_len;

    u_int8_t dnskey_algorithm;
    u_int8_t dnskey_digest_type;
    u_char *dnskey_digest;
    size_t dnskey_digest_len;

    *flags = 0;

    debug3("verify_host_key_dns");
    if (hostkey == NULL)
        fatal("No key to look up!");

    if (is_numeric_hostname(hostname)) {
        debug("skipped DNS lookup for numerical hostname");
        return -1;
    }

    result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
                            DNS_RDATATYPE_SSHFP, 0, &fingerprints);
    if (result) {
        verbose("DNS lookup error: %s", dns_result_totext(result));
        return -1;
    }

    if (fingerprints->rri_flags & RRSET_VALIDATED) {
        *flags |= DNS_VERIFY_SECURE;
        debug("found %d secure fingerprints in DNS",
              fingerprints->rri_nrdatas);
    } else {
        debug("found %d insecure fingerprints in DNS",
              fingerprints->rri_nrdatas);
    }

    /* Initialize default host key parameters */
    if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
                      &hostkey_digest, &hostkey_digest_len, hostkey)) {
        error("Error calculating host key fingerprint.");
        freerrset(fingerprints);
        return -1;
    }

    if (fingerprints->rri_nrdatas)
        *flags |= DNS_VERIFY_FOUND;

    for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) {
        /*
         * Extract the key from the answer. Ignore any badly
         * formatted fingerprints.
         */
        if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type,
                            &dnskey_digest, &dnskey_digest_len,
                            fingerprints->rri_rdatas[counter].rdi_data,
                            fingerprints->rri_rdatas[counter].rdi_length)) {
            verbose("Error parsing fingerprint from DNS.");
            continue;
        }

        if (hostkey_digest_type != dnskey_digest_type) {
            hostkey_digest_type = dnskey_digest_type;
            free(hostkey_digest);

            /* Initialize host key parameters */
            if (!dns_read_key(&hostkey_algorithm,
                              &hostkey_digest_type, &hostkey_digest,
                              &hostkey_digest_len, hostkey)) {
                error("Error calculating key fingerprint.");
                freerrset(fingerprints);
                return -1;
            }
        }

        /* Check if the current key is the same as the given key */
        if (hostkey_algorithm == dnskey_algorithm &&
                hostkey_digest_type == dnskey_digest_type) {
            if (hostkey_digest_len == dnskey_digest_len &&
                    timingsafe_bcmp(hostkey_digest, dnskey_digest,
                                    hostkey_digest_len) == 0)
                *flags |= DNS_VERIFY_MATCH;
        }
        free(dnskey_digest);
    }

    free(hostkey_digest); /* from sshkey_fingerprint_raw() */
    freerrset(fingerprints);

    if (*flags & DNS_VERIFY_FOUND)
        if (*flags & DNS_VERIFY_MATCH)
            debug("matching host key fingerprint found in DNS");
        else
            debug("mismatching host key fingerprint found in DNS");
    else
        debug("no host key fingerprint found in DNS");

    return 0;
}
Beispiel #26
0
/* SSL 2.0 imlementation for SSL_read/SSL_peek -
 * This routine will return 0 to len bytes, decrypted etc if required.
 */
static int ssl2_read_internal(SSL *s, void *buf, int len, int peek)
	{
	int n;
	unsigned char mac[MAX_MAC_SIZE];
	unsigned char *p;
	int i;
	int mac_size;

 ssl2_read_again:
	if (SSL_in_init(s) && !s->in_handshake)
		{
		n=s->handshake_func(s);
		if (n < 0) return(n);
		if (n == 0)
			{
			SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_SSL_HANDSHAKE_FAILURE);
			return(-1);
			}
		}

	clear_sys_error();
	s->rwstate=SSL_NOTHING;
	if (len <= 0) return(len);

	if (s->s2->ract_data_length != 0) /* read from buffer */
		{
		if (len > s->s2->ract_data_length)
			n=s->s2->ract_data_length;
		else
			n=len;

		memcpy(buf,s->s2->ract_data,(unsigned int)n);
		if (!peek)
			{
			s->s2->ract_data_length-=n;
			s->s2->ract_data+=n;
			if (s->s2->ract_data_length == 0)
				s->rstate=SSL_ST_READ_HEADER;
			}

		return(n);
		}

	/* s->s2->ract_data_length == 0
	 * 
	 * Fill the buffer, then goto ssl2_read_again.
	 */

	if (s->rstate == SSL_ST_READ_HEADER)
		{
		if (s->first_packet)
			{
			n=read_n(s,5,SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2,0);
			if (n <= 0) return(n); /* error or non-blocking */
			s->first_packet=0;
			p=s->packet;
			if (!((p[0] & 0x80) && (
				(p[2] == SSL2_MT_CLIENT_HELLO) ||
				(p[2] == SSL2_MT_SERVER_HELLO))))
				{
				SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_NON_SSLV2_INITIAL_PACKET);
				return(-1);
				}
			}
		else
			{
			n=read_n(s,2,SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2,0);
			if (n <= 0) return(n); /* error or non-blocking */
			}
		/* part read stuff */

		s->rstate=SSL_ST_READ_BODY;
		p=s->packet;
		/* Do header */
		/*s->s2->padding=0;*/
		s->s2->escape=0;
		s->s2->rlength=(((unsigned int)p[0])<<8)|((unsigned int)p[1]);
		if ((p[0] & TWO_BYTE_BIT))		/* Two byte header? */
			{
			s->s2->three_byte_header=0;
			s->s2->rlength&=TWO_BYTE_MASK;	
			}
		else
			{
			s->s2->three_byte_header=1;
			s->s2->rlength&=THREE_BYTE_MASK;

			/* security >s2->escape */
			s->s2->escape=((p[0] & SEC_ESC_BIT))?1:0;
			}
		}

	if (s->rstate == SSL_ST_READ_BODY)
		{
		n=s->s2->rlength+2+s->s2->three_byte_header;
		if (n > (int)s->packet_length)
			{
			n-=s->packet_length;
			i=read_n(s,(unsigned int)n,(unsigned int)n,1);
			if (i <= 0) return(i); /* ERROR */
			}

		p= &(s->packet[2]);
		s->rstate=SSL_ST_READ_HEADER;
		if (s->s2->three_byte_header)
			s->s2->padding= *(p++);
		else	s->s2->padding=0;

		/* Data portion */
		if (s->s2->clear_text)
			{
			mac_size = 0;
			s->s2->mac_data=p;
			s->s2->ract_data=p;
			if (s->s2->padding)
				{
				SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_ILLEGAL_PADDING);
				return(-1);
				}
			}
		else
			{
			mac_size=EVP_MD_CTX_size(s->read_hash);
			if (mac_size < 0)
				return -1;
			OPENSSL_assert(mac_size <= MAX_MAC_SIZE);
			s->s2->mac_data=p;
			s->s2->ract_data= &p[mac_size];
			if (s->s2->padding + mac_size > s->s2->rlength)
				{
				SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_ILLEGAL_PADDING);
				return(-1);
				}
			}

		s->s2->ract_data_length=s->s2->rlength;
		/* added a check for length > max_size in case
		 * encryption was not turned on yet due to an error */
		if ((!s->s2->clear_text) &&
			(s->s2->rlength >= (unsigned int)mac_size))
			{
			ssl2_enc(s,0);
			s->s2->ract_data_length-=mac_size;
			ssl2_mac(s,mac,0);
			s->s2->ract_data_length-=s->s2->padding;
			if (	(timingsafe_bcmp(mac,s->s2->mac_data,mac_size) != 0) ||
				(s->s2->rlength%EVP_CIPHER_CTX_block_size(s->enc_read_ctx) != 0))
				{
				SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_BAD_MAC_DECODE);
				return(-1);
				}
			}
		INC32(s->s2->read_sequence); /* expect next number */
		/* s->s2->ract_data is now available for processing */

		/* Possibly the packet that we just read had 0 actual data bytes.
		 * (SSLeay/OpenSSL itself never sends such packets; see ssl2_write.)
		 * In this case, returning 0 would be interpreted by the caller
		 * as indicating EOF, so it's not a good idea.  Instead, we just
		 * continue reading; thus ssl2_read_internal may have to process
		 * multiple packets before it can return.
		 *
		 * [Note that using select() for blocking sockets *never* guarantees
		 * that the next SSL_read will not block -- the available
		 * data may contain incomplete packets, and except for SSL 2,
		 * renegotiation can confuse things even more.] */

		goto ssl2_read_again; /* This should really be
		                       * "return ssl2_read(s,buf,len)",
		                       * but that would allow for
		                       * denial-of-service attacks if a
		                       * C compiler is used that does not
		                       * recognize end-recursion. */
		}
	else
		{
		SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_BAD_STATE);
			return(-1);
		}
	}