xref: /freebsd/crypto/openssl/crypto/hmac/hmac_s390x.c (revision e7be843b4a162e68651d3911f0357ed464915629)
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