1 /* $OpenBSD: hm_pmeth.c,v 1.8 2014/07/11 08:44:48 jsing Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project 2007.
4  */
5 /* ====================================================================
6  * Copyright (c) 2007 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58 
59 #include <stdio.h>
60 #include <string.h>
61 
62 #include <openssl/evp.h>
63 #include <openssl/hmac.h>
64 #include <openssl/x509.h>
65 #include <openssl/x509v3.h>
66 
67 #include "evp_locl.h"
68 
69 /* HMAC pkey context structure */
70 
71 typedef struct {
72 	const EVP_MD *md;	/* MD for HMAC use */
73 	ASN1_OCTET_STRING ktmp; /* Temp storage for key */
74 	HMAC_CTX ctx;
75 } HMAC_PKEY_CTX;
76 
77 static int
78 pkey_hmac_init(EVP_PKEY_CTX *ctx)
79 {
80 	HMAC_PKEY_CTX *hctx;
81 
82 	hctx = malloc(sizeof(HMAC_PKEY_CTX));
83 	if (!hctx)
84 		return 0;
85 	hctx->md = NULL;
86 	hctx->ktmp.data = NULL;
87 	hctx->ktmp.length = 0;
88 	hctx->ktmp.flags = 0;
89 	hctx->ktmp.type = V_ASN1_OCTET_STRING;
90 	HMAC_CTX_init(&hctx->ctx);
91 
92 	ctx->data = hctx;
93 	ctx->keygen_info_count = 0;
94 
95 	return 1;
96 }
97 
98 static int
99 pkey_hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
100 {
101 	HMAC_PKEY_CTX *sctx, *dctx;
102 
103 	if (!pkey_hmac_init(dst))
104 		return 0;
105 	sctx = src->data;
106 	dctx = dst->data;
107 	dctx->md = sctx->md;
108 	HMAC_CTX_init(&dctx->ctx);
109 	if (!HMAC_CTX_copy(&dctx->ctx, &sctx->ctx))
110 		return 0;
111 	if (sctx->ktmp.data) {
112 		if (!ASN1_OCTET_STRING_set(&dctx->ktmp, sctx->ktmp.data,
113 		    sctx->ktmp.length))
114 			return 0;
115 	}
116 	return 1;
117 }
118 
119 static void
120 pkey_hmac_cleanup(EVP_PKEY_CTX *ctx)
121 {
122 	HMAC_PKEY_CTX *hctx = ctx->data;
123 
124 	HMAC_CTX_cleanup(&hctx->ctx);
125 	if (hctx->ktmp.data) {
126 		if (hctx->ktmp.length)
127 			explicit_bzero(hctx->ktmp.data, hctx->ktmp.length);
128 		free(hctx->ktmp.data);
129 		hctx->ktmp.data = NULL;
130 	}
131 	free(hctx);
132 }
133 
134 static int
135 pkey_hmac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
136 {
137 	ASN1_OCTET_STRING *hkey = NULL;
138 	HMAC_PKEY_CTX *hctx = ctx->data;
139 
140 	if (!hctx->ktmp.data)
141 		return 0;
142 	hkey = ASN1_OCTET_STRING_dup(&hctx->ktmp);
143 	if (!hkey)
144 		return 0;
145 	EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, hkey);
146 
147 	return 1;
148 }
149 
150 static int
151 int_update(EVP_MD_CTX *ctx, const void *data, size_t count)
152 {
153 	HMAC_PKEY_CTX *hctx = ctx->pctx->data;
154 
155 	if (!HMAC_Update(&hctx->ctx, data, count))
156 		return 0;
157 	return 1;
158 }
159 
160 static int
161 hmac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
162 {
163 	HMAC_PKEY_CTX *hctx = ctx->data;
164 
165 	HMAC_CTX_set_flags(&hctx->ctx, mctx->flags & ~EVP_MD_CTX_FLAG_NO_INIT);
166 	EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
167 	mctx->update = int_update;
168 	return 1;
169 }
170 
171 static int
172 hmac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
173     EVP_MD_CTX *mctx)
174 {
175 	unsigned int hlen;
176 	HMAC_PKEY_CTX *hctx = ctx->data;
177 	int l = EVP_MD_CTX_size(mctx);
178 
179 	if (l < 0)
180 		return 0;
181 	*siglen = l;
182 	if (!sig)
183 		return 1;
184 
185 	if (!HMAC_Final(&hctx->ctx, sig, &hlen))
186 		return 0;
187 	*siglen = (size_t)hlen;
188 	return 1;
189 }
190 
191 static int
192 pkey_hmac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
193 {
194 	HMAC_PKEY_CTX *hctx = ctx->data;
195 	ASN1_OCTET_STRING *key;
196 
197 	switch (type) {
198 	case EVP_PKEY_CTRL_SET_MAC_KEY:
199 		if ((!p2 && p1 > 0) || (p1 < -1))
200 			return 0;
201 		if (!ASN1_OCTET_STRING_set(&hctx->ktmp, p2, p1))
202 			return 0;
203 		break;
204 
205 	case EVP_PKEY_CTRL_MD:
206 		hctx->md = p2;
207 		break;
208 
209 	case EVP_PKEY_CTRL_DIGESTINIT:
210 		key = (ASN1_OCTET_STRING *)ctx->pkey->pkey.ptr;
211 		if (!HMAC_Init_ex(&hctx->ctx, key->data, key->length, hctx->md,
212 		    ctx->engine))
213 			return 0;
214 		break;
215 
216 	default:
217 		return -2;
218 	}
219 	return 1;
220 }
221 
222 static int
223 pkey_hmac_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value)
224 {
225 	if (!value)
226 		return 0;
227 	if (!strcmp(type, "key")) {
228 		void *p = (void *)value;
229 		return pkey_hmac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, -1, p);
230 	}
231 	if (!strcmp(type, "hexkey")) {
232 		unsigned char *key;
233 		int r;
234 		long keylen;
235 		key = string_to_hex(value, &keylen);
236 		if (!key)
237 			return 0;
238 		r = pkey_hmac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, keylen, key);
239 		free(key);
240 		return r;
241 	}
242 	return -2;
243 }
244 
245 const EVP_PKEY_METHOD hmac_pkey_meth = {
246 	.pkey_id = EVP_PKEY_HMAC,
247 
248 	.init = pkey_hmac_init,
249 	.copy = pkey_hmac_copy,
250 	.cleanup = pkey_hmac_cleanup,
251 
252 	.keygen = pkey_hmac_keygen,
253 
254 	.signctx_init = hmac_signctx_init,
255 	.signctx = hmac_signctx,
256 
257 	.ctrl = pkey_hmac_ctrl,
258 	.ctrl_str = pkey_hmac_ctrl_str
259 };
260