1 /*
2  * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <string.h>
11 #include <openssl/core_dispatch.h>
12 #include <openssl/core_names.h>
13 #include <openssl/params.h>
14 #include <openssl/evp.h>
15 #include <openssl/err.h>
16 #include <openssl/proverr.h>
17 
18 #include "crypto/siphash.h"
19 
20 #include "prov/implementations.h"
21 #include "prov/providercommon.h"
22 
23 /*
24  * Forward declaration of everything implemented here.  This is not strictly
25  * necessary for the compiler, but provides an assurance that the signatures
26  * of the functions in the dispatch table are correct.
27  */
28 static OSSL_FUNC_mac_newctx_fn siphash_new;
29 static OSSL_FUNC_mac_dupctx_fn siphash_dup;
30 static OSSL_FUNC_mac_freectx_fn siphash_free;
31 static OSSL_FUNC_mac_gettable_ctx_params_fn siphash_gettable_ctx_params;
32 static OSSL_FUNC_mac_get_ctx_params_fn siphash_get_ctx_params;
33 static OSSL_FUNC_mac_settable_ctx_params_fn siphash_settable_ctx_params;
34 static OSSL_FUNC_mac_set_ctx_params_fn siphash_set_params;
35 static OSSL_FUNC_mac_init_fn siphash_init;
36 static OSSL_FUNC_mac_update_fn siphash_update;
37 static OSSL_FUNC_mac_final_fn siphash_final;
38 
39 struct siphash_data_st {
40     void *provctx;
41     SIPHASH siphash;             /* Siphash data */
42     SIPHASH sipcopy;             /* Siphash data copy for reinitialization */
43     unsigned int crounds, drounds;
44 };
45 
crounds(struct siphash_data_st * ctx)46 static unsigned int crounds(struct siphash_data_st *ctx)
47 {
48     return ctx->crounds != 0 ? ctx->crounds : SIPHASH_C_ROUNDS;
49 }
50 
drounds(struct siphash_data_st * ctx)51 static unsigned int drounds(struct siphash_data_st *ctx)
52 {
53     return ctx->drounds != 0 ? ctx->drounds : SIPHASH_D_ROUNDS;
54 }
55 
siphash_new(void * provctx)56 static void *siphash_new(void *provctx)
57 {
58     struct siphash_data_st *ctx;
59 
60     if (!ossl_prov_is_running())
61         return NULL;
62     ctx = OPENSSL_zalloc(sizeof(*ctx));
63     if (ctx != NULL)
64         ctx->provctx = provctx;
65     return ctx;
66 }
67 
siphash_free(void * vmacctx)68 static void siphash_free(void *vmacctx)
69 {
70     OPENSSL_free(vmacctx);
71 }
72 
siphash_dup(void * vsrc)73 static void *siphash_dup(void *vsrc)
74 {
75     struct siphash_data_st *ssrc = vsrc;
76     struct siphash_data_st *sdst;
77 
78     if (!ossl_prov_is_running())
79         return NULL;
80     sdst = OPENSSL_malloc(sizeof(*sdst));
81     if (sdst == NULL)
82         return NULL;
83 
84     *sdst = *ssrc;
85     return sdst;
86 }
87 
siphash_size(void * vmacctx)88 static size_t siphash_size(void *vmacctx)
89 {
90     struct siphash_data_st *ctx = vmacctx;
91 
92     return SipHash_hash_size(&ctx->siphash);
93 }
94 
siphash_setkey(struct siphash_data_st * ctx,const unsigned char * key,size_t keylen)95 static int siphash_setkey(struct siphash_data_st *ctx,
96                           const unsigned char *key, size_t keylen)
97 {
98     int ret;
99 
100     if (keylen != SIPHASH_KEY_SIZE)
101         return 0;
102     ret = SipHash_Init(&ctx->siphash, key, crounds(ctx), drounds(ctx));
103     if (ret)
104         ctx->sipcopy = ctx->siphash;
105     return ret;
106 }
107 
siphash_init(void * vmacctx,const unsigned char * key,size_t keylen,const OSSL_PARAM params[])108 static int siphash_init(void *vmacctx, const unsigned char *key, size_t keylen,
109                         const OSSL_PARAM params[])
110 {
111     struct siphash_data_st *ctx = vmacctx;
112 
113     if (!ossl_prov_is_running() || !siphash_set_params(ctx, params))
114         return 0;
115     /*
116      * Without a key, there is not much to do here,
117      * The actual initialization happens through controls.
118      */
119     if (key == NULL) {
120         ctx->siphash = ctx->sipcopy;
121         return 1;
122     }
123     return siphash_setkey(ctx, key, keylen);
124 }
125 
siphash_update(void * vmacctx,const unsigned char * data,size_t datalen)126 static int siphash_update(void *vmacctx, const unsigned char *data,
127                           size_t datalen)
128 {
129     struct siphash_data_st *ctx = vmacctx;
130 
131     if (datalen == 0)
132         return 1;
133 
134     SipHash_Update(&ctx->siphash, data, datalen);
135     return 1;
136 }
137 
siphash_final(void * vmacctx,unsigned char * out,size_t * outl,size_t outsize)138 static int siphash_final(void *vmacctx, unsigned char *out, size_t *outl,
139                          size_t outsize)
140 {
141     struct siphash_data_st *ctx = vmacctx;
142     size_t hlen = siphash_size(ctx);
143 
144     if (!ossl_prov_is_running() || outsize < hlen)
145         return 0;
146 
147     *outl = hlen;
148     return SipHash_Final(&ctx->siphash, out, hlen);
149 }
150 
siphash_gettable_ctx_params(ossl_unused void * ctx,ossl_unused void * provctx)151 static const OSSL_PARAM *siphash_gettable_ctx_params(ossl_unused void *ctx,
152                                                      ossl_unused void *provctx)
153 {
154     static const OSSL_PARAM known_gettable_ctx_params[] = {
155         OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL),
156         OSSL_PARAM_uint(OSSL_MAC_PARAM_C_ROUNDS, NULL),
157         OSSL_PARAM_uint(OSSL_MAC_PARAM_D_ROUNDS, NULL),
158         OSSL_PARAM_END
159     };
160 
161     return known_gettable_ctx_params;
162 }
163 
siphash_get_ctx_params(void * vmacctx,OSSL_PARAM params[])164 static int siphash_get_ctx_params(void *vmacctx, OSSL_PARAM params[])
165 {
166     struct siphash_data_st *ctx = vmacctx;
167     OSSL_PARAM *p;
168 
169     if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE)) != NULL
170         && !OSSL_PARAM_set_size_t(p, siphash_size(vmacctx)))
171         return 0;
172     if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_C_ROUNDS)) != NULL
173         && !OSSL_PARAM_set_uint(p, crounds(ctx)))
174         return 0;
175     if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_D_ROUNDS)) != NULL
176         && !OSSL_PARAM_set_uint(p, drounds(ctx)))
177         return 0;
178     return 1;
179 }
180 
siphash_settable_ctx_params(ossl_unused void * ctx,void * provctx)181 static const OSSL_PARAM *siphash_settable_ctx_params(ossl_unused void *ctx,
182                                                      void *provctx)
183 {
184     static const OSSL_PARAM known_settable_ctx_params[] = {
185         OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL),
186         OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0),
187         OSSL_PARAM_uint(OSSL_MAC_PARAM_C_ROUNDS, NULL),
188         OSSL_PARAM_uint(OSSL_MAC_PARAM_D_ROUNDS, NULL),
189         OSSL_PARAM_END
190     };
191 
192     return known_settable_ctx_params;
193 }
194 
siphash_set_params(void * vmacctx,const OSSL_PARAM * params)195 static int siphash_set_params(void *vmacctx, const OSSL_PARAM *params)
196 {
197     struct siphash_data_st *ctx = vmacctx;
198     const OSSL_PARAM *p = NULL;
199     size_t size;
200 
201     if (params == NULL)
202         return 1;
203 
204     if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_SIZE)) != NULL) {
205         if (!OSSL_PARAM_get_size_t(p, &size)
206             || !SipHash_set_hash_size(&ctx->siphash, size)
207             || !SipHash_set_hash_size(&ctx->sipcopy, size))
208             return 0;
209     }
210     if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_C_ROUNDS)) != NULL
211             && !OSSL_PARAM_get_uint(p, &ctx->crounds))
212         return 0;
213     if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_D_ROUNDS)) != NULL
214             && !OSSL_PARAM_get_uint(p, &ctx->drounds))
215         return 0;
216     if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL)
217         if (p->data_type != OSSL_PARAM_OCTET_STRING
218             || !siphash_setkey(ctx, p->data, p->data_size))
219             return 0;
220     return 1;
221 }
222 
223 const OSSL_DISPATCH ossl_siphash_functions[] = {
224     { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))siphash_new },
225     { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))siphash_dup },
226     { OSSL_FUNC_MAC_FREECTX, (void (*)(void))siphash_free },
227     { OSSL_FUNC_MAC_INIT, (void (*)(void))siphash_init },
228     { OSSL_FUNC_MAC_UPDATE, (void (*)(void))siphash_update },
229     { OSSL_FUNC_MAC_FINAL, (void (*)(void))siphash_final },
230     { OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS,
231       (void (*)(void))siphash_gettable_ctx_params },
232     { OSSL_FUNC_MAC_GET_CTX_PARAMS, (void (*)(void))siphash_get_ctx_params },
233     { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS,
234       (void (*)(void))siphash_settable_ctx_params },
235     { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))siphash_set_params },
236     { 0, NULL }
237 };
238