1 /*
2 * Copyright 2024 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 /* We need to use some engine deprecated APIs */
11 #define OPENSSL_SUPPRESS_DEPRECATED
12
13 #include "crypto/s390x_arch.h"
14 #include "hmac_local.h"
15 #include "openssl/obj_mac.h"
16 #include "openssl/evp.h"
17 #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE)
18 # include <openssl/engine.h>
19 #endif
20
21 #ifdef OPENSSL_HMAC_S390X
22
s390x_fc_from_md(const EVP_MD * md)23 static int s390x_fc_from_md(const EVP_MD *md)
24 {
25 int fc;
26
27 if (EVP_MD_is_a(md, "SHA2-224"))
28 fc = S390X_HMAC_SHA_224;
29 else if (EVP_MD_is_a(md, "SHA2-256"))
30 fc = S390X_HMAC_SHA_256;
31 else if (EVP_MD_is_a(md, "SHA2-384"))
32 fc = S390X_HMAC_SHA_384;
33 else if (EVP_MD_is_a(md, "SHA2-512"))
34 fc = S390X_HMAC_SHA_512;
35 else
36 return 0;
37
38 if ((OPENSSL_s390xcap_P.kmac[1] & S390X_CAPBIT(fc)) == 0)
39 return 0;
40
41 return fc;
42 }
43
s390x_call_kmac(HMAC_CTX * ctx,const unsigned char * in,size_t len)44 static void s390x_call_kmac(HMAC_CTX *ctx, const unsigned char *in, size_t len)
45 {
46 unsigned int fc = ctx->plat.s390x.fc;
47
48 if (ctx->plat.s390x.ikp)
49 fc |= S390X_KMAC_IKP;
50
51 if (ctx->plat.s390x.iimp)
52 fc |= S390X_KMAC_IIMP;
53
54 switch (ctx->plat.s390x.fc) {
55 case S390X_HMAC_SHA_224:
56 case S390X_HMAC_SHA_256:
57 ctx->plat.s390x.param.hmac_224_256.imbl += ((uint64_t)len * 8);
58 break;
59 case S390X_HMAC_SHA_384:
60 case S390X_HMAC_SHA_512:
61 ctx->plat.s390x.param.hmac_384_512.imbl += ((uint128_t)len * 8);
62 break;
63 default:
64 break;
65 }
66
67 s390x_kmac(in, len, fc, &ctx->plat.s390x.param);
68
69 ctx->plat.s390x.ikp = 1;
70 }
71
s390x_check_engine_used(const EVP_MD * md,ENGINE * impl)72 static int s390x_check_engine_used(const EVP_MD *md, ENGINE *impl)
73 {
74 # if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE)
75 const EVP_MD *d;
76
77 if (impl != NULL) {
78 if (!ENGINE_init(impl))
79 return 0;
80 } else {
81 impl = ENGINE_get_digest_engine(EVP_MD_get_type(md));
82 }
83
84 if (impl == NULL)
85 return 0;
86
87 d = ENGINE_get_digest(impl, EVP_MD_get_type(md));
88 ENGINE_finish(impl);
89
90 if (d != NULL)
91 return 1;
92 # endif
93
94 return 0;
95 }
96
s390x_HMAC_init(HMAC_CTX * ctx,const void * key,int key_len,ENGINE * impl)97 int s390x_HMAC_init(HMAC_CTX *ctx, const void *key, int key_len, ENGINE *impl)
98 {
99 unsigned char *key_param;
100 unsigned int key_param_len;
101
102 ctx->plat.s390x.fc = s390x_fc_from_md(ctx->md);
103 if (ctx->plat.s390x.fc == 0)
104 return -1; /* Not supported by kmac instruction */
105
106 if (s390x_check_engine_used(ctx->md, impl)) {
107 ctx->plat.s390x.fc = 0;
108 return -1; /* An engine handles the digest, disable acceleration */
109 }
110
111 ctx->plat.s390x.blk_size = EVP_MD_get_block_size(ctx->md);
112 if (ctx->plat.s390x.blk_size < 0)
113 return 0;
114
115 if (ctx->plat.s390x.size !=
116 (size_t)(ctx->plat.s390x.blk_size * HMAC_S390X_BUF_NUM_BLOCKS)) {
117 OPENSSL_clear_free(ctx->plat.s390x.buf, ctx->plat.s390x.size);
118 ctx->plat.s390x.size = 0;
119 ctx->plat.s390x.buf = OPENSSL_zalloc(ctx->plat.s390x.blk_size *
120 HMAC_S390X_BUF_NUM_BLOCKS);
121 if (ctx->plat.s390x.buf == NULL)
122 return 0;
123 ctx->plat.s390x.size = ctx->plat.s390x.blk_size *
124 HMAC_S390X_BUF_NUM_BLOCKS;
125 }
126 ctx->plat.s390x.num = 0;
127
128 ctx->plat.s390x.ikp = 0;
129 ctx->plat.s390x.iimp = 1;
130
131 switch (ctx->plat.s390x.fc) {
132 case S390X_HMAC_SHA_224:
133 case S390X_HMAC_SHA_256:
134 ctx->plat.s390x.param.hmac_224_256.imbl = 0;
135 OPENSSL_cleanse(ctx->plat.s390x.param.hmac_224_256.h,
136 sizeof(ctx->plat.s390x.param.hmac_224_256.h));
137 break;
138 case S390X_HMAC_SHA_384:
139 case S390X_HMAC_SHA_512:
140 ctx->plat.s390x.param.hmac_384_512.imbl = 0;
141 OPENSSL_cleanse(ctx->plat.s390x.param.hmac_384_512.h,
142 sizeof(ctx->plat.s390x.param.hmac_384_512.h));
143 break;
144 default:
145 return 0;
146 }
147
148 if (key != NULL) {
149 switch (ctx->plat.s390x.fc) {
150 case S390X_HMAC_SHA_224:
151 case S390X_HMAC_SHA_256:
152 OPENSSL_cleanse(&ctx->plat.s390x.param.hmac_224_256.key,
153 sizeof(ctx->plat.s390x.param.hmac_224_256.key));
154 key_param = ctx->plat.s390x.param.hmac_224_256.key;
155 key_param_len = sizeof(ctx->plat.s390x.param.hmac_224_256.key);
156 break;
157 case S390X_HMAC_SHA_384:
158 case S390X_HMAC_SHA_512:
159 OPENSSL_cleanse(&ctx->plat.s390x.param.hmac_384_512.key,
160 sizeof(ctx->plat.s390x.param.hmac_384_512.key));
161 key_param = ctx->plat.s390x.param.hmac_384_512.key;
162 key_param_len = sizeof(ctx->plat.s390x.param.hmac_384_512.key);
163 break;
164 default:
165 return 0;
166 }
167
168 if (!ossl_assert(ctx->plat.s390x.blk_size <= (int)key_param_len))
169 return 0;
170
171 if (key_len > ctx->plat.s390x.blk_size) {
172 if (!EVP_DigestInit_ex(ctx->md_ctx, ctx->md, impl)
173 || !EVP_DigestUpdate(ctx->md_ctx, key, key_len)
174 || !EVP_DigestFinal_ex(ctx->md_ctx, key_param,
175 &key_param_len))
176 return 0;
177 } else {
178 if (key_len < 0 || key_len > (int)key_param_len)
179 return 0;
180 memcpy(key_param, key, key_len);
181 /* remaining key bytes already zeroed out above */
182 }
183 }
184
185 return 1;
186 }
187
s390x_HMAC_update(HMAC_CTX * ctx,const unsigned char * data,size_t len)188 int s390x_HMAC_update(HMAC_CTX *ctx, const unsigned char *data, size_t len)
189 {
190 size_t remain, num;
191
192 if (len == 0)
193 return 1;
194
195 /* buffer is full, process it now */
196 if (ctx->plat.s390x.num == ctx->plat.s390x.size) {
197 s390x_call_kmac(ctx, ctx->plat.s390x.buf, ctx->plat.s390x.num);
198
199 ctx->plat.s390x.num = 0;
200 }
201
202 remain = ctx->plat.s390x.size - ctx->plat.s390x.num;
203 if (len > remain) {
204 /* data does not fit into buffer */
205 if (ctx->plat.s390x.num > 0) {
206 /* first fill buffer and process it */
207 memcpy(&ctx->plat.s390x.buf[ctx->plat.s390x.num], data, remain);
208 ctx->plat.s390x.num += remain;
209
210 s390x_call_kmac(ctx, ctx->plat.s390x.buf, ctx->plat.s390x.num);
211
212 ctx->plat.s390x.num = 0;
213
214 data += remain;
215 len -= remain;
216 }
217
218 if (!ossl_assert(ctx->plat.s390x.num == 0))
219 return 0;
220
221 if (len > ctx->plat.s390x.size) {
222 /*
223 * remaining data is still larger than buffer, process remaining
224 * full blocks of input directly
225 */
226 remain = len % ctx->plat.s390x.blk_size;
227 num = len - remain;
228
229 s390x_call_kmac(ctx, data, num);
230
231 data += num;
232 len -= num;
233 }
234 }
235
236 /* add remaining input data (which is < buffer size) to buffer */
237 if (!ossl_assert(len <= ctx->plat.s390x.size))
238 return 0;
239
240 if (len > 0) {
241 memcpy(&ctx->plat.s390x.buf[ctx->plat.s390x.num], data, len);
242 ctx->plat.s390x.num += len;
243 }
244
245 return 1;
246 }
247
s390x_HMAC_final(HMAC_CTX * ctx,unsigned char * md,unsigned int * len)248 int s390x_HMAC_final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len)
249 {
250 void *result;
251 unsigned int res_len;
252
253 ctx->plat.s390x.iimp = 0; /* last block */
254 s390x_call_kmac(ctx, ctx->plat.s390x.buf, ctx->plat.s390x.num);
255
256 ctx->plat.s390x.num = 0;
257
258 switch (ctx->plat.s390x.fc) {
259 case S390X_HMAC_SHA_224:
260 result = &ctx->plat.s390x.param.hmac_224_256.h[0];
261 res_len = SHA224_DIGEST_LENGTH;
262 break;
263 case S390X_HMAC_SHA_256:
264 result = &ctx->plat.s390x.param.hmac_224_256.h[0];
265 res_len = SHA256_DIGEST_LENGTH;
266 break;
267 case S390X_HMAC_SHA_384:
268 result = &ctx->plat.s390x.param.hmac_384_512.h[0];
269 res_len = SHA384_DIGEST_LENGTH;
270 break;
271 case S390X_HMAC_SHA_512:
272 result = &ctx->plat.s390x.param.hmac_384_512.h[0];
273 res_len = SHA512_DIGEST_LENGTH;
274 break;
275 default:
276 return 0;
277 }
278
279 memcpy(md, result, res_len);
280 if (len != NULL)
281 *len = res_len;
282
283 return 1;
284 }
285
s390x_HMAC_CTX_copy(HMAC_CTX * dctx,HMAC_CTX * sctx)286 int s390x_HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx)
287 {
288 dctx->plat.s390x.fc = sctx->plat.s390x.fc;
289 dctx->plat.s390x.blk_size = sctx->plat.s390x.blk_size;
290 dctx->plat.s390x.ikp = sctx->plat.s390x.ikp;
291 dctx->plat.s390x.iimp = sctx->plat.s390x.iimp;
292
293 memcpy(&dctx->plat.s390x.param, &sctx->plat.s390x.param,
294 sizeof(dctx->plat.s390x.param));
295
296 OPENSSL_clear_free(dctx->plat.s390x.buf, dctx->plat.s390x.size);
297 dctx->plat.s390x.buf = NULL;
298 if (sctx->plat.s390x.buf != NULL) {
299 dctx->plat.s390x.buf = OPENSSL_memdup(sctx->plat.s390x.buf,
300 sctx->plat.s390x.size);
301 if (dctx->plat.s390x.buf == NULL)
302 return 0;
303 }
304
305 dctx->plat.s390x.size = sctx->plat.s390x.size;
306 dctx->plat.s390x.num = sctx->plat.s390x.num;
307
308 return 1;
309 }
310
s390x_HMAC_CTX_cleanup(HMAC_CTX * ctx)311 int s390x_HMAC_CTX_cleanup(HMAC_CTX *ctx)
312 {
313 OPENSSL_clear_free(ctx->plat.s390x.buf, ctx->plat.s390x.size);
314 ctx->plat.s390x.buf = NULL;
315 ctx->plat.s390x.size = 0;
316 ctx->plat.s390x.num = 0;
317
318 OPENSSL_cleanse(&ctx->plat.s390x.param, sizeof(ctx->plat.s390x.param));
319
320 ctx->plat.s390x.blk_size = 0;
321 ctx->plat.s390x.ikp = 0;
322 ctx->plat.s390x.iimp = 1;
323
324 ctx->plat.s390x.fc = 0;
325
326 return 1;
327 }
328
329 #endif
330