Register hmac/xcbc algorithms after potentially underlying PKCS#11
[strongswan.git] / src / libtls / tls_prf.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tls_prf.h"
17
18 typedef struct private_tls_prf12_t private_tls_prf12_t;
19
20 /**
21 * Private data of an tls_prf_t object.
22 */
23 struct private_tls_prf12_t {
24
25 /**
26 * Public tls_prf_t interface.
27 */
28 tls_prf_t public;
29
30 /**
31 * Underlying primitive PRF
32 */
33 prf_t *prf;
34 };
35
36 METHOD(tls_prf_t, set_key12, void,
37 private_tls_prf12_t *this, chunk_t key)
38 {
39 this->prf->set_key(this->prf, key);
40 }
41
42 /**
43 * The P_hash function as in TLS 1.0/1.2
44 */
45 static void p_hash(prf_t *prf, char *label, chunk_t seed, size_t block_size,
46 size_t bytes, char *out)
47 {
48 char buf[block_size], abuf[block_size];
49 chunk_t a;
50
51 /* seed = label + seed */
52 seed = chunk_cata("cc", chunk_create(label, strlen(label)), seed);
53 /* A(0) = seed */
54 a = seed;
55
56 while (TRUE)
57 {
58 /* A(i) = HMAC_hash(secret, A(i-1)) */
59 prf->get_bytes(prf, a, abuf);
60 a = chunk_from_thing(abuf);
61 /* HMAC_hash(secret, A(i) + seed) */
62 prf->get_bytes(prf, a, NULL);
63 prf->get_bytes(prf, seed, buf);
64
65 if (bytes <= block_size)
66 {
67 memcpy(out, buf, bytes);
68 break;
69 }
70 memcpy(out, buf, block_size);
71 out += block_size;
72 bytes -= block_size;
73 }
74 }
75
76 METHOD(tls_prf_t, get_bytes12, void,
77 private_tls_prf12_t *this, char *label, chunk_t seed,
78 size_t bytes, char *out)
79 {
80 p_hash(this->prf, label, seed, this->prf->get_block_size(this->prf),
81 bytes, out);
82 }
83
84 METHOD(tls_prf_t, destroy12, void,
85 private_tls_prf12_t *this)
86 {
87 this->prf->destroy(this->prf);
88 free(this);
89 }
90
91 /**
92 * See header
93 */
94 tls_prf_t *tls_prf_create_12(pseudo_random_function_t prf)
95 {
96 private_tls_prf12_t *this;
97
98 INIT(this,
99 .public = {
100 .set_key = _set_key12,
101 .get_bytes = _get_bytes12,
102 .destroy = _destroy12,
103 },
104 .prf = lib->crypto->create_prf(lib->crypto, prf),
105 );
106 if (!this->prf)
107 {
108 free(this);
109 return NULL;
110 }
111 return &this->public;
112 }
113
114
115 typedef struct private_tls_prf10_t private_tls_prf10_t;
116
117 /**
118 * Private data of an tls_prf_t object.
119 */
120 struct private_tls_prf10_t {
121
122 /**
123 * Public tls_prf_t interface.
124 */
125 tls_prf_t public;
126
127 /**
128 * Underlying MD5 PRF
129 */
130 prf_t *md5;
131
132 /**
133 * Underlying SHA1 PRF
134 */
135 prf_t *sha1;
136 };
137
138 METHOD(tls_prf_t, set_key10, void,
139 private_tls_prf10_t *this, chunk_t key)
140 {
141 size_t len = key.len / 2 + key.len % 2;
142
143 this->md5->set_key(this->md5, chunk_create(key.ptr, len));
144 this->sha1->set_key(this->sha1, chunk_create(key.ptr + key.len - len, len));
145 }
146
147 METHOD(tls_prf_t, get_bytes10, void,
148 private_tls_prf10_t *this, char *label, chunk_t seed,
149 size_t bytes, char *out)
150 {
151 char buf[bytes];
152
153 p_hash(this->md5, label, seed, this->md5->get_block_size(this->md5),
154 bytes, out);
155 p_hash(this->sha1, label, seed, this->sha1->get_block_size(this->sha1),
156 bytes, buf);
157 memxor(out, buf, bytes);
158 }
159
160 METHOD(tls_prf_t, destroy10, void,
161 private_tls_prf10_t *this)
162 {
163 DESTROY_IF(this->md5);
164 DESTROY_IF(this->sha1);
165 free(this);
166 }
167
168 /**
169 * See header
170 */
171 tls_prf_t *tls_prf_create_10(pseudo_random_function_t prf)
172 {
173 private_tls_prf10_t *this;
174
175 INIT(this,
176 .public = {
177 .set_key = _set_key10,
178 .get_bytes = _get_bytes10,
179 .destroy = _destroy10,
180 },
181 .md5 = lib->crypto->create_prf(lib->crypto, PRF_HMAC_MD5),
182 .sha1 = lib->crypto->create_prf(lib->crypto, PRF_HMAC_SHA1),
183 );
184 if (!this->md5 || !this->sha1)
185 {
186 destroy10(this);
187 return NULL;
188 }
189 return &this->public;
190 }