static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
			int sec_len,
			const void *seed1, int seed1_len,
			const void *seed2, int seed2_len,
			const void *seed3, int seed3_len,
			const void *seed4, int seed4_len,
			const void *seed5, int seed5_len,
			unsigned char *out, int olen)
	{
	int chunk;
	unsigned int j;
	HMAC_CTX ctx;
	HMAC_CTX ctx_tmp;
	unsigned char A1[EVP_MAX_MD_SIZE];
	unsigned int A1_len;
	int ret = 0;
	
	chunk=EVP_MD_size(md);
	OPENSSL_assert(chunk >= 0);

	HMAC_CTX_init(&ctx);
	HMAC_CTX_init(&ctx_tmp);
	if (!HMAC_Init_ex(&ctx,sec,sec_len,md, NULL))
		goto err;
	if (!HMAC_Init_ex(&ctx_tmp,sec,sec_len,md, NULL))
		goto err;
	if (seed1 != NULL && !HMAC_Update(&ctx,seed1,seed1_len))
		goto err;
	if (seed2 != NULL && !HMAC_Update(&ctx,seed2,seed2_len))
		goto err;
	if (seed3 != NULL && !HMAC_Update(&ctx,seed3,seed3_len))
		goto err;
	if (seed4 != NULL && !HMAC_Update(&ctx,seed4,seed4_len))
		goto err;
	if (seed5 != NULL && !HMAC_Update(&ctx,seed5,seed5_len))
		goto err;
	if (!HMAC_Final(&ctx,A1,&A1_len))
		goto err;

	for (;;)
		{
		if (!HMAC_Init_ex(&ctx,NULL,0,NULL,NULL)) /* re-init */
			goto err;
		if (!HMAC_Init_ex(&ctx_tmp,NULL,0,NULL,NULL)) /* re-init */
			goto err;
		if (!HMAC_Update(&ctx,A1,A1_len))
			goto err;
		if (!HMAC_Update(&ctx_tmp,A1,A1_len))
			goto err;
		if (seed1 != NULL && !HMAC_Update(&ctx,seed1,seed1_len))
			goto err;
		if (seed2 != NULL && !HMAC_Update(&ctx,seed2,seed2_len))
			goto err;
		if (seed3 != NULL && !HMAC_Update(&ctx,seed3,seed3_len))
			goto err;
		if (seed4 != NULL && !HMAC_Update(&ctx,seed4,seed4_len))
			goto err;
		if (seed5 != NULL && !HMAC_Update(&ctx,seed5,seed5_len))
			goto err;

		if (olen > chunk)
			{
			if (!HMAC_Final(&ctx,out,&j))
				goto err;
			out+=j;
			olen-=j;
			if (!HMAC_Final(&ctx_tmp,A1,&A1_len)) /* calc the next A1 value */
				goto err;
			}
		else	/* last one */
			{
			if (!HMAC_Final(&ctx,A1,&A1_len))
				goto err;
			memcpy(out,A1,olen);
			break;
			}
		}
	ret = 1;
err:
	HMAC_CTX_cleanup(&ctx);
	HMAC_CTX_cleanup(&ctx_tmp);
	OPENSSL_cleanse(A1,sizeof(A1));
	return ret;
	}
static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
			int sec_len,
			const void *seed1, int seed1_len,
			const void *seed2, int seed2_len,
			const void *seed3, int seed3_len,
			const void *seed4, int seed4_len,
			const void *seed5, int seed5_len,
			unsigned char *out, int olen)
	{
	int chunk;
	unsigned int j;
	HMAC_CTX ctx;
	HMAC_CTX ctx_tmp;
	unsigned char A1[EVP_MAX_MD_SIZE];
	unsigned int A1_len;
	int ret = 0;
	
	chunk=EVP_MD_size(md);
	OPENSSL_assert(chunk >= 0);

	HMAC_CTX_init(&ctx);
	HMAC_CTX_init(&ctx_tmp);
	if (!HMAC_Init_ex(&ctx,sec,sec_len,md, NULL))
		goto err;
	if (!HMAC_Init_ex(&ctx_tmp,sec,sec_len,md, NULL))
		goto err;
	if (seed1 != NULL && !HMAC_Update(&ctx,seed1,seed1_len))
		goto err;
	if (seed2 != NULL && !HMAC_Update(&ctx,seed2,seed2_len))
		goto err;
	if (seed3 != NULL && !HMAC_Update(&ctx,seed3,seed3_len))
		goto err;
	if (seed4 != NULL && !HMAC_Update(&ctx,seed4,seed4_len))
		goto err;
	if (seed5 != NULL && !HMAC_Update(&ctx,seed5,seed5_len))
		goto err;
	if (!HMAC_Final(&ctx,A1,&A1_len))
		goto err;

	for (;;)
		{
		if (!HMAC_Init_ex(&ctx,NULL,0,NULL,NULL))  
			goto err;
		if (!HMAC_Init_ex(&ctx_tmp,NULL,0,NULL,NULL))  
			goto err;
		if (!HMAC_Update(&ctx,A1,A1_len))
			goto err;
		if (!HMAC_Update(&ctx_tmp,A1,A1_len))
			goto err;
		if (seed1 != NULL && !HMAC_Update(&ctx,seed1,seed1_len))
			goto err;
		if (seed2 != NULL && !HMAC_Update(&ctx,seed2,seed2_len))
			goto err;
		if (seed3 != NULL && !HMAC_Update(&ctx,seed3,seed3_len))
			goto err;
		if (seed4 != NULL && !HMAC_Update(&ctx,seed4,seed4_len))
			goto err;
		if (seed5 != NULL && !HMAC_Update(&ctx,seed5,seed5_len))
			goto err;

		if (olen > chunk)
			{
			if (!HMAC_Final(&ctx,out,&j))
				goto err;
			out+=j;
			olen-=j;
			if (!HMAC_Final(&ctx_tmp,A1,&A1_len))  
				goto err;
			}
		else	 
			{
			if (!HMAC_Final(&ctx,A1,&A1_len))
				goto err;
			memcpy(out,A1,olen);
			break;
			}
		}
	ret = 1;
err:
	HMAC_CTX_cleanup(&ctx);
	HMAC_CTX_cleanup(&ctx_tmp);
	OPENSSL_cleanse(A1,sizeof(A1));
	return ret;
	}