openssl: Ensure underlying hash algorithm is available during HMAC init
[strongswan.git] / src / libstrongswan / plugins / openssl / openssl_hmac.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
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
38 #include <openssl/opensslconf.h>
39
40 #ifndef OPENSSL_NO_HMAC
41
42 #include <openssl/evp.h>
43 #include <openssl/hmac.h>
44
45 #include "openssl_hmac.h"
46
47 #include <crypto/mac.h>
48 #include <crypto/prfs/mac_prf.h>
49 #include <crypto/signers/mac_signer.h>
50
51 typedef struct private_mac_t private_mac_t;
52
53 /**
54 * Private data of a mac_t object.
55 */
56 struct private_mac_t {
57
58 /**
59 * Public interface
60 */
61 mac_t public;
62
63 /**
64 * Hasher to use
65 */
66 const EVP_MD *hasher;
67
68 /**
69 * Current HMAC context
70 */
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
79
80 /**
81 * Key set on HMAC_CTX?
82 */
83 bool key_set;
84 };
85
86 METHOD(mac_t, set_key, bool,
87 private_mac_t *this, chunk_t key)
88 {
89 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
90 if (HMAC_Init_ex(this->hmac, key.ptr, key.len, this->hasher, NULL))
91 {
92 this->key_set = TRUE;
93 return TRUE;
94 }
95 return FALSE;
96 #else /* OPENSSL_VERSION_NUMBER < 1.0 */
97 HMAC_Init_ex(this->hmac, key.ptr, key.len, this->hasher, NULL);
98 this->key_set = TRUE;
99 return TRUE;
100 #endif
101 }
102
103 METHOD(mac_t, get_mac, bool,
104 private_mac_t *this, chunk_t data, uint8_t *out)
105 {
106 if (!this->key_set)
107 {
108 return FALSE;
109 }
110 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
111 if (!HMAC_Update(this->hmac, data.ptr, data.len))
112 {
113 return FALSE;
114 }
115 if (out == NULL)
116 {
117 return TRUE;
118 }
119 if (!HMAC_Final(this->hmac, out, NULL))
120 {
121 return FALSE;
122 }
123 #else /* OPENSSL_VERSION_NUMBER < 1.0 */
124 HMAC_Update(this->hmac, data.ptr, data.len);
125 if (out == NULL)
126 {
127 return TRUE;
128 }
129 HMAC_Final(this->hmac, out, NULL);
130 #endif
131 return set_key(this, chunk_empty);
132 }
133
134 METHOD(mac_t, get_mac_size, size_t,
135 private_mac_t *this)
136 {
137 return EVP_MD_size(this->hasher);
138 }
139
140 METHOD(mac_t, destroy, void,
141 private_mac_t *this)
142 {
143 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
144 HMAC_CTX_free(this->hmac);
145 #else
146 HMAC_CTX_cleanup(&this->hmac_ctx);
147 #endif
148 free(this);
149 }
150
151 /*
152 * Create an OpenSSL-backed implementation of the mac_t interface
153 */
154 static mac_t *hmac_create(hash_algorithm_t algo)
155 {
156 private_mac_t *this;
157 char *name;
158
159 name = enum_to_name(hash_algorithm_short_names, algo);
160 if (!name)
161 {
162 return NULL;
163 }
164
165 INIT(this,
166 .public = {
167 .get_mac = _get_mac,
168 .get_mac_size = _get_mac_size,
169 .set_key = _set_key,
170 .destroy = _destroy,
171 },
172 .hasher = EVP_get_digestbyname(name),
173 );
174
175 if (!this->hasher)
176 {
177 free(this);
178 return NULL;
179 }
180
181 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
182 this->hmac = HMAC_CTX_new();
183 #else
184 HMAC_CTX_init(&this->hmac_ctx);
185 this->hmac = &this->hmac_ctx;
186 #endif
187
188 /* make sure the underlying hash algorithm is supported */
189 if (!set_key(this, chunk_from_str("")))
190 {
191 destroy(this);
192 return NULL;
193 }
194 return &this->public;
195 }
196
197 /*
198 * Described in header
199 */
200 prf_t *openssl_hmac_prf_create(pseudo_random_function_t algo)
201 {
202 mac_t *hmac;
203
204 hmac = hmac_create(hasher_algorithm_from_prf(algo));
205 if (hmac)
206 {
207 return mac_prf_create(hmac);
208 }
209 return NULL;
210 }
211
212 /*
213 * Described in header
214 */
215 signer_t *openssl_hmac_signer_create(integrity_algorithm_t algo)
216 {
217 mac_t *hmac;
218 size_t trunc;
219
220 hmac = hmac_create(hasher_algorithm_from_integrity(algo, &trunc));
221 if (hmac)
222 {
223 return mac_signer_create(hmac, trunc);
224 }
225 return NULL;
226 }
227
228 #endif /* OPENSSL_NO_HMAC */