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