Branch data Line data Source code
1 : : /*
2 : : *****************************************************************************
3 : : *
4 : : * File: fko_hmac.c
5 : : *
6 : : * Purpose: Provide HMAC support to SPA communications
7 : : *
8 : : * Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
9 : : * Copyright (C) 2009-2014 fwknop developers and contributors. For a full
10 : : * list of contributors, see the file 'CREDITS'.
11 : : *
12 : : * License (GNU General Public License):
13 : : *
14 : : * This program is free software; you can redistribute it and/or
15 : : * modify it under the terms of the GNU General Public License
16 : : * as published by the Free Software Foundation; either version 2
17 : : * of the License, or (at your option) any later version.
18 : : *
19 : : * This program is distributed in the hope that it will be useful,
20 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 : : * GNU General Public License for more details.
23 : : *
24 : : * You should have received a copy of the GNU General Public License
25 : : * along with this program; if not, write to the Free Software
26 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 : : * USA
28 : : *
29 : : *****************************************************************************
30 : : */
31 : : #include "fko_common.h"
32 : : #include "fko.h"
33 : : #include "cipher_funcs.h"
34 : : #include "hmac.h"
35 : : #include "base64.h"
36 : :
37 : : int
38 : 343 : fko_verify_hmac(fko_ctx_t ctx,
39 : : const char * const hmac_key, const int hmac_key_len)
40 : : {
41 : 343 : char *hmac_digest_from_data = NULL;
42 : 343 : char *tbuf = NULL;
43 : 343 : int res = FKO_SUCCESS;
44 : 343 : int hmac_b64_digest_len = 0, zero_free_rv = FKO_SUCCESS;
45 : :
46 : : /* Must be initialized
47 : : */
48 [ + - ][ + - ]: 343 : if(!CTX_INITIALIZED(ctx))
49 : : return(FKO_ERROR_CTX_NOT_INITIALIZED);
50 : :
51 [ + - ]: 343 : if(hmac_key == NULL)
52 : : return(FKO_ERROR_INVALID_DATA);
53 : :
54 [ + - ]: 343 : if (! is_valid_encoded_msg_len(ctx->encrypted_msg_len))
55 : : return(FKO_ERROR_INVALID_DATA_HMAC_MSGLEN_VALIDFAIL);
56 : :
57 [ + - ]: 343 : if(hmac_key_len < 0 || hmac_key_len > MAX_DIGEST_BLOCK_LEN)
58 : : return(FKO_ERROR_INVALID_HMAC_KEY_LEN);
59 : :
60 [ + - ]: 343 : if(ctx->hmac_type == FKO_HMAC_MD5)
61 : : hmac_b64_digest_len = MD5_B64_LEN;
62 [ + + ]: 343 : else if(ctx->hmac_type == FKO_HMAC_SHA1)
63 : : hmac_b64_digest_len = SHA1_B64_LEN;
64 [ - + ]: 270 : else if(ctx->hmac_type == FKO_HMAC_SHA256)
65 : : hmac_b64_digest_len = SHA256_B64_LEN;
66 [ # # ]: 0 : else if(ctx->hmac_type == FKO_HMAC_SHA384)
67 : : hmac_b64_digest_len = SHA384_B64_LEN;
68 [ # # ]: 0 : else if(ctx->hmac_type == FKO_HMAC_SHA512)
69 : : hmac_b64_digest_len = SHA512_B64_LEN;
70 : : else
71 : : return(FKO_ERROR_UNSUPPORTED_HMAC_MODE);
72 : :
73 [ + - ]: 343 : if((ctx->encrypted_msg_len - hmac_b64_digest_len)
74 : : < MIN_SPA_ENCODED_MSG_SIZE)
75 : : return(FKO_ERROR_INVALID_DATA_HMAC_ENCMSGLEN_VALIDFAIL);
76 : :
77 : : /* Get digest value
78 : : */
79 : 686 : hmac_digest_from_data = strndup((ctx->encrypted_msg
80 : 343 : + ctx->encrypted_msg_len - hmac_b64_digest_len),
81 : : hmac_b64_digest_len);
82 : :
83 [ + - ]: 343 : if(hmac_digest_from_data == NULL)
84 : : return(FKO_ERROR_MEMORY_ALLOCATION);
85 : :
86 : : /* Now we chop the HMAC digest off of the encrypted msg
87 : : */
88 : 343 : tbuf = strndup(ctx->encrypted_msg,
89 : : ctx->encrypted_msg_len - hmac_b64_digest_len);
90 : :
91 [ - + ]: 343 : if(tbuf == NULL)
92 : : {
93 [ # # ]: 0 : if(zero_free(hmac_digest_from_data, strnlen(hmac_digest_from_data,
94 : : MAX_SPA_ENCODED_MSG_SIZE)) == FKO_SUCCESS)
95 : : return(FKO_ERROR_MEMORY_ALLOCATION);
96 : : else
97 : 0 : return(FKO_ERROR_ZERO_OUT_DATA);
98 : : }
99 : :
100 [ - + ]: 343 : if(zero_free(ctx->encrypted_msg, ctx->encrypted_msg_len) != FKO_SUCCESS)
101 : 0 : zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;
102 : :
103 : 343 : ctx->encrypted_msg = tbuf;
104 : 343 : ctx->encrypted_msg_len -= hmac_b64_digest_len;
105 : :
106 [ - + ]: 343 : if(ctx->encryption_mode == FKO_ENC_MODE_ASYMMETRIC)
107 : : {
108 : : /* See if we need to add the "hQ" string to the front of the
109 : : * encrypted data.
110 : : */
111 [ # # ]: 0 : if(! ctx->added_gpg_prefix)
112 : : {
113 : 0 : res = add_gpg_prefix(ctx);
114 : : }
115 : : }
116 : : else
117 : : {
118 : : /* See if we need to add the "Salted__" string to the front of the
119 : : * encrypted data.
120 : : */
121 [ + - ]: 343 : if(! ctx->added_salted_str)
122 : : {
123 : 343 : res = add_salted_str(ctx);
124 : : }
125 : : }
126 : :
127 [ - + ]: 343 : if (res != FKO_SUCCESS)
128 : : {
129 [ # # ]: 0 : if(zero_free(hmac_digest_from_data, strnlen(hmac_digest_from_data,
130 : : MAX_SPA_ENCODED_MSG_SIZE)) != FKO_SUCCESS)
131 : 0 : zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;
132 : :
133 [ # # ]: 0 : if(zero_free_rv == FKO_SUCCESS)
134 : : return(res);
135 : : else
136 : 0 : return(zero_free_rv);
137 : : }
138 : :
139 : : /* Calculate the HMAC from the encrypted data and then
140 : : * compare
141 : : */
142 : 343 : res = fko_set_spa_hmac_type(ctx, ctx->hmac_type);
143 [ + - ]: 343 : if(res == FKO_SUCCESS)
144 : : {
145 : 343 : res = fko_set_spa_hmac(ctx, hmac_key, hmac_key_len);
146 : :
147 [ + - ]: 343 : if(res == FKO_SUCCESS)
148 : : {
149 [ + - ]: 343 : if(constant_runtime_cmp(hmac_digest_from_data,
150 : 343 : ctx->msg_hmac, hmac_b64_digest_len) != 0)
151 : : {
152 : 343 : res = FKO_ERROR_INVALID_DATA_HMAC_COMPAREFAIL;
153 : : }
154 : : }
155 : : }
156 : :
157 [ - + ]: 343 : if(zero_free(hmac_digest_from_data, strnlen(hmac_digest_from_data,
158 : : MAX_SPA_ENCODED_MSG_SIZE)) != FKO_SUCCESS)
159 : 0 : zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;
160 : :
161 [ + - ]: 343 : if(res == FKO_SUCCESS)
162 : : return(zero_free_rv);
163 : : else
164 : 343 : return(res);
165 : : }
166 : :
167 : : /* Return the fko HMAC data
168 : : */
169 : : int
170 : 449 : fko_get_spa_hmac(fko_ctx_t ctx, char **hmac_data)
171 : : {
172 : : /* Must be initialized
173 : : */
174 [ + - ][ + - ]: 449 : if(!CTX_INITIALIZED(ctx))
175 : : return(FKO_ERROR_CTX_NOT_INITIALIZED);
176 : :
177 [ + - ]: 449 : if(hmac_data == NULL)
178 : : return(FKO_ERROR_INVALID_DATA);
179 : :
180 : 449 : *hmac_data = ctx->msg_hmac;
181 : :
182 : 449 : return(FKO_SUCCESS);
183 : : }
184 : :
185 : : /* Set the HMAC type
186 : : */
187 : : int
188 : 1111 : fko_set_spa_hmac_type(fko_ctx_t ctx, const short hmac_type)
189 : : {
190 : : #if HAVE_LIBFIU
191 : : fiu_return_on("fko_set_spa_hmac_type_init",
192 : : FKO_ERROR_CTX_NOT_INITIALIZED);
193 : : #endif
194 : :
195 : : /* Must be initialized
196 : : */
197 [ + - ][ + - ]: 1111 : if(!CTX_INITIALIZED(ctx))
198 : : return(FKO_ERROR_CTX_NOT_INITIALIZED);
199 : :
200 : : #if HAVE_LIBFIU
201 : : fiu_return_on("fko_set_spa_hmac_type_val",
202 : : FKO_ERROR_INVALID_DATA_HMAC_TYPE_VALIDFAIL);
203 : : #endif
204 : :
205 [ + - ]: 1111 : if(hmac_type < 0 || hmac_type >= FKO_LAST_HMAC_MODE)
206 : : return(FKO_ERROR_INVALID_DATA_HMAC_TYPE_VALIDFAIL);
207 : :
208 : 1111 : ctx->hmac_type = hmac_type;
209 : :
210 : 1111 : ctx->state |= FKO_HMAC_MODE_MODIFIED;
211 : :
212 : 1111 : return(FKO_SUCCESS);
213 : : }
214 : :
215 : : /* Return the fko HMAC type
216 : : */
217 : : int
218 : 449 : fko_get_spa_hmac_type(fko_ctx_t ctx, short *hmac_type)
219 : : {
220 : : /* Must be initialized
221 : : */
222 [ + - ][ + - ]: 449 : if(!CTX_INITIALIZED(ctx))
223 : : return(FKO_ERROR_CTX_NOT_INITIALIZED);
224 : :
225 [ + - ]: 449 : if(hmac_type == NULL)
226 : : return(FKO_ERROR_INVALID_DATA);
227 : :
228 : 449 : *hmac_type = ctx->hmac_type;
229 : :
230 : 449 : return(FKO_SUCCESS);
231 : : }
232 : :
233 : 686 : int fko_set_spa_hmac(fko_ctx_t ctx,
234 : : const char * const hmac_key, const int hmac_key_len)
235 : : {
236 : 686 : unsigned char hmac[SHA512_DIGEST_STR_LEN] = {0};
237 : 686 : char *hmac_base64 = NULL;
238 : 686 : int hmac_digest_str_len = 0;
239 : 686 : int hmac_digest_len = 0;
240 : :
241 : : /* Must be initialized
242 : : */
243 [ + - ][ + - ]: 686 : if(!CTX_INITIALIZED(ctx))
244 : : return(FKO_ERROR_CTX_NOT_INITIALIZED);
245 : :
246 [ + - ]: 686 : if(hmac_key == NULL)
247 : : return(FKO_ERROR_INVALID_DATA);
248 : :
249 [ + - ]: 686 : if(hmac_key_len < 0 || hmac_key_len > MAX_DIGEST_BLOCK_LEN)
250 : : return(FKO_ERROR_INVALID_HMAC_KEY_LEN);
251 : :
252 [ - + ]: 686 : if(ctx->hmac_type == FKO_HMAC_MD5)
253 : : {
254 : 0 : hmac_md5(ctx->encrypted_msg,
255 : 0 : ctx->encrypted_msg_len, hmac, hmac_key, hmac_key_len);
256 : :
257 : 0 : hmac_digest_len = MD5_DIGEST_LEN;
258 : 0 : hmac_digest_str_len = MD5_DIGEST_STR_LEN;
259 : : }
260 [ + + ]: 686 : else if(ctx->hmac_type == FKO_HMAC_SHA1)
261 : : {
262 : 146 : hmac_sha1(ctx->encrypted_msg,
263 : 146 : ctx->encrypted_msg_len, hmac, hmac_key, hmac_key_len);
264 : :
265 : 146 : hmac_digest_len = SHA1_DIGEST_LEN;
266 : 146 : hmac_digest_str_len = SHA1_DIGEST_STR_LEN;
267 : : }
268 [ + - ]: 540 : else if(ctx->hmac_type == FKO_HMAC_SHA256)
269 : : {
270 : 540 : hmac_sha256(ctx->encrypted_msg,
271 : 540 : ctx->encrypted_msg_len, hmac, hmac_key, hmac_key_len);
272 : :
273 : 540 : hmac_digest_len = SHA256_DIGEST_LEN;
274 : 540 : hmac_digest_str_len = SHA256_DIGEST_STR_LEN;
275 : : }
276 [ # # ]: 0 : else if(ctx->hmac_type == FKO_HMAC_SHA384)
277 : : {
278 : 0 : hmac_sha384(ctx->encrypted_msg,
279 : 0 : ctx->encrypted_msg_len, hmac, hmac_key, hmac_key_len);
280 : :
281 : 0 : hmac_digest_len = SHA384_DIGEST_LEN;
282 : 0 : hmac_digest_str_len = SHA384_DIGEST_STR_LEN;
283 : : }
284 [ # # ]: 0 : else if(ctx->hmac_type == FKO_HMAC_SHA512)
285 : : {
286 : 0 : hmac_sha512(ctx->encrypted_msg,
287 : 0 : ctx->encrypted_msg_len, hmac, hmac_key, hmac_key_len);
288 : :
289 : 0 : hmac_digest_len = SHA512_DIGEST_LEN;
290 : 0 : hmac_digest_str_len = SHA512_DIGEST_STR_LEN;
291 : : }
292 : :
293 : 686 : hmac_base64 = calloc(1, MD_HEX_SIZE(hmac_digest_len)+1);
294 [ + - ]: 686 : if (hmac_base64 == NULL)
295 : : return(FKO_ERROR_MEMORY_ALLOCATION);
296 : :
297 : 686 : b64_encode(hmac, hmac_base64, hmac_digest_len);
298 : 686 : strip_b64_eq(hmac_base64);
299 : :
300 [ - + ]: 686 : if(ctx->msg_hmac != NULL)
301 : 0 : free(ctx->msg_hmac);
302 : :
303 : 686 : ctx->msg_hmac = strdup(hmac_base64);
304 : :
305 : 686 : free(hmac_base64);
306 : :
307 [ + - ]: 686 : if(ctx->msg_hmac == NULL)
308 : : return(FKO_ERROR_MEMORY_ALLOCATION);
309 : :
310 : 686 : ctx->msg_hmac_len = strnlen(ctx->msg_hmac, hmac_digest_str_len);
311 : :
312 [ + - ]: 686 : switch(ctx->msg_hmac_len)
313 : : {
314 : : case MD5_B64_LEN:
315 : : break;
316 : : case SHA1_B64_LEN:
317 : : break;
318 : : case SHA256_B64_LEN:
319 : : break;
320 : : case SHA384_B64_LEN:
321 : : break;
322 : : case SHA512_B64_LEN:
323 : : break;
324 : : default:
325 : : return(FKO_ERROR_INVALID_DATA_HMAC_LEN_VALIDFAIL);
326 : : }
327 : :
328 : 686 : return FKO_SUCCESS;
329 : : }
330 : :
331 : : /***EOF***/
|