]>
Commit | Line | Data |
---|---|---|
149b7e6d MW |
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 | ||
e7d98b8c | 36 | METHOD(tls_prf_t, set_key12, bool, |
149b7e6d MW |
37 | private_tls_prf12_t *this, chunk_t key) |
38 | { | |
39 | this->prf->set_key(this->prf, key); | |
e7d98b8c | 40 | return TRUE; |
149b7e6d MW |
41 | } |
42 | ||
43 | /** | |
44 | * The P_hash function as in TLS 1.0/1.2 | |
45 | */ | |
97b30b93 | 46 | static bool p_hash(prf_t *prf, char *label, chunk_t seed, size_t block_size, |
149b7e6d MW |
47 | size_t bytes, char *out) |
48 | { | |
49 | char buf[block_size], abuf[block_size]; | |
50 | chunk_t a; | |
51 | ||
52 | /* seed = label + seed */ | |
53 | seed = chunk_cata("cc", chunk_create(label, strlen(label)), seed); | |
54 | /* A(0) = seed */ | |
55 | a = seed; | |
56 | ||
57 | while (TRUE) | |
58 | { | |
59 | /* A(i) = HMAC_hash(secret, A(i-1)) */ | |
60 | prf->get_bytes(prf, a, abuf); | |
61 | a = chunk_from_thing(abuf); | |
62 | /* HMAC_hash(secret, A(i) + seed) */ | |
63 | prf->get_bytes(prf, a, NULL); | |
64 | prf->get_bytes(prf, seed, buf); | |
65 | ||
66 | if (bytes <= block_size) | |
67 | { | |
68 | memcpy(out, buf, bytes); | |
69 | break; | |
70 | } | |
71 | memcpy(out, buf, block_size); | |
72 | out += block_size; | |
73 | bytes -= block_size; | |
74 | } | |
97b30b93 | 75 | return TRUE; |
149b7e6d MW |
76 | } |
77 | ||
97b30b93 | 78 | METHOD(tls_prf_t, get_bytes12, bool, |
149b7e6d MW |
79 | private_tls_prf12_t *this, char *label, chunk_t seed, |
80 | size_t bytes, char *out) | |
81 | { | |
97b30b93 MW |
82 | return p_hash(this->prf, label, seed, this->prf->get_block_size(this->prf), |
83 | bytes, out); | |
149b7e6d MW |
84 | } |
85 | ||
86 | METHOD(tls_prf_t, destroy12, void, | |
87 | private_tls_prf12_t *this) | |
88 | { | |
89 | this->prf->destroy(this->prf); | |
90 | free(this); | |
91 | } | |
92 | ||
93 | /** | |
94 | * See header | |
95 | */ | |
96 | tls_prf_t *tls_prf_create_12(pseudo_random_function_t prf) | |
97 | { | |
98 | private_tls_prf12_t *this; | |
99 | ||
100 | INIT(this, | |
101 | .public = { | |
102 | .set_key = _set_key12, | |
103 | .get_bytes = _get_bytes12, | |
104 | .destroy = _destroy12, | |
105 | }, | |
106 | .prf = lib->crypto->create_prf(lib->crypto, prf), | |
107 | ); | |
108 | if (!this->prf) | |
109 | { | |
110 | free(this); | |
111 | return NULL; | |
112 | } | |
113 | return &this->public; | |
114 | } | |
115 | ||
116 | ||
117 | typedef struct private_tls_prf10_t private_tls_prf10_t; | |
118 | ||
119 | /** | |
120 | * Private data of an tls_prf_t object. | |
121 | */ | |
122 | struct private_tls_prf10_t { | |
123 | ||
124 | /** | |
125 | * Public tls_prf_t interface. | |
126 | */ | |
127 | tls_prf_t public; | |
128 | ||
129 | /** | |
130 | * Underlying MD5 PRF | |
131 | */ | |
132 | prf_t *md5; | |
133 | ||
134 | /** | |
135 | * Underlying SHA1 PRF | |
136 | */ | |
137 | prf_t *sha1; | |
138 | }; | |
139 | ||
e7d98b8c | 140 | METHOD(tls_prf_t, set_key10, bool, |
149b7e6d MW |
141 | private_tls_prf10_t *this, chunk_t key) |
142 | { | |
143 | size_t len = key.len / 2 + key.len % 2; | |
144 | ||
145 | this->md5->set_key(this->md5, chunk_create(key.ptr, len)); | |
146 | this->sha1->set_key(this->sha1, chunk_create(key.ptr + key.len - len, len)); | |
e7d98b8c | 147 | return TRUE; |
149b7e6d MW |
148 | } |
149 | ||
97b30b93 | 150 | METHOD(tls_prf_t, get_bytes10, bool, |
149b7e6d MW |
151 | private_tls_prf10_t *this, char *label, chunk_t seed, |
152 | size_t bytes, char *out) | |
153 | { | |
154 | char buf[bytes]; | |
155 | ||
97b30b93 MW |
156 | if (!p_hash(this->md5, label, seed, this->md5->get_block_size(this->md5), |
157 | bytes, out) || | |
158 | !p_hash(this->sha1, label, seed, this->sha1->get_block_size(this->sha1), | |
159 | bytes, buf)) | |
160 | { | |
161 | return FALSE; | |
162 | } | |
149b7e6d | 163 | memxor(out, buf, bytes); |
97b30b93 | 164 | return TRUE; |
149b7e6d MW |
165 | } |
166 | ||
167 | METHOD(tls_prf_t, destroy10, void, | |
168 | private_tls_prf10_t *this) | |
169 | { | |
170 | DESTROY_IF(this->md5); | |
171 | DESTROY_IF(this->sha1); | |
172 | free(this); | |
173 | } | |
174 | ||
175 | /** | |
176 | * See header | |
177 | */ | |
178 | tls_prf_t *tls_prf_create_10(pseudo_random_function_t prf) | |
179 | { | |
180 | private_tls_prf10_t *this; | |
181 | ||
182 | INIT(this, | |
183 | .public = { | |
184 | .set_key = _set_key10, | |
185 | .get_bytes = _get_bytes10, | |
186 | .destroy = _destroy10, | |
187 | }, | |
188 | .md5 = lib->crypto->create_prf(lib->crypto, PRF_HMAC_MD5), | |
189 | .sha1 = lib->crypto->create_prf(lib->crypto, PRF_HMAC_SHA1), | |
190 | ); | |
191 | if (!this->md5 || !this->sha1) | |
192 | { | |
193 | destroy10(this); | |
194 | return NULL; | |
195 | } | |
196 | return &this->public; | |
197 | } |