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