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