1252190Srpaulo/*
2252190Srpaulo * TLS PRF P_SHA256
3252190Srpaulo * Copyright (c) 2011, Jouni Malinen <j@w1.fi>
4252190Srpaulo *
5252190Srpaulo * This software may be distributed under the terms of the BSD license.
6252190Srpaulo * See README for more details.
7252190Srpaulo */
8252190Srpaulo
9252190Srpaulo#include "includes.h"
10252190Srpaulo
11252190Srpaulo#include "common.h"
12252190Srpaulo#include "sha256.h"
13252190Srpaulo
14252190Srpaulo
15252190Srpaulo/**
16252190Srpaulo * tls_prf_sha256 - Pseudo-Random Function for TLS v1.2 (P_SHA256, RFC 5246)
17252190Srpaulo * @secret: Key for PRF
18252190Srpaulo * @secret_len: Length of the key in bytes
19252190Srpaulo * @label: A unique label for each purpose of the PRF
20252190Srpaulo * @seed: Seed value to bind into the key
21252190Srpaulo * @seed_len: Length of the seed
22252190Srpaulo * @out: Buffer for the generated pseudo-random key
23252190Srpaulo * @outlen: Number of bytes of key to generate
24252190Srpaulo * Returns: 0 on success, -1 on failure.
25252190Srpaulo *
26252190Srpaulo * This function is used to derive new, cryptographically separate keys from a
27252190Srpaulo * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
28252190Srpaulo */
29351611Scyint tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
30351611Scy		   const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
31252190Srpaulo{
32252190Srpaulo	size_t clen;
33252190Srpaulo	u8 A[SHA256_MAC_LEN];
34252190Srpaulo	u8 P[SHA256_MAC_LEN];
35252190Srpaulo	size_t pos;
36252190Srpaulo	const unsigned char *addr[3];
37252190Srpaulo	size_t len[3];
38252190Srpaulo
39252190Srpaulo	addr[0] = A;
40252190Srpaulo	len[0] = SHA256_MAC_LEN;
41252190Srpaulo	addr[1] = (unsigned char *) label;
42252190Srpaulo	len[1] = os_strlen(label);
43252190Srpaulo	addr[2] = seed;
44252190Srpaulo	len[2] = seed_len;
45252190Srpaulo
46252190Srpaulo	/*
47252190Srpaulo	 * RFC 5246, Chapter 5
48252190Srpaulo	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
49252190Srpaulo	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
50252190Srpaulo	 * PRF(secret, label, seed) = P_SHA256(secret, label + seed)
51252190Srpaulo	 */
52252190Srpaulo
53351611Scy	if (hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
54351611Scy		return -1;
55252190Srpaulo
56252190Srpaulo	pos = 0;
57252190Srpaulo	while (pos < outlen) {
58351611Scy		if (hmac_sha256_vector(secret, secret_len, 3, addr, len, P) <
59351611Scy		    0 ||
60351611Scy		    hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A) < 0)
61351611Scy			return -1;
62252190Srpaulo
63252190Srpaulo		clen = outlen - pos;
64252190Srpaulo		if (clen > SHA256_MAC_LEN)
65252190Srpaulo			clen = SHA256_MAC_LEN;
66252190Srpaulo		os_memcpy(out + pos, P, clen);
67252190Srpaulo		pos += clen;
68252190Srpaulo	}
69351611Scy
70351611Scy	return 0;
71252190Srpaulo}
72