xref: /minix3/external/bsd/bind/dist/lib/isc/hmacmd5.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
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