예제 #1
0
int
_gnutls_mac_init(mac_hd_st * mac, const mac_entry_st * e,
		 const void *key, int keylen)
{
	int result;
	const gnutls_crypto_mac_st *cc = NULL;

	FAIL_IF_LIB_ERROR;

	if (unlikely(e == NULL || e->id == GNUTLS_MAC_NULL))
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	mac->e = e;
	mac->mac_len = _gnutls_mac_get_algo_len(e);

	/* check if a digest has been registered 
	 */
	cc = _gnutls_get_crypto_mac(e->id);
	if (cc != NULL && cc->init != NULL) {
		if (cc->init(e->id, &mac->handle) < 0) {
			gnutls_assert();
			return GNUTLS_E_HASH_FAILED;
		}

		if (cc->setkey(mac->handle, key, keylen) < 0) {
			gnutls_assert();
			cc->deinit(mac->handle);
			return GNUTLS_E_HASH_FAILED;
		}

		mac->hash = cc->hash;
		mac->setnonce = cc->setnonce;
		mac->output = cc->output;
		mac->deinit = cc->deinit;

		return 0;
	}

	result = _gnutls_mac_ops.init(e->id, &mac->handle);
	if (result < 0) {
		gnutls_assert();
		return result;
	}

	mac->hash = _gnutls_mac_ops.hash;
	mac->setnonce = _gnutls_mac_ops.setnonce;
	mac->output = _gnutls_mac_ops.output;
	mac->deinit = _gnutls_mac_ops.deinit;

	if (_gnutls_mac_ops.setkey(mac->handle, key, keylen) < 0) {
		gnutls_assert();
		mac->deinit(mac->handle);
		return GNUTLS_E_HASH_FAILED;
	}

	return 0;
}
예제 #2
0
int
_gnutls_mac_deinit_ssl3_handshake(digest_hd_st * handle,
				  void *digest, uint8_t * key,
				  uint32_t key_size)
{
	uint8_t ret[MAX_HASH_SIZE];
	digest_hd_st td;
	uint8_t opad[48];
	uint8_t ipad[48];
	int padsize;
	int block, rc;

	padsize = get_padsize(handle->e->id);
	if (padsize == 0) {
		gnutls_assert();
		rc = GNUTLS_E_INTERNAL_ERROR;
		goto cleanup;
	}

	memset(opad, 0x5C, padsize);
	memset(ipad, 0x36, padsize);

	rc = _gnutls_hash_init(&td, handle->e);
	if (rc < 0) {
		gnutls_assert();
		goto cleanup;
	}

	if (key_size > 0)
		_gnutls_hash(&td, key, key_size);

	_gnutls_hash(&td, opad, padsize);
	block = _gnutls_mac_get_algo_len(handle->e);

	if (key_size > 0)
		_gnutls_hash(handle, key, key_size);
	_gnutls_hash(handle, ipad, padsize);
	_gnutls_hash_deinit(handle, ret);	/* get the previous hash */

	_gnutls_hash(&td, ret, block);

	_gnutls_hash_deinit(&td, digest);

	return 0;

      cleanup:
	_gnutls_hash_deinit(handle, NULL);
	return rc;
}
예제 #3
0
int _gnutls_mac_output_ssl3(digest_hd_st * handle, void *digest)
{
	uint8_t ret[MAX_HASH_SIZE];
	digest_hd_st td;
	uint8_t opad[48];
	int padsize;
	int block, rc;

	padsize = get_padsize(handle->e->id);
	if (padsize == 0) {
		gnutls_assert();
		return GNUTLS_E_INTERNAL_ERROR;
	}

	memset(opad, 0x5C, padsize);

	rc = _gnutls_hash_init(&td, handle->e);
	if (rc < 0) {
		gnutls_assert();
		return rc;
	}

	if (handle->keysize > 0)
		_gnutls_hash(&td, handle->key, handle->keysize);

	_gnutls_hash(&td, opad, padsize);
	block = _gnutls_mac_get_algo_len(handle->e);
	_gnutls_hash_output(handle, ret);	/* get the previous hash */
	_gnutls_hash(&td, ret, block);

	_gnutls_hash_deinit(&td, digest);

	/* reset handle */
	memset(opad, 0x36, padsize);

	if (handle->keysize > 0)
		_gnutls_hash(handle, handle->key, handle->keysize);
	_gnutls_hash(handle, opad, padsize);

	return 0;
}
예제 #4
0
/* ID should be:
 * 3 for MAC
 * 2 for IV
 * 1 for encryption key
 *
 * Note that this function produces different key for the
 * NULL password, and for the password with zero length.
 */
int
_gnutls_pkcs12_string_to_key(const mac_entry_st * me,
			     unsigned int id, const uint8_t * salt,
			     unsigned int salt_size, unsigned int iter,
			     const char *pw, unsigned int req_keylen,
			     uint8_t * keybuf)
{
	int rc;
	unsigned int i, j;
	digest_hd_st md;
	bigint_t num_b1 = NULL, num_ij = NULL;
	bigint_t mpi512 = NULL;
	unsigned int pwlen;
	uint8_t hash[MAX_HASH_SIZE], buf_b[64], buf_i[MAX_PASS_LEN * 2 + 64], *p;
	uint8_t d[64];
	size_t cur_keylen;
	size_t n, m, p_size, i_size;
	unsigned mac_len;
	const uint8_t buf_512[] =	/* 2^64 */
	{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00
	};

	cur_keylen = 0;

	if (pw == NULL)
		pwlen = 0;
	else
		pwlen = strlen(pw);

	if (pwlen > MAX_PASS_LEN) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	if ((rc = _pkcs12_check_pass(pw, pwlen)) < 0) {
		gnutls_assert();
		return rc;
	}

	rc = _gnutls_mpi_init_scan(&mpi512, buf_512, sizeof(buf_512));
	if (rc < 0) {
		gnutls_assert();
		return rc;
	}

	/* Store salt and password in BUF_I */
	p_size = ((pwlen / 64) * 64) + 64;

	if (p_size > sizeof(buf_i) - 64)
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	p = buf_i;
	for (i = 0; i < 64; i++)
		*p++ = salt[i % salt_size];
	if (pw) {
		for (i = j = 0; i < p_size; i += 2) {
			*p++ = 0;
			*p++ = pw[j];
			if (++j > pwlen)	/* Note, that we include the trailing (0) */
				j = 0;
		}
	} else
		memset(p, 0, p_size);

	i_size = 64 + p_size;
	mac_len = _gnutls_mac_get_algo_len(me);

	for (;;) {
		rc = _gnutls_hash_init(&md, me);
		if (rc < 0) {
			gnutls_assert();
			goto cleanup;
		}
		memset(d, id & 0xff, 64);
		_gnutls_hash(&md, d, 64);
		_gnutls_hash(&md, buf_i, pw ? i_size : 64);
		_gnutls_hash_deinit(&md, hash);
		for (i = 1; i < iter; i++) {
			rc = _gnutls_hash_fast(me->id, hash, mac_len,
					       hash);
			if (rc < 0) {
				gnutls_assert();
				goto cleanup;
			}
		}
		for (i = 0; i < mac_len && cur_keylen < req_keylen; i++)
			keybuf[cur_keylen++] = hash[i];
		if (cur_keylen == req_keylen) {
			rc = 0;	/* ready */
			goto cleanup;
		}

		/* need more bytes. */
		for (i = 0; i < 64; i++)
			buf_b[i] = hash[i % mac_len];
		n = 64;
		rc = _gnutls_mpi_init_scan(&num_b1, buf_b, n);
		if (rc < 0) {
			gnutls_assert();
			goto cleanup;
		}

		rc = _gnutls_mpi_add_ui(num_b1, num_b1, 1);
		if (rc < 0) {
			gnutls_assert();
			goto cleanup;
		}
		
		for (i = 0; i < 128; i += 64) {
			n = 64;
			rc = _gnutls_mpi_init_scan(&num_ij, buf_i + i, n);
			if (rc < 0) {
				gnutls_assert();
				goto cleanup;
			}

			rc = _gnutls_mpi_addm(num_ij, num_ij, num_b1, mpi512);
			if (rc < 0) {
				gnutls_assert();
				goto cleanup;
			}

			n = 64;
#ifndef PKCS12_BROKEN_KEYGEN
			m = (_gnutls_mpi_get_nbits(num_ij) + 7) / 8;
#else
			m = n;
#endif
			memset(buf_i + i, 0, n - m);
			rc = _gnutls_mpi_print(num_ij, buf_i + i + n - m,
					       &n);
			if (rc < 0) {
				gnutls_assert();
				goto cleanup;
			}
			_gnutls_mpi_release(&num_ij);
		}
	}
      cleanup:
	_gnutls_mpi_release(&num_ij);
	_gnutls_mpi_release(&num_b1);
	_gnutls_mpi_release(&mpi512);

	return rc;
}
예제 #5
0
파일: pkcs12.c 프로젝트: gnutls/gnutls
/**
 * gnutls_pkcs12_generate_mac2:
 * @pkcs12: A pkcs12 type
 * @mac: the MAC algorithm to use
 * @pass: The password for the MAC
 *
 * This function will generate a MAC for the PKCS12 structure.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 **/
int gnutls_pkcs12_generate_mac2(gnutls_pkcs12_t pkcs12, gnutls_mac_algorithm_t mac, const char *pass)
{
	uint8_t salt[8], key[MAX_HASH_SIZE];
	int result;
	const int iter = 10*1024;
	mac_hd_st td1;
	gnutls_datum_t tmp = { NULL, 0 };
	unsigned mac_size, key_len;
	uint8_t mac_out[MAX_HASH_SIZE];
	const mac_entry_st *me = mac_to_entry(mac);

	if (pkcs12 == NULL || me == NULL)
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	if (me->oid == NULL)
		return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);

	mac_size = _gnutls_mac_get_algo_len(me);
	key_len = mac_size;

	/* Generate the salt.
	 */
	result = gnutls_rnd(GNUTLS_RND_NONCE, salt, sizeof(salt));
	if (result < 0) {
		gnutls_assert();
		return result;
	}

	/* Write the salt into the structure.
	 */
	result =
	    asn1_write_value(pkcs12->pkcs12, "macData.macSalt", salt,
			     sizeof(salt));
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		result = _gnutls_asn2err(result);
		goto cleanup;
	}

	/* write the iterations
	 */

	if (iter > 1) {
		result =
		    _gnutls_x509_write_uint32(pkcs12->pkcs12,
					      "macData.iterations", iter);
		if (result < 0) {
			gnutls_assert();
			goto cleanup;
		}
	}

	/* Generate the key.
	 */
#if ENABLE_GOST
	if (me->id == GNUTLS_MAC_GOSTR_94 ||
	    me->id == GNUTLS_MAC_STREEBOG_256 ||
	    me->id == GNUTLS_MAC_STREEBOG_512) {
		key_len = 32;
		result = _gnutls_pkcs12_gost_string_to_key(me->id,
							   salt,
							   sizeof(salt),
							   iter,
							   pass,
							   mac_size,
							   key);
	} else
#endif
		result = _gnutls_pkcs12_string_to_key(me, 3 /*MAC*/,
						      salt, sizeof(salt),
						      iter, pass,
						      mac_size, key);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	/* Get the data to be MACed
	 */
	result = _decode_pkcs12_auth_safe(pkcs12->pkcs12, NULL, &tmp);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	/* MAC the data
	 */
	result = _gnutls_mac_init(&td1, me,
				  key, key_len);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	_gnutls_mac(&td1, tmp.data, tmp.size);
	_gnutls_free_datum(&tmp);

	_gnutls_mac_deinit(&td1, mac_out);


	result =
	    asn1_write_value(pkcs12->pkcs12, "macData.mac.digest", mac_out,
			     mac_size);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		result = _gnutls_asn2err(result);
		goto cleanup;
	}

	result =
	    asn1_write_value(pkcs12->pkcs12,
			     "macData.mac.digestAlgorithm.parameters",
			     NULL, 0);
	if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) {
		gnutls_assert();
		result = _gnutls_asn2err(result);
		goto cleanup;
	}

	result =
	    asn1_write_value(pkcs12->pkcs12,
			     "macData.mac.digestAlgorithm.algorithm",
			     me->oid, 1);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		result = _gnutls_asn2err(result);
		goto cleanup;
	}

	return 0;

      cleanup:
	_gnutls_free_datum(&tmp);
	return result;
}
예제 #6
0
파일: pkcs12.c 프로젝트: gnutls/gnutls
/**
 * gnutls_pkcs12_verify_mac:
 * @pkcs12: should contain a gnutls_pkcs12_t type
 * @pass: The password for the MAC
 *
 * This function will verify the MAC for the PKCS12 structure.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 **/
int gnutls_pkcs12_verify_mac(gnutls_pkcs12_t pkcs12, const char *pass)
{
	uint8_t key[MAX_HASH_SIZE];
	char oid[MAX_OID_SIZE];
	int result;
	unsigned int iter;
	int len;
	mac_hd_st td1;
	gnutls_datum_t tmp = { NULL, 0 }, salt = {
	NULL, 0};
	uint8_t mac_output[MAX_HASH_SIZE];
	uint8_t mac_output_orig[MAX_HASH_SIZE];
	gnutls_mac_algorithm_t algo;
	unsigned mac_len, key_len;
	const mac_entry_st *entry;
#if ENABLE_GOST
	int gost_retry = 0;
#endif

	if (pkcs12 == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	/* read the iterations
	 */
	result =
	    _gnutls_x509_read_uint(pkcs12->pkcs12, "macData.iterations",
				   &iter);
	if (result < 0) {
		iter = 1;	/* the default */
	}

	len = sizeof(oid);
	result =
	    asn1_read_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm",
			    oid, &len);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	algo = gnutls_oid_to_digest(oid);
	if (algo == GNUTLS_MAC_UNKNOWN) {
 unknown_mac:
		gnutls_assert();
		return GNUTLS_E_UNKNOWN_HASH_ALGORITHM;
	}

	entry = mac_to_entry(algo);
	if (entry == NULL)
		goto unknown_mac;

	mac_len = _gnutls_mac_get_algo_len(entry);
	key_len = mac_len;

	/* Read the salt from the structure.
	 */
	result =
	    _gnutls_x509_read_null_value(pkcs12->pkcs12, "macData.macSalt",
				    &salt);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	/* Generate the key.
	 */
	result = _gnutls_pkcs12_string_to_key(entry, 3 /*MAC*/,
					      salt.data, salt.size,
					      iter, pass,
					      key_len, key);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	/* Get the data to be MACed
	 */
	result = _decode_pkcs12_auth_safe(pkcs12->pkcs12, NULL, &tmp);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

#if ENABLE_GOST
	/* GOST PKCS#12 files use either PKCS#12 scheme or proprietary
	 * HMAC-based scheme to generate MAC key. */
pkcs12_try_gost:
#endif

	/* MAC the data
	 */
	result = _gnutls_mac_init(&td1, entry, key, key_len);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	_gnutls_mac(&td1, tmp.data, tmp.size);

	_gnutls_mac_deinit(&td1, mac_output);

	len = sizeof(mac_output_orig);
	result =
	    asn1_read_value(pkcs12->pkcs12, "macData.mac.digest",
			    mac_output_orig, &len);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		result = _gnutls_asn2err(result);
		goto cleanup;
	}

	if ((unsigned)len != mac_len ||
	    memcmp(mac_output_orig, mac_output, len) != 0) {

#if ENABLE_GOST
		/* It is possible that GOST files use proprietary
		 * key generation scheme */
		if (!gost_retry &&
		    (algo == GNUTLS_MAC_GOSTR_94 ||
		     algo == GNUTLS_MAC_STREEBOG_256 ||
		     algo == GNUTLS_MAC_STREEBOG_512)) {
			gost_retry = 1;
			key_len = 32;
			result = _gnutls_pkcs12_gost_string_to_key(algo,
								   salt.data,
								   salt.size,
								   iter,
								   pass,
								   key_len,
								   key);
			if (result < 0) {
				gnutls_assert();
				goto cleanup;
			}

			goto pkcs12_try_gost;
		}
#endif

		gnutls_assert();
		result = GNUTLS_E_MAC_VERIFY_FAILED;
		goto cleanup;
	}

	result = 0;
 cleanup:
	_gnutls_free_datum(&tmp);
	_gnutls_free_datum(&salt);
	return result;
}
예제 #7
0
static int server_recv_params(gnutls_session_t session,
			      const unsigned char *data, size_t len,
			      const gnutls_psk_server_credentials_t pskcred)
{
	int ret;
	const mac_entry_st *prf;
	gnutls_datum_t full_client_hello;
	uint8_t binder_value[MAX_HASH_SIZE];
	uint16_t psk_index, i;
	gnutls_datum_t binder_recvd = { NULL, 0 };
	gnutls_datum_t key = {NULL, 0};
	psk_ext_parser_st psk_parser;
	psk_ext_iter_st psk_iter;
	struct psk_st psk;
	psk_auth_info_t info;
	tls13_ticket_st ticket_data;
	/* These values should be set properly when session ticket is accepted. */
	uint32_t ticket_age = UINT32_MAX;
	struct timespec ticket_creation_time = { 0, 0 };
	bool resuming;

	ret = _gnutls13_psk_ext_parser_init(&psk_parser, data, len);
	if (ret < 0) {
		/* No PSKs advertised by client */
		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
			return 0;
		return gnutls_assert_val(ret);
	}

	_gnutls13_psk_ext_iter_init(&psk_iter, &psk_parser);
	for (psk_index = 0; ; psk_index++) {
		ret = _gnutls13_psk_ext_iter_next_identity(&psk_iter, &psk);
		if (ret < 0) {
			/* We couldn't find any usable PSK */
			if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
				return 0;
			return gnutls_assert_val(ret);
		}

		/* This will unpack the session ticket if it is well
		 * formed and has the expected name */
		if (!(session->internals.flags & GNUTLS_NO_TICKETS) &&
		    (ret = _gnutls13_unpack_session_ticket(session, &psk.identity, &ticket_data)) == 0) {
			prf = ticket_data.prf;

			session->internals.resumption_requested = 1;

			/* Check whether ticket is stale or not */
			ticket_age = psk.ob_ticket_age - ticket_data.age_add;
			if (ticket_age / 1000 > ticket_data.lifetime) {
				gnutls_assert();
				tls13_ticket_deinit(&ticket_data);
				continue;
			}

			ret = compute_psk_from_ticket(&ticket_data, &key);
			if (ret < 0) {
				gnutls_assert();
				tls13_ticket_deinit(&ticket_data);
				continue;
			}

			memcpy(&ticket_creation_time,
			       &ticket_data.creation_time,
			       sizeof(struct timespec));

			tls13_ticket_deinit(&ticket_data);

			resuming = 1;
			break;
		} else if (pskcred &&
			   psk.ob_ticket_age == 0 &&
			   psk.identity.size > 0 && psk.identity.size <= MAX_USERNAME_SIZE) {
			/* _gnutls_psk_pwd_find_entry() expects 0-terminated identities */
			char identity_str[MAX_USERNAME_SIZE + 1];

			prf = pskcred->binder_algo;

			memcpy(identity_str, psk.identity.data, psk.identity.size);
			identity_str[psk.identity.size] = 0;

			/* this fails only on configuration errors; as such we always
			 * return its error code in that case */
			ret = _gnutls_psk_pwd_find_entry(session, identity_str, &key);
			if (ret < 0)
				return gnutls_assert_val(ret);

			resuming = 0;
			break;
		}
	}

	_gnutls13_psk_ext_iter_init(&psk_iter, &psk_parser);
	for (i = 0; i <= psk_index; i++) {
		ret = _gnutls13_psk_ext_iter_next_binder(&psk_iter, &binder_recvd);
		if (ret < 0) {
			gnutls_assert();
			/* We couldn't extract binder */
			if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
				ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
			goto fail;
		}
	}

	/* Get full ClientHello */
	if (!_gnutls_ext_get_full_client_hello(session, &full_client_hello)) {
		ret = GNUTLS_E_INTERNAL_ERROR;
		gnutls_assert();
		goto fail;
	}

	/* Compute the binder value for this PSK */
	ret = compute_psk_binder(session, prf, psk_parser.binders_len+2, 0, 0,
				 &key, &full_client_hello, resuming,
				 binder_value);
	if (ret < 0) {
		gnutls_assert();
		goto fail;
	}

	if (_gnutls_mac_get_algo_len(prf) != binder_recvd.size ||
	    safe_memcmp(binder_value, binder_recvd.data, binder_recvd.size)) {
		gnutls_assert();
		ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
		goto fail;
	}

	if (session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK)
		_gnutls_handshake_log("EXT[%p]: selected DHE-PSK mode\n", session);
	else {
		reset_cand_groups(session);
		_gnutls_handshake_log("EXT[%p]: selected PSK mode\n", session);
	}

	/* save the username in psk_auth_info to make it available
	 * using gnutls_psk_server_get_username() */
	if (!resuming) {
		assert(psk.identity.size < sizeof(info->username));

		ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1);
		if (ret < 0) {
			gnutls_assert();
			goto fail;
		}

		info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
		assert(info != NULL);

		memcpy(info->username, psk.identity.data, psk.identity.size);
		info->username[psk.identity.size] = 0;
		_gnutls_handshake_log("EXT[%p]: selected PSK identity: %s (%d)\n", session, info->username, psk_index);
	} else {
		if (session->internals.hsk_flags & HSK_EARLY_DATA_ACCEPTED) {
			if (session->internals.anti_replay) {
				ret = _gnutls_anti_replay_check(session->internals.anti_replay,
								ticket_age,
								&ticket_creation_time,
								&binder_recvd);
				if (ret < 0) {
					session->internals.hsk_flags &= ~HSK_EARLY_DATA_ACCEPTED;
					_gnutls_handshake_log("EXT[%p]: replay detected; rejecting early data\n",
						      session);
				}
			} else {
				_gnutls_handshake_log("EXT[%p]: anti-replay is not enabled; rejecting early data\n",
						      session);
				session->internals.hsk_flags &= ~HSK_EARLY_DATA_ACCEPTED;
			}
		}

		session->internals.resumed = RESUME_TRUE;
		_gnutls_handshake_log("EXT[%p]: selected resumption PSK identity (%d)\n", session, psk_index);
	}

	session->internals.hsk_flags |= HSK_PSK_SELECTED;

	/* Reference the selected pre-shared key */
	session->key.binders[0].psk.data = key.data;
	session->key.binders[0].psk.size = key.size;

	session->key.binders[0].idx = psk_index;
	session->key.binders[0].prf = prf;
	session->key.binders[0].resumption = resuming;

	ret = _gnutls_generate_early_secrets_for_psk(session);
	if (ret < 0) {
		gnutls_assert();
		goto fail;
	}

	return 0;

 fail:
	gnutls_free(key.data);
	return ret;
}
예제 #8
0
static int
client_send_params(gnutls_session_t session,
		   gnutls_buffer_t extdata,
		   const gnutls_psk_client_credentials_t cred)
{
	int ret, ext_offset = 0;
	uint8_t binder_value[MAX_HASH_SIZE];
	size_t spos;
	gnutls_datum_t username = {NULL, 0};
	gnutls_datum_t user_key = {NULL, 0}, rkey = {NULL, 0};
	gnutls_datum_t client_hello;
	unsigned next_idx;
	const mac_entry_st *prf_res = NULL;
	const mac_entry_st *prf_psk = NULL;
	struct timespec cur_time;
	uint32_t ticket_age, ob_ticket_age;
	int free_username = 0;
	psk_auth_info_t info = NULL;
	unsigned psk_id_len = 0;
	unsigned binders_len, binders_pos;

	if (((session->internals.flags & GNUTLS_NO_TICKETS) ||
	    session->internals.tls13_ticket.ticket.data == NULL) &&
	    (!cred || !_gnutls_have_psk_credentials(cred, session))) {

		return 0;
	}

	binders_len = 0;

	/* placeholder to be filled later */
	spos = extdata->length;
	ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* First, let's see if we have a session ticket to send */
	if (!(session->internals.flags & GNUTLS_NO_TICKETS) &&
	    session->internals.tls13_ticket.ticket.data != NULL) {
		/* We found a session ticket */
		if (unlikely(session->internals.tls13_ticket.prf == NULL)) {
			_gnutls13_session_ticket_unset(session);
			ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
			goto cleanup;
		}

		prf_res = session->internals.tls13_ticket.prf;

		gnutls_gettime(&cur_time);
		if (unlikely(_gnutls_timespec_cmp(&cur_time,
						  &session->internals.
						  tls13_ticket.
						  arrival_time) < 0)) {
			gnutls_assert();
			_gnutls13_session_ticket_unset(session);
			goto ignore_ticket;
		}

		/* Check whether the ticket is stale */
		ticket_age = timespec_sub_ms(&cur_time,
					     &session->internals.tls13_ticket.
					     arrival_time);
		if (ticket_age / 1000 > session->internals.tls13_ticket.lifetime) {
			_gnutls13_session_ticket_unset(session);
			goto ignore_ticket;
		}

		ret = compute_psk_from_ticket(&session->internals.tls13_ticket, &rkey);
		if (ret < 0) {
			_gnutls13_session_ticket_unset(session);
			goto ignore_ticket;
		}

		/* Calculate obfuscated ticket age, in milliseconds, mod 2^32 */
		ob_ticket_age = ticket_age + session->internals.tls13_ticket.age_add;

		if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16,
							     session->internals.tls13_ticket.ticket.data,
							     session->internals.tls13_ticket.ticket.size)) < 0) {
			gnutls_assert();
			goto cleanup;
		}

		/* Now append the obfuscated ticket age */
		if ((ret = _gnutls_buffer_append_prefix(extdata, 32, ob_ticket_age)) < 0) {
			gnutls_assert();
			goto cleanup;
		}

		psk_id_len += 6 + session->internals.tls13_ticket.ticket.size;
		binders_len += 1 + _gnutls_mac_get_algo_len(prf_res);
	}

 ignore_ticket:
	if (cred && _gnutls_have_psk_credentials(cred, session)) {
		gnutls_datum_t tkey;

		if (cred->binder_algo == NULL) {
			gnutls_assert();
			ret = gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
			goto cleanup;
		}

		prf_psk = cred->binder_algo;

		ret = _gnutls_find_psk_key(session, cred, &username, &tkey, &free_username);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		if (username.size == 0 || username.size > UINT16_MAX) {
			ret = gnutls_assert_val(GNUTLS_E_INVALID_PASSWORD);
			goto cleanup;
		}

		if (!free_username) {
			/* we need to copy the key */
			ret = _gnutls_set_datum(&user_key, tkey.data, tkey.size);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}
		} else {
			user_key.data = tkey.data;
			user_key.size = tkey.size;
		}

		ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
		assert(info != NULL);

		memcpy(info->username, username.data, username.size);
		info->username[username.size] = 0;

		if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16,
							     username.data,
							     username.size)) < 0) {
			gnutls_assert();
			goto cleanup;
		}

		/* Now append the obfuscated ticket age */
		if ((ret = _gnutls_buffer_append_prefix(extdata, 32, 0)) < 0) {
			gnutls_assert();
			goto cleanup;
		}

		psk_id_len += 6 + username.size;
		binders_len += 1 + _gnutls_mac_get_algo_len(prf_psk);
	}

	/* if no tickets or identities to be sent */
	if (psk_id_len == 0) {
		/* reset extensions buffer */
		extdata->length = spos;
		return 0;
	}

	_gnutls_write_uint16(psk_id_len, &extdata->data[spos]);

	binders_pos = extdata->length-spos;
	ext_offset = _gnutls_ext_get_extensions_offset(session);

	/* Compute the binders. extdata->data points to the start
	 * of this client hello. */
	assert(extdata->length >= sizeof(mbuffer_st));
	assert(ext_offset >= (ssize_t)sizeof(mbuffer_st));
	ext_offset -= sizeof(mbuffer_st);
	client_hello.data = extdata->data+sizeof(mbuffer_st);
	client_hello.size = extdata->length-sizeof(mbuffer_st);

	next_idx = 0;

	ret = _gnutls_buffer_append_prefix(extdata, 16, binders_len);
	if (ret < 0) {
		gnutls_assert_val(ret);
		goto cleanup;
	}

	if (prf_res && rkey.size > 0) {
		ret = compute_psk_binder(session, prf_res,
					 binders_len, binders_pos,
					 ext_offset, &rkey, &client_hello, 1,
					 binder_value);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		/* Associate the selected pre-shared key with the session */
		gnutls_free(session->key.binders[next_idx].psk.data);
		session->key.binders[next_idx].psk.data = rkey.data;
		session->key.binders[next_idx].psk.size = rkey.size;
		rkey.data = NULL;

		session->key.binders[next_idx].prf = prf_res;
		session->key.binders[next_idx].resumption = 1;
		session->key.binders[next_idx].idx = next_idx;

		_gnutls_handshake_log("EXT[%p]: sent PSK resumption identity (%d)\n", session, next_idx);

		next_idx++;

		/* Add the binder */
		ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_res->output_size);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		session->internals.hsk_flags |= HSK_TLS13_TICKET_SENT;
	}

	if (prf_psk && user_key.size > 0 && info) {
		ret = compute_psk_binder(session, prf_psk,
					 binders_len, binders_pos,
					 ext_offset, &user_key, &client_hello, 0,
					 binder_value);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		/* Associate the selected pre-shared key with the session */
		gnutls_free(session->key.binders[next_idx].psk.data);
		session->key.binders[next_idx].psk.data = user_key.data;
		session->key.binders[next_idx].psk.size = user_key.size;
		user_key.data = NULL;

		session->key.binders[next_idx].prf = prf_psk;
		session->key.binders[next_idx].resumption = 0;
		session->key.binders[next_idx].idx = next_idx;

		_gnutls_handshake_log("EXT[%p]: sent PSK identity '%s' (%d)\n", session, info->username, next_idx);

		next_idx++;

		/* Add the binder */
		ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_psk->output_size);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}
	}

	ret = 0;

cleanup:
	if (free_username)
		_gnutls_free_datum(&username);

	_gnutls_free_temp_key_datum(&user_key);
	_gnutls_free_temp_key_datum(&rkey);

	return ret;
}
예제 #9
0
static int
wrap_padlock_hmac_fast(gnutls_mac_algorithm_t algo,
		       const void *nonce, size_t nonce_size,
		       const void *key, size_t key_size, const void *text,
		       size_t text_size, void *digest)
{
	if (algo == GNUTLS_MAC_SHA1 || algo == GNUTLS_MAC_SHA256) {
		unsigned char *pad;
		unsigned char pad2[SHA1_DATA_SIZE + MAX_SHA_DIGEST_SIZE];
		unsigned char hkey[MAX_SHA_DIGEST_SIZE];
		unsigned int digest_size =
		    _gnutls_mac_get_algo_len(mac_to_entry(algo));

		if (key_size > SHA1_DATA_SIZE) {
			wrap_padlock_hash_fast((gnutls_digest_algorithm_t)
					       algo, key, key_size, hkey);
			key = hkey;
			key_size = digest_size;
		}

		pad = gnutls_malloc(text_size + SHA1_DATA_SIZE);
		if (pad == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		memset(pad, IPAD, SHA1_DATA_SIZE);
		memxor(pad, key, key_size);

		memcpy(&pad[SHA1_DATA_SIZE], text, text_size);

		wrap_padlock_hash_fast((gnutls_digest_algorithm_t) algo,
				       pad, text_size + SHA1_DATA_SIZE,
				       &pad2[SHA1_DATA_SIZE]);

		gnutls_free(pad);

		memset(pad2, OPAD, SHA1_DATA_SIZE);
		memxor(pad2, key, key_size);

		wrap_padlock_hash_fast((gnutls_digest_algorithm_t) algo,
				       pad2, digest_size + SHA1_DATA_SIZE,
				       digest);

	} else {
		struct padlock_hmac_ctx ctx;
		int ret;

		ret = _hmac_ctx_init(algo, &ctx);
		if (ret < 0)
			return gnutls_assert_val(ret);
		ctx.algo = algo;

		wrap_padlock_hmac_setkey(&ctx, key, key_size);

		wrap_padlock_hmac_update(&ctx, text, text_size);

		wrap_padlock_hmac_output(&ctx, digest, ctx.length);
		wrap_padlock_hmac_deinit(&ctx);
	}

	return 0;
}
예제 #10
0
/* Auth_cipher API 
 */
int _gnutls_auth_cipher_init(auth_cipher_hd_st * handle,
			     const cipher_entry_st * e,
			     const gnutls_datum_t * cipher_key,
			     const gnutls_datum_t * iv,
			     const mac_entry_st * me,
			     const gnutls_datum_t * mac_key,
			     unsigned etm,
			     unsigned ssl_hmac, int enc)
{
	int ret;

	if (unlikely(e == NULL))
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

        FAIL_IF_LIB_ERROR;

	memset(handle, 0, sizeof(*handle));
	handle->etm = etm;

	if (e->id != GNUTLS_CIPHER_NULL) {
		handle->non_null = 1;
		ret =
		    _gnutls_cipher_init(&handle->cipher, e, cipher_key, iv,
					enc);
		if (ret < 0)
			return gnutls_assert_val(ret);
	} else
		handle->non_null = 0;

	if (me->id != GNUTLS_MAC_AEAD) {
		handle->is_mac = 1;
		handle->ssl_hmac = ssl_hmac;

		if (ssl_hmac)
			ret =
			    _gnutls_mac_init_ssl3(&handle->mac.dig, me,
						  mac_key->data,
						  mac_key->size);
		else
			ret =
			    _gnutls_mac_init(&handle->mac.mac, me,
					     mac_key->data, mac_key->size);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		handle->tag_size = _gnutls_mac_get_algo_len(me);
	} else if (_gnutls_cipher_algo_is_aead(e)) {
		handle->tag_size = _gnutls_cipher_get_tag_size(e);
	} else {
		gnutls_assert();
		ret = GNUTLS_E_INVALID_REQUEST;
		goto cleanup;
	}

	return 0;
      cleanup:
	if (handle->non_null != 0)
		_gnutls_cipher_deinit(&handle->cipher);
	return ret;

}