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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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
|
---|