1 /* $NetBSD: hmacmd5.c,v 1.8 2015/07/08 17:28:59 christos Exp $ */
2
3 /*
4 * Copyright (C) 2004-2007, 2009, 2013, 2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001 Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /* Id: hmacmd5.c,v 1.16 2009/02/06 23:47:42 tbox Exp */
21
22 /*! \file
23 * This code implements the HMAC-MD5 keyed hash algorithm
24 * described in RFC2104.
25 */
26
27 #include "config.h"
28
29 #include <isc/assertions.h>
30 #include <isc/hmacmd5.h>
31 #include <isc/md5.h>
32 #include <isc/platform.h>
33 #include <isc/safe.h>
34 #include <isc/string.h>
35 #include <isc/types.h>
36 #include <isc/util.h>
37
38 #if PKCS11CRYPTO || PKCS11CRYPTOWITHHMAC
39 #include <pk11/internal.h>
40 #include <pk11/pk11.h>
41 #endif
42
43 #ifdef ISC_PLATFORM_OPENSSLHASH
44
45 void
isc_hmacmd5_init(isc_hmacmd5_t * ctx,const unsigned char * key,unsigned int len)46 isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
47 unsigned int len)
48 {
49 #ifdef HMAC_RETURN_INT
50 RUNTIME_CHECK(HMAC_Init(ctx, (const void *) key,
51 (int) len, EVP_md5()) == 1);
52 #else
53 HMAC_Init(ctx, (const void *) key, (int) len, EVP_md5());
54 #endif
55 }
56
57 void
isc_hmacmd5_invalidate(isc_hmacmd5_t * ctx)58 isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
59 HMAC_CTX_cleanup(ctx);
60 }
61
62 void
isc_hmacmd5_update(isc_hmacmd5_t * ctx,const unsigned char * buf,unsigned int len)63 isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
64 unsigned int len)
65 {
66 #ifdef HMAC_RETURN_INT
67 RUNTIME_CHECK(HMAC_Update(ctx, buf, (int) len) == 1);
68 #else
69 HMAC_Update(ctx, buf, (int) len);
70 #endif
71 }
72
73 void
isc_hmacmd5_sign(isc_hmacmd5_t * ctx,unsigned char * digest)74 isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
75 #ifdef HMAC_RETURN_INT
76 RUNTIME_CHECK(HMAC_Final(ctx, digest, NULL) == 1);
77 #else
78 HMAC_Final(ctx, digest, NULL);
79 #endif
80 HMAC_CTX_cleanup(ctx);
81 }
82
83 #elif PKCS11CRYPTOWITHHMAC
84
85 static CK_BBOOL truevalue = TRUE;
86 static CK_BBOOL falsevalue = FALSE;
87
88 void
isc_hmacmd5_init(isc_hmacmd5_t * ctx,const unsigned char * key,unsigned int len)89 isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
90 unsigned int len)
91 {
92 CK_RV rv;
93 CK_MECHANISM mech = { CKM_MD5_HMAC, NULL, 0 };
94 CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
95 CK_KEY_TYPE keyType = CKK_MD5_HMAC;
96 CK_ATTRIBUTE keyTemplate[] =
97 {
98 { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
99 { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
100 { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
101 { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
102 { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
103 { CKA_VALUE, NULL, (CK_ULONG) len }
104 };
105
106 DE_CONST(key, keyTemplate[5].pValue);
107 RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
108 ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
109 ctx->object = CK_INVALID_HANDLE;
110 PK11_FATALCHECK(pkcs_C_CreateObject,
111 (ctx->session, keyTemplate,
112 (CK_ULONG) 6, &ctx->object));
113 INSIST(ctx->object != CK_INVALID_HANDLE);
114 PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
115 }
116
117 void
isc_hmacmd5_invalidate(isc_hmacmd5_t * ctx)118 isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
119 CK_BYTE garbage[ISC_MD5_DIGESTLENGTH];
120 CK_ULONG len = ISC_MD5_DIGESTLENGTH;
121
122 if (ctx->handle == NULL)
123 return;
124 (void) pkcs_C_SignFinal(ctx->session, garbage, &len);
125 memset(garbage, 0, sizeof(garbage));
126 if (ctx->object != CK_INVALID_HANDLE)
127 (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
128 ctx->object = CK_INVALID_HANDLE;
129 pk11_return_session(ctx);
130 }
131
132 void
isc_hmacmd5_update(isc_hmacmd5_t * ctx,const unsigned char * buf,unsigned int len)133 isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
134 unsigned int len)
135 {
136 CK_RV rv;
137 CK_BYTE_PTR pPart;
138
139 DE_CONST(buf, pPart);
140 PK11_FATALCHECK(pkcs_C_SignUpdate,
141 (ctx->session, pPart, (CK_ULONG) len));
142 }
143
144 void
isc_hmacmd5_sign(isc_hmacmd5_t * ctx,unsigned char * digest)145 isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
146 CK_RV rv;
147 CK_ULONG len = ISC_MD5_DIGESTLENGTH;
148
149 PK11_FATALCHECK(pkcs_C_SignFinal,
150 (ctx->session, (CK_BYTE_PTR) digest, &len));
151 if (ctx->object != CK_INVALID_HANDLE)
152 (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
153 ctx->object = CK_INVALID_HANDLE;
154 pk11_return_session(ctx);
155 }
156
157 #elif PKCS11CRYPTO
158
159 #define PADLEN 64
160 #define IPAD 0x36
161 #define OPAD 0x5C
162
163 void
isc_hmacmd5_init(isc_hmacmd5_t * ctx,const unsigned char * key,unsigned int len)164 isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
165 unsigned int len)
166 {
167 CK_RV rv;
168 CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
169 unsigned char ipad[PADLEN];
170 unsigned int i;
171
172 RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
173 ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
174 RUNTIME_CHECK((ctx->key = pk11_mem_get(PADLEN)) != NULL);
175 if (len > PADLEN) {
176 CK_BYTE_PTR kPart;
177 CK_ULONG kl;
178
179 PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
180 DE_CONST(key, kPart);
181 PK11_FATALCHECK(pkcs_C_DigestUpdate,
182 (ctx->session, kPart, (CK_ULONG) len));
183 kl = ISC_MD5_DIGESTLENGTH;
184 PK11_FATALCHECK(pkcs_C_DigestFinal,
185 (ctx->session, (CK_BYTE_PTR) ctx->key, &kl));
186 } else
187 memmove(ctx->key, key, len);
188 PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
189 memset(ipad, IPAD, PADLEN);
190 for (i = 0; i < PADLEN; i++)
191 ipad[i] ^= ctx->key[i];
192 PK11_FATALCHECK(pkcs_C_DigestUpdate,
193 (ctx->session, ipad, (CK_ULONG) PADLEN));
194 }
195
196 void
isc_hmacmd5_invalidate(isc_hmacmd5_t * ctx)197 isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
198 if (ctx->key != NULL)
199 pk11_mem_put(ctx->key, PADLEN);
200 ctx->key = NULL;
201 isc_md5_invalidate(ctx);
202 }
203
204 void
isc_hmacmd5_update(isc_hmacmd5_t * ctx,const unsigned char * buf,unsigned int len)205 isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
206 unsigned int len)
207 {
208 CK_RV rv;
209 CK_BYTE_PTR pPart;
210
211 DE_CONST(buf, pPart);
212 PK11_FATALCHECK(pkcs_C_DigestUpdate,
213 (ctx->session, pPart, (CK_ULONG) len));
214 }
215
216 void
isc_hmacmd5_sign(isc_hmacmd5_t * ctx,unsigned char * digest)217 isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
218 CK_RV rv;
219 CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
220 CK_ULONG len = ISC_MD5_DIGESTLENGTH;
221 CK_BYTE opad[PADLEN];
222 unsigned int i;
223
224 PK11_FATALCHECK(pkcs_C_DigestFinal,
225 (ctx->session, (CK_BYTE_PTR) digest,
226 (CK_ULONG_PTR) &len));
227 memset(opad, OPAD, PADLEN);
228 for (i = 0; i < PADLEN; i++)
229 opad[i] ^= ctx->key[i];
230 pk11_mem_put(ctx->key, PADLEN);
231 ctx->key = NULL;
232 PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
233 PK11_FATALCHECK(pkcs_C_DigestUpdate,
234 (ctx->session, opad, (CK_ULONG) PADLEN));
235 PK11_FATALCHECK(pkcs_C_DigestUpdate,
236 (ctx->session, (CK_BYTE_PTR) digest, len));
237 PK11_FATALCHECK(pkcs_C_DigestFinal,
238 (ctx->session,
239 (CK_BYTE_PTR) digest,
240 (CK_ULONG_PTR) &len));
241 pk11_return_session(ctx);
242 }
243
244 #else
245
246 #define PADLEN 64
247 #define IPAD 0x36
248 #define OPAD 0x5C
249
250 /*!
251 * Start HMAC-MD5 process. Initialize an md5 context and digest the key.
252 */
253 void
isc_hmacmd5_init(isc_hmacmd5_t * ctx,const unsigned char * key,unsigned int len)254 isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
255 unsigned int len)
256 {
257 unsigned char ipad[PADLEN];
258 int i;
259
260 memset(ctx->key, 0, sizeof(ctx->key));
261 if (len > sizeof(ctx->key)) {
262 isc_md5_t md5ctx;
263 isc_md5_init(&md5ctx);
264 isc_md5_update(&md5ctx, key, len);
265 isc_md5_final(&md5ctx, ctx->key);
266 } else
267 memmove(ctx->key, key, len);
268
269 isc_md5_init(&ctx->md5ctx);
270 memset(ipad, IPAD, sizeof(ipad));
271 for (i = 0; i < PADLEN; i++)
272 ipad[i] ^= ctx->key[i];
273 isc_md5_update(&ctx->md5ctx, ipad, sizeof(ipad));
274 }
275
276 void
isc_hmacmd5_invalidate(isc_hmacmd5_t * ctx)277 isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
278 isc_md5_invalidate(&ctx->md5ctx);
279 memset(ctx->key, 0, sizeof(ctx->key));
280 }
281
282 /*!
283 * Update context to reflect the concatenation of another buffer full
284 * of bytes.
285 */
286 void
isc_hmacmd5_update(isc_hmacmd5_t * ctx,const unsigned char * buf,unsigned int len)287 isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
288 unsigned int len)
289 {
290 isc_md5_update(&ctx->md5ctx, buf, len);
291 }
292
293 /*!
294 * Compute signature - finalize MD5 operation and reapply MD5.
295 */
296 void
isc_hmacmd5_sign(isc_hmacmd5_t * ctx,unsigned char * digest)297 isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
298 unsigned char opad[PADLEN];
299 int i;
300
301 isc_md5_final(&ctx->md5ctx, digest);
302
303 memset(opad, OPAD, sizeof(opad));
304 for (i = 0; i < PADLEN; i++)
305 opad[i] ^= ctx->key[i];
306
307 isc_md5_init(&ctx->md5ctx);
308 isc_md5_update(&ctx->md5ctx, opad, sizeof(opad));
309 isc_md5_update(&ctx->md5ctx, digest, ISC_MD5_DIGESTLENGTH);
310 isc_md5_final(&ctx->md5ctx, digest);
311 isc_hmacmd5_invalidate(ctx);
312 }
313
314 #endif /* !ISC_PLATFORM_OPENSSLHASH */
315
316 /*!
317 * Verify signature - finalize MD5 operation and reapply MD5, then
318 * compare to the supplied digest.
319 */
320 isc_boolean_t
isc_hmacmd5_verify(isc_hmacmd5_t * ctx,unsigned char * digest)321 isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest) {
322 return (isc_hmacmd5_verify2(ctx, digest, ISC_MD5_DIGESTLENGTH));
323 }
324
325 isc_boolean_t
isc_hmacmd5_verify2(isc_hmacmd5_t * ctx,unsigned char * digest,size_t len)326 isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len) {
327 unsigned char newdigest[ISC_MD5_DIGESTLENGTH];
328
329 REQUIRE(len <= ISC_MD5_DIGESTLENGTH);
330 isc_hmacmd5_sign(ctx, newdigest);
331 return (isc_safe_memcmp(digest, newdigest, len));
332 }
333