]>
Commit | Line | Data |
---|---|---|
8391c1d0 TB |
1 | /* |
2 | * Copyright (C) 2012 Tobias Brunner | |
19ef2aec TB |
3 | * |
4 | * Copyright (C) secunet Security Networks AG | |
8391c1d0 TB |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | * for more details. | |
15 | */ | |
16 | ||
17 | /* | |
18 | * Copyright (C) 2012 Aleksandr Grinberg | |
19 | * | |
20 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
21 | * of this software and associated documentation files (the "Software"), to deal | |
22 | * in the Software without restriction, including without limitation the rights | |
23 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
24 | * copies of the Software, and to permit persons to whom the Software is | |
25 | * furnished to do so, subject to the following conditions: | |
26 | * | |
27 | * The above copyright notice and this permission notice shall be included in | |
28 | * all copies or substantial portions of the Software. | |
29 | * | |
30 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
31 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
32 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
33 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
34 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
35 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
36 | * THE SOFTWARE. | |
37 | */ | |
38 | ||
a3a190b7 TB |
39 | #include <openssl/opensslconf.h> |
40 | ||
41 | #ifndef OPENSSL_NO_HMAC | |
42 | ||
8391c1d0 TB |
43 | #include <openssl/evp.h> |
44 | #include <openssl/hmac.h> | |
45 | ||
db0c53c2 TB |
46 | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
47 | #include <openssl/core_names.h> | |
48 | #endif | |
49 | ||
8391c1d0 TB |
50 | #include "openssl_hmac.h" |
51 | ||
c4a3c967 TB |
52 | #include <crypto/mac.h> |
53 | #include <crypto/prfs/mac_prf.h> | |
54 | #include <crypto/signers/mac_signer.h> | |
73d032e4 | 55 | |
c4a3c967 | 56 | typedef struct private_mac_t private_mac_t; |
8391c1d0 TB |
57 | |
58 | /** | |
c4a3c967 | 59 | * Private data of a mac_t object. |
8391c1d0 | 60 | */ |
c4a3c967 | 61 | struct private_mac_t { |
8391c1d0 TB |
62 | |
63 | /** | |
64 | * Public interface | |
65 | */ | |
c4a3c967 | 66 | mac_t public; |
8391c1d0 | 67 | |
db0c53c2 TB |
68 | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
69 | /** | |
70 | * HMAC context | |
71 | */ | |
72 | EVP_MAC_CTX *hmac; | |
73 | ||
74 | /** | |
75 | * Base context because EVP_MAC_init() does not reset the internal state if | |
76 | * no key is passed, so the above is a copy that's replaced with every | |
77 | * reset that does not change the key | |
78 | */ | |
79 | EVP_MAC_CTX *hmac_base; | |
80 | #else | |
8391c1d0 TB |
81 | /** |
82 | * Hasher to use | |
83 | */ | |
84 | const EVP_MD *hasher; | |
85 | ||
86 | /** | |
87 | * Current HMAC context | |
88 | */ | |
97b1a27f | 89 | HMAC_CTX *hmac; |
db0c53c2 | 90 | #endif |
97b1a27f TB |
91 | |
92 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | |
93 | /** | |
94 | * Static context for OpenSSL < 1.1.0 | |
95 | */ | |
96 | HMAC_CTX hmac_ctx; | |
97 | #endif | |
8391c1d0 TB |
98 | }; |
99 | ||
6a440f83 TB |
100 | /** |
101 | * Resets the state with the given key, or only resets the internal state | |
102 | * if key is chunk_empty. | |
103 | */ | |
104 | static bool reset(private_mac_t *this, chunk_t key) | |
8391c1d0 | 105 | { |
db0c53c2 TB |
106 | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
107 | if (!key.len || EVP_MAC_init(this->hmac_base, key.ptr, key.len, NULL)) | |
108 | { | |
109 | EVP_MAC_CTX_free(this->hmac); | |
110 | this->hmac = EVP_MAC_CTX_dup(this->hmac_base); | |
111 | return TRUE; | |
112 | } | |
113 | #else | |
97b1a27f | 114 | if (HMAC_Init_ex(this->hmac, key.ptr, key.len, this->hasher, NULL)) |
c2906c8f | 115 | { |
c2906c8f MW |
116 | return TRUE; |
117 | } | |
082b0d72 | 118 | #endif |
db0c53c2 | 119 | return FALSE; |
8391c1d0 TB |
120 | } |
121 | ||
6a440f83 TB |
122 | METHOD(mac_t, set_key, bool, |
123 | private_mac_t *this, chunk_t key) | |
124 | { | |
125 | if (!key.ptr) | |
64b28172 | 126 | { /* HMAC_Init_ex() won't reset the key if a NULL pointer is passed, |
627eaa22 | 127 | * use a lengthy string in case there is a limit in FIPS-mode */ |
64b28172 | 128 | key = chunk_from_str("00000000000000000000000000000000"); |
6a440f83 | 129 | } |
db0c53c2 TB |
130 | if (!reset(this, key)) |
131 | { | |
132 | return FALSE; | |
133 | } | |
134 | return TRUE; | |
135 | } | |
136 | ||
137 | METHOD(mac_t, get_mac_size, size_t, | |
138 | private_mac_t *this) | |
139 | { | |
140 | #if OPENSSL_VERSION_NUMBER >= 0x30000000L | |
141 | return EVP_MAC_CTX_get_mac_size(this->hmac); | |
142 | #else | |
143 | return EVP_MD_size(this->hasher); | |
144 | #endif | |
6a440f83 TB |
145 | } |
146 | ||
27e1eabb | 147 | METHOD(mac_t, get_mac, bool, |
b12c53ce | 148 | private_mac_t *this, chunk_t data, uint8_t *out) |
8391c1d0 | 149 | { |
db0c53c2 TB |
150 | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
151 | if (!EVP_MAC_update(this->hmac, data.ptr, data.len)) | |
152 | { | |
153 | return FALSE; | |
154 | } | |
155 | #else | |
97b1a27f | 156 | if (!HMAC_Update(this->hmac, data.ptr, data.len)) |
082b0d72 MW |
157 | { |
158 | return FALSE; | |
159 | } | |
db0c53c2 TB |
160 | #endif |
161 | if (!out) | |
8391c1d0 | 162 | { |
082b0d72 | 163 | return TRUE; |
8391c1d0 | 164 | } |
db0c53c2 TB |
165 | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
166 | if (!EVP_MAC_final(this->hmac, out, NULL, get_mac_size(this))) | |
082b0d72 MW |
167 | { |
168 | return FALSE; | |
169 | } | |
db0c53c2 TB |
170 | #else |
171 | if (!HMAC_Final(this->hmac, out, NULL)) | |
082b0d72 | 172 | { |
db0c53c2 | 173 | return FALSE; |
082b0d72 | 174 | } |
082b0d72 | 175 | #endif |
6a440f83 | 176 | return reset(this, chunk_empty); |
8391c1d0 TB |
177 | } |
178 | ||
c4a3c967 TB |
179 | METHOD(mac_t, destroy, void, |
180 | private_mac_t *this) | |
8391c1d0 | 181 | { |
db0c53c2 TB |
182 | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
183 | EVP_MAC_CTX_free(this->hmac_base); | |
184 | EVP_MAC_CTX_free(this->hmac); | |
185 | #elif OPENSSL_VERSION_NUMBER >= 0x10100000L | |
97b1a27f TB |
186 | HMAC_CTX_free(this->hmac); |
187 | #else | |
188 | HMAC_CTX_cleanup(&this->hmac_ctx); | |
189 | #endif | |
8391c1d0 TB |
190 | free(this); |
191 | } | |
192 | ||
193 | /* | |
c4a3c967 | 194 | * Create an OpenSSL-backed implementation of the mac_t interface |
8391c1d0 | 195 | */ |
c4a3c967 | 196 | static mac_t *hmac_create(hash_algorithm_t algo) |
8391c1d0 | 197 | { |
c4a3c967 | 198 | private_mac_t *this; |
610f90a8 MW |
199 | char *name; |
200 | ||
201 | name = enum_to_name(hash_algorithm_short_names, algo); | |
202 | if (!name) | |
203 | { | |
204 | return NULL; | |
205 | } | |
8391c1d0 TB |
206 | |
207 | INIT(this, | |
208 | .public = { | |
209 | .get_mac = _get_mac, | |
73d032e4 | 210 | .get_mac_size = _get_mac_size, |
8391c1d0 TB |
211 | .set_key = _set_key, |
212 | .destroy = _destroy, | |
213 | }, | |
214 | ); | |
215 | ||
db0c53c2 TB |
216 | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
217 | OSSL_PARAM params[] = { | |
218 | OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, name, 0), | |
219 | OSSL_PARAM_END, | |
220 | }; | |
221 | EVP_MAC *mac = EVP_MAC_fetch(NULL, "HMAC", NULL); | |
222 | ||
223 | if (!mac) | |
224 | { | |
225 | free(this); | |
226 | return NULL; | |
227 | } | |
228 | this->hmac_base = EVP_MAC_CTX_new(mac); | |
229 | EVP_MAC_free(mac); | |
230 | if (!this->hmac_base || !EVP_MAC_CTX_set_params(this->hmac_base, params)) | |
231 | { | |
232 | free(this); | |
233 | return NULL; | |
234 | } | |
235 | #else /* OPENSSL_VERSION_NUMBER */ | |
236 | this->hasher = EVP_get_digestbyname(name); | |
8391c1d0 TB |
237 | if (!this->hasher) |
238 | { | |
239 | free(this); | |
240 | return NULL; | |
241 | } | |
97b1a27f TB |
242 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L |
243 | this->hmac = HMAC_CTX_new(); | |
244 | #else | |
245 | HMAC_CTX_init(&this->hmac_ctx); | |
246 | this->hmac = &this->hmac_ctx; | |
247 | #endif | |
db0c53c2 | 248 | #endif /* OPENSSL_VERSION_NUMBER */ |
8391c1d0 | 249 | |
6b347d52 | 250 | /* make sure the underlying hash algorithm is supported */ |
64b28172 | 251 | if (!set_key(this, chunk_empty)) |
6b347d52 TB |
252 | { |
253 | destroy(this); | |
254 | return NULL; | |
255 | } | |
8391c1d0 TB |
256 | return &this->public; |
257 | } | |
73d032e4 TB |
258 | |
259 | /* | |
260 | * Described in header | |
261 | */ | |
262 | prf_t *openssl_hmac_prf_create(pseudo_random_function_t algo) | |
263 | { | |
c4a3c967 | 264 | mac_t *hmac; |
73d032e4 | 265 | |
228d096e | 266 | hmac = hmac_create(hasher_algorithm_from_prf(algo)); |
73d032e4 TB |
267 | if (hmac) |
268 | { | |
c4a3c967 | 269 | return mac_prf_create(hmac); |
73d032e4 TB |
270 | } |
271 | return NULL; | |
272 | } | |
273 | ||
274 | /* | |
275 | * Described in header | |
276 | */ | |
277 | signer_t *openssl_hmac_signer_create(integrity_algorithm_t algo) | |
278 | { | |
c4a3c967 | 279 | mac_t *hmac; |
228d096e | 280 | size_t trunc; |
73d032e4 | 281 | |
228d096e | 282 | hmac = hmac_create(hasher_algorithm_from_integrity(algo, &trunc)); |
73d032e4 TB |
283 | if (hmac) |
284 | { | |
c4a3c967 | 285 | return mac_signer_create(hmac, trunc); |
73d032e4 TB |
286 | } |
287 | return NULL; | |
288 | } | |
289 | ||
a3a190b7 | 290 | #endif /* OPENSSL_NO_HMAC */ |