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