]>
Commit | Line | Data |
---|---|---|
8391c1d0 TB |
1 | /* |
2 | * Copyright (C) 2012 Tobias Brunner | |
1b671669 | 3 | * HSR Hochschule fuer Technik Rapperswil |
8391c1d0 TB |
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 | /* | |
17 | * Copyright (C) 2012 Aleksandr Grinberg | |
18 | * | |
19 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
20 | * of this software and associated documentation files (the "Software"), to deal | |
21 | * in the Software without restriction, including without limitation the rights | |
22 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
23 | * copies of the Software, and to permit persons to whom the Software is | |
24 | * furnished to do so, subject to the following conditions: | |
25 | * | |
26 | * The above copyright notice and this permission notice shall be included in | |
27 | * all copies or substantial portions of the Software. | |
28 | * | |
29 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
30 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
31 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
32 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
33 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
34 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
35 | * THE SOFTWARE. | |
36 | */ | |
37 | ||
a3a190b7 TB |
38 | #include <openssl/opensslconf.h> |
39 | ||
40 | #ifndef OPENSSL_NO_HMAC | |
41 | ||
8391c1d0 TB |
42 | #include <openssl/evp.h> |
43 | #include <openssl/hmac.h> | |
44 | ||
45 | #include "openssl_hmac.h" | |
46 | ||
c4a3c967 TB |
47 | #include <crypto/mac.h> |
48 | #include <crypto/prfs/mac_prf.h> | |
49 | #include <crypto/signers/mac_signer.h> | |
73d032e4 | 50 | |
c4a3c967 | 51 | typedef struct private_mac_t private_mac_t; |
8391c1d0 TB |
52 | |
53 | /** | |
c4a3c967 | 54 | * Private data of a mac_t object. |
8391c1d0 | 55 | */ |
c4a3c967 | 56 | struct private_mac_t { |
8391c1d0 TB |
57 | |
58 | /** | |
59 | * Public interface | |
60 | */ | |
c4a3c967 | 61 | mac_t public; |
8391c1d0 TB |
62 | |
63 | /** | |
64 | * Hasher to use | |
65 | */ | |
66 | const EVP_MD *hasher; | |
67 | ||
68 | /** | |
69 | * Current HMAC context | |
70 | */ | |
97b1a27f TB |
71 | HMAC_CTX *hmac; |
72 | ||
73 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | |
74 | /** | |
75 | * Static context for OpenSSL < 1.1.0 | |
76 | */ | |
77 | HMAC_CTX hmac_ctx; | |
78 | #endif | |
8391c1d0 TB |
79 | }; |
80 | ||
6a440f83 TB |
81 | /** |
82 | * Resets the state with the given key, or only resets the internal state | |
83 | * if key is chunk_empty. | |
84 | */ | |
85 | static bool reset(private_mac_t *this, chunk_t key) | |
8391c1d0 | 86 | { |
082b0d72 | 87 | #if OPENSSL_VERSION_NUMBER >= 0x10000000L |
97b1a27f | 88 | if (HMAC_Init_ex(this->hmac, key.ptr, key.len, this->hasher, NULL)) |
c2906c8f | 89 | { |
c2906c8f MW |
90 | return TRUE; |
91 | } | |
92 | return FALSE; | |
082b0d72 | 93 | #else /* OPENSSL_VERSION_NUMBER < 1.0 */ |
97b1a27f | 94 | HMAC_Init_ex(this->hmac, key.ptr, key.len, this->hasher, NULL); |
082b0d72 MW |
95 | return TRUE; |
96 | #endif | |
8391c1d0 TB |
97 | } |
98 | ||
6a440f83 TB |
99 | METHOD(mac_t, set_key, bool, |
100 | private_mac_t *this, chunk_t key) | |
101 | { | |
102 | if (!key.ptr) | |
64b28172 | 103 | { /* HMAC_Init_ex() won't reset the key if a NULL pointer is passed, |
627eaa22 | 104 | * use a lengthy string in case there is a limit in FIPS-mode */ |
64b28172 | 105 | key = chunk_from_str("00000000000000000000000000000000"); |
6a440f83 TB |
106 | } |
107 | return reset(this, key); | |
108 | } | |
109 | ||
27e1eabb | 110 | METHOD(mac_t, get_mac, bool, |
b12c53ce | 111 | private_mac_t *this, chunk_t data, uint8_t *out) |
8391c1d0 | 112 | { |
082b0d72 | 113 | #if OPENSSL_VERSION_NUMBER >= 0x10000000L |
97b1a27f | 114 | if (!HMAC_Update(this->hmac, data.ptr, data.len)) |
082b0d72 MW |
115 | { |
116 | return FALSE; | |
117 | } | |
8391c1d0 TB |
118 | if (out == NULL) |
119 | { | |
082b0d72 | 120 | return TRUE; |
8391c1d0 | 121 | } |
97b1a27f | 122 | if (!HMAC_Final(this->hmac, out, NULL)) |
082b0d72 MW |
123 | { |
124 | return FALSE; | |
125 | } | |
126 | #else /* OPENSSL_VERSION_NUMBER < 1.0 */ | |
97b1a27f | 127 | HMAC_Update(this->hmac, data.ptr, data.len); |
082b0d72 MW |
128 | if (out == NULL) |
129 | { | |
130 | return TRUE; | |
131 | } | |
97b1a27f | 132 | HMAC_Final(this->hmac, out, NULL); |
082b0d72 | 133 | #endif |
6a440f83 | 134 | return reset(this, chunk_empty); |
8391c1d0 TB |
135 | } |
136 | ||
c4a3c967 TB |
137 | METHOD(mac_t, get_mac_size, size_t, |
138 | private_mac_t *this) | |
8391c1d0 TB |
139 | { |
140 | return EVP_MD_size(this->hasher); | |
141 | } | |
142 | ||
c4a3c967 TB |
143 | METHOD(mac_t, destroy, void, |
144 | private_mac_t *this) | |
8391c1d0 | 145 | { |
97b1a27f TB |
146 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L |
147 | HMAC_CTX_free(this->hmac); | |
148 | #else | |
149 | HMAC_CTX_cleanup(&this->hmac_ctx); | |
150 | #endif | |
8391c1d0 TB |
151 | free(this); |
152 | } | |
153 | ||
154 | /* | |
c4a3c967 | 155 | * Create an OpenSSL-backed implementation of the mac_t interface |
8391c1d0 | 156 | */ |
c4a3c967 | 157 | static mac_t *hmac_create(hash_algorithm_t algo) |
8391c1d0 | 158 | { |
c4a3c967 | 159 | private_mac_t *this; |
610f90a8 MW |
160 | char *name; |
161 | ||
162 | name = enum_to_name(hash_algorithm_short_names, algo); | |
163 | if (!name) | |
164 | { | |
165 | return NULL; | |
166 | } | |
8391c1d0 TB |
167 | |
168 | INIT(this, | |
169 | .public = { | |
170 | .get_mac = _get_mac, | |
73d032e4 | 171 | .get_mac_size = _get_mac_size, |
8391c1d0 TB |
172 | .set_key = _set_key, |
173 | .destroy = _destroy, | |
174 | }, | |
610f90a8 | 175 | .hasher = EVP_get_digestbyname(name), |
8391c1d0 TB |
176 | ); |
177 | ||
8391c1d0 TB |
178 | if (!this->hasher) |
179 | { | |
180 | free(this); | |
181 | return NULL; | |
182 | } | |
183 | ||
97b1a27f TB |
184 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L |
185 | this->hmac = HMAC_CTX_new(); | |
186 | #else | |
187 | HMAC_CTX_init(&this->hmac_ctx); | |
188 | this->hmac = &this->hmac_ctx; | |
189 | #endif | |
8391c1d0 | 190 | |
6b347d52 | 191 | /* make sure the underlying hash algorithm is supported */ |
64b28172 | 192 | if (!set_key(this, chunk_empty)) |
6b347d52 TB |
193 | { |
194 | destroy(this); | |
195 | return NULL; | |
196 | } | |
8391c1d0 TB |
197 | return &this->public; |
198 | } | |
73d032e4 TB |
199 | |
200 | /* | |
201 | * Described in header | |
202 | */ | |
203 | prf_t *openssl_hmac_prf_create(pseudo_random_function_t algo) | |
204 | { | |
c4a3c967 | 205 | mac_t *hmac; |
73d032e4 | 206 | |
228d096e | 207 | hmac = hmac_create(hasher_algorithm_from_prf(algo)); |
73d032e4 TB |
208 | if (hmac) |
209 | { | |
c4a3c967 | 210 | return mac_prf_create(hmac); |
73d032e4 TB |
211 | } |
212 | return NULL; | |
213 | } | |
214 | ||
215 | /* | |
216 | * Described in header | |
217 | */ | |
218 | signer_t *openssl_hmac_signer_create(integrity_algorithm_t algo) | |
219 | { | |
c4a3c967 | 220 | mac_t *hmac; |
228d096e | 221 | size_t trunc; |
73d032e4 | 222 | |
228d096e | 223 | hmac = hmac_create(hasher_algorithm_from_integrity(algo, &trunc)); |
73d032e4 TB |
224 | if (hmac) |
225 | { | |
c4a3c967 | 226 | return mac_signer_create(hmac, trunc); |
73d032e4 TB |
227 | } |
228 | return NULL; | |
229 | } | |
230 | ||
a3a190b7 | 231 | #endif /* OPENSSL_NO_HMAC */ |