xref: /openbmc/qemu/crypto/hash-afalg.c (revision e51d8fbb7e673e487e98327fc067700b5a3edf30)
19a059773SLongpeng(Mike) /*
242e7e15fSLongpeng(Mike)  * QEMU Crypto af_alg-backend hash/hmac support
39a059773SLongpeng(Mike)  *
490c3dc60SAlejandro Zeise  * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
59a059773SLongpeng(Mike)  * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
69a059773SLongpeng(Mike)  *
79a059773SLongpeng(Mike)  * Authors:
89a059773SLongpeng(Mike)  *    Longpeng(Mike) <longpeng2@huawei.com>
99a059773SLongpeng(Mike)  *
109a059773SLongpeng(Mike)  * This work is licensed under the terms of the GNU GPL, version 2 or
119a059773SLongpeng(Mike)  * (at your option) any later version.  See the COPYING file in the
129a059773SLongpeng(Mike)  * top-level directory.
139a059773SLongpeng(Mike)  */
149a059773SLongpeng(Mike) #include "qemu/osdep.h"
159a059773SLongpeng(Mike) #include "qemu/iov.h"
169a059773SLongpeng(Mike) #include "qemu/sockets.h"
179a059773SLongpeng(Mike) #include "qapi/error.h"
189a059773SLongpeng(Mike) #include "crypto/hash.h"
1942e7e15fSLongpeng(Mike) #include "crypto/hmac.h"
209a059773SLongpeng(Mike) #include "hashpriv.h"
2142e7e15fSLongpeng(Mike) #include "hmacpriv.h"
229a059773SLongpeng(Mike) 
239a059773SLongpeng(Mike) static char *
qcrypto_afalg_hash_format_name(QCryptoHashAlgo alg,bool is_hmac,Error ** errp)24ef834aa2SMarkus Armbruster qcrypto_afalg_hash_format_name(QCryptoHashAlgo alg,
2542e7e15fSLongpeng(Mike)                                bool is_hmac,
269a059773SLongpeng(Mike)                                Error **errp)
279a059773SLongpeng(Mike) {
289a059773SLongpeng(Mike)     char *name;
299a059773SLongpeng(Mike)     const char *alg_name;
309a059773SLongpeng(Mike) 
319a059773SLongpeng(Mike)     switch (alg) {
32ef834aa2SMarkus Armbruster     case QCRYPTO_HASH_ALGO_MD5:
339a059773SLongpeng(Mike)         alg_name = "md5";
349a059773SLongpeng(Mike)         break;
35ef834aa2SMarkus Armbruster     case QCRYPTO_HASH_ALGO_SHA1:
369a059773SLongpeng(Mike)         alg_name = "sha1";
379a059773SLongpeng(Mike)         break;
38ef834aa2SMarkus Armbruster     case QCRYPTO_HASH_ALGO_SHA224:
399a059773SLongpeng(Mike)         alg_name = "sha224";
409a059773SLongpeng(Mike)         break;
41ef834aa2SMarkus Armbruster     case QCRYPTO_HASH_ALGO_SHA256:
429a059773SLongpeng(Mike)         alg_name = "sha256";
439a059773SLongpeng(Mike)         break;
44ef834aa2SMarkus Armbruster     case QCRYPTO_HASH_ALGO_SHA384:
459a059773SLongpeng(Mike)         alg_name = "sha384";
469a059773SLongpeng(Mike)         break;
47ef834aa2SMarkus Armbruster     case QCRYPTO_HASH_ALGO_SHA512:
489a059773SLongpeng(Mike)         alg_name = "sha512";
499a059773SLongpeng(Mike)         break;
50ef834aa2SMarkus Armbruster     case QCRYPTO_HASH_ALGO_RIPEMD160:
519a059773SLongpeng(Mike)         alg_name = "rmd160";
529a059773SLongpeng(Mike)         break;
539a059773SLongpeng(Mike) 
549a059773SLongpeng(Mike)     default:
559a059773SLongpeng(Mike)         error_setg(errp, "Unsupported hash algorithm %d", alg);
569a059773SLongpeng(Mike)         return NULL;
579a059773SLongpeng(Mike)     }
589a059773SLongpeng(Mike) 
5942e7e15fSLongpeng(Mike)     if (is_hmac) {
6042e7e15fSLongpeng(Mike)         name = g_strdup_printf("hmac(%s)", alg_name);
6142e7e15fSLongpeng(Mike)     } else {
629a059773SLongpeng(Mike)         name = g_strdup_printf("%s", alg_name);
6342e7e15fSLongpeng(Mike)     }
649a059773SLongpeng(Mike) 
659a059773SLongpeng(Mike)     return name;
669a059773SLongpeng(Mike) }
679a059773SLongpeng(Mike) 
688f525028SMarkus Armbruster static QCryptoAFAlgo *
qcrypto_afalg_hash_hmac_ctx_new(QCryptoHashAlgo alg,const uint8_t * key,size_t nkey,bool is_hmac,Error ** errp)69ef834aa2SMarkus Armbruster qcrypto_afalg_hash_hmac_ctx_new(QCryptoHashAlgo alg,
7042e7e15fSLongpeng(Mike)                                 const uint8_t *key, size_t nkey,
7142e7e15fSLongpeng(Mike)                                 bool is_hmac, Error **errp)
729a059773SLongpeng(Mike) {
738f525028SMarkus Armbruster     QCryptoAFAlgo *afalg;
749a059773SLongpeng(Mike)     char *name;
759a059773SLongpeng(Mike) 
7642e7e15fSLongpeng(Mike)     name = qcrypto_afalg_hash_format_name(alg, is_hmac, errp);
779a059773SLongpeng(Mike)     if (!name) {
789a059773SLongpeng(Mike)         return NULL;
799a059773SLongpeng(Mike)     }
809a059773SLongpeng(Mike) 
819a059773SLongpeng(Mike)     afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_HASH, name, errp);
829a059773SLongpeng(Mike)     if (!afalg) {
839a059773SLongpeng(Mike)         g_free(name);
849a059773SLongpeng(Mike)         return NULL;
859a059773SLongpeng(Mike)     }
869a059773SLongpeng(Mike) 
879a059773SLongpeng(Mike)     g_free(name);
889a059773SLongpeng(Mike) 
8942e7e15fSLongpeng(Mike)     /* HMAC needs setkey */
9042e7e15fSLongpeng(Mike)     if (is_hmac) {
91e7b79428SMarc-André Lureau         if (setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY,
9242e7e15fSLongpeng(Mike)                        key, nkey) != 0) {
9342e7e15fSLongpeng(Mike)             error_setg_errno(errp, errno, "Set hmac key failed");
9442e7e15fSLongpeng(Mike)             qcrypto_afalg_comm_free(afalg);
9542e7e15fSLongpeng(Mike)             return NULL;
9642e7e15fSLongpeng(Mike)         }
9742e7e15fSLongpeng(Mike)     }
9842e7e15fSLongpeng(Mike) 
999a059773SLongpeng(Mike)     return afalg;
1009a059773SLongpeng(Mike) }
1019a059773SLongpeng(Mike) 
1028f525028SMarkus Armbruster static QCryptoAFAlgo *
qcrypto_afalg_hash_ctx_new(QCryptoHashAlgo alg,Error ** errp)103ef834aa2SMarkus Armbruster qcrypto_afalg_hash_ctx_new(QCryptoHashAlgo alg,
10442e7e15fSLongpeng(Mike)                            Error **errp)
10542e7e15fSLongpeng(Mike) {
10642e7e15fSLongpeng(Mike)     return qcrypto_afalg_hash_hmac_ctx_new(alg, NULL, 0, false, errp);
10742e7e15fSLongpeng(Mike) }
10842e7e15fSLongpeng(Mike) 
1098f525028SMarkus Armbruster QCryptoAFAlgo *
qcrypto_afalg_hmac_ctx_new(QCryptoHashAlgo alg,const uint8_t * key,size_t nkey,Error ** errp)110ef834aa2SMarkus Armbruster qcrypto_afalg_hmac_ctx_new(QCryptoHashAlgo alg,
11142e7e15fSLongpeng(Mike)                            const uint8_t *key, size_t nkey,
11242e7e15fSLongpeng(Mike)                            Error **errp)
11342e7e15fSLongpeng(Mike) {
11442e7e15fSLongpeng(Mike)     return qcrypto_afalg_hash_hmac_ctx_new(alg, key, nkey, true, errp);
11542e7e15fSLongpeng(Mike) }
11642e7e15fSLongpeng(Mike) 
11790c3dc60SAlejandro Zeise static
qcrypto_afalg_hash_new(QCryptoHashAlgo alg,Error ** errp)11890c3dc60SAlejandro Zeise QCryptoHash *qcrypto_afalg_hash_new(QCryptoHashAlgo alg, Error **errp)
11990c3dc60SAlejandro Zeise {
12090c3dc60SAlejandro Zeise     /* Check if hash algorithm is supported */
12190c3dc60SAlejandro Zeise     char *alg_name = qcrypto_afalg_hash_format_name(alg, false, NULL);
12290c3dc60SAlejandro Zeise     QCryptoHash *hash;
12390c3dc60SAlejandro Zeise 
12490c3dc60SAlejandro Zeise     if (alg_name == NULL) {
12590c3dc60SAlejandro Zeise         error_setg(errp, "Unknown hash algorithm %d", alg);
12690c3dc60SAlejandro Zeise         return NULL;
12790c3dc60SAlejandro Zeise     }
12890c3dc60SAlejandro Zeise 
12990c3dc60SAlejandro Zeise     g_free(alg_name);
13090c3dc60SAlejandro Zeise 
13190c3dc60SAlejandro Zeise     hash = g_new(QCryptoHash, 1);
13290c3dc60SAlejandro Zeise     hash->alg = alg;
13390c3dc60SAlejandro Zeise     hash->opaque = qcrypto_afalg_hash_ctx_new(alg, errp);
13490c3dc60SAlejandro Zeise     if (!hash->opaque) {
13590c3dc60SAlejandro Zeise         free(hash);
13690c3dc60SAlejandro Zeise         return NULL;
13790c3dc60SAlejandro Zeise     }
13890c3dc60SAlejandro Zeise 
13990c3dc60SAlejandro Zeise     return hash;
14090c3dc60SAlejandro Zeise }
14190c3dc60SAlejandro Zeise 
14290c3dc60SAlejandro Zeise static
qcrypto_afalg_hash_free(QCryptoHash * hash)14390c3dc60SAlejandro Zeise void qcrypto_afalg_hash_free(QCryptoHash *hash)
14490c3dc60SAlejandro Zeise {
145*f8395ce8SMarkus Armbruster     QCryptoAFAlgo *ctx = hash->opaque;
14690c3dc60SAlejandro Zeise 
14790c3dc60SAlejandro Zeise     if (ctx) {
14890c3dc60SAlejandro Zeise         qcrypto_afalg_comm_free(ctx);
14990c3dc60SAlejandro Zeise     }
15090c3dc60SAlejandro Zeise 
15190c3dc60SAlejandro Zeise     g_free(hash);
15290c3dc60SAlejandro Zeise }
15390c3dc60SAlejandro Zeise 
15490c3dc60SAlejandro Zeise /**
15590c3dc60SAlejandro Zeise  * Send data to the kernel's crypto core.
15690c3dc60SAlejandro Zeise  *
15790c3dc60SAlejandro Zeise  * The more_data parameter is used to notify the crypto engine
15890c3dc60SAlejandro Zeise  * that this is an "update" operation, and that more data will
15990c3dc60SAlejandro Zeise  * be provided to calculate the final hash.
16090c3dc60SAlejandro Zeise  */
16190c3dc60SAlejandro Zeise static
qcrypto_afalg_send_to_kernel(QCryptoAFAlgo * afalg,const struct iovec * iov,size_t niov,bool more_data,Error ** errp)162*f8395ce8SMarkus Armbruster int qcrypto_afalg_send_to_kernel(QCryptoAFAlgo *afalg,
16390c3dc60SAlejandro Zeise                                  const struct iovec *iov,
16490c3dc60SAlejandro Zeise                                  size_t niov,
16590c3dc60SAlejandro Zeise                                  bool more_data,
16690c3dc60SAlejandro Zeise                                  Error **errp)
16790c3dc60SAlejandro Zeise {
16890c3dc60SAlejandro Zeise     int ret = 0;
16990c3dc60SAlejandro Zeise     int flags = (more_data ? MSG_MORE : 0);
17090c3dc60SAlejandro Zeise 
17190c3dc60SAlejandro Zeise     /* send data to kernel's crypto core */
17290c3dc60SAlejandro Zeise     ret = iov_send_recv_with_flags(afalg->opfd, flags, iov, niov,
17390c3dc60SAlejandro Zeise                                    0, iov_size(iov, niov), true);
17490c3dc60SAlejandro Zeise     if (ret < 0) {
17590c3dc60SAlejandro Zeise         error_setg_errno(errp, errno, "Send data to afalg-core failed");
17690c3dc60SAlejandro Zeise         ret = -1;
17790c3dc60SAlejandro Zeise     } else {
17890c3dc60SAlejandro Zeise         /* No error, so return 0 */
17990c3dc60SAlejandro Zeise         ret = 0;
18090c3dc60SAlejandro Zeise     }
18190c3dc60SAlejandro Zeise 
18290c3dc60SAlejandro Zeise     return ret;
18390c3dc60SAlejandro Zeise }
18490c3dc60SAlejandro Zeise 
18590c3dc60SAlejandro Zeise static
qcrypto_afalg_recv_from_kernel(QCryptoAFAlgo * afalg,QCryptoHashAlgo alg,uint8_t ** result,size_t * result_len,Error ** errp)186*f8395ce8SMarkus Armbruster int qcrypto_afalg_recv_from_kernel(QCryptoAFAlgo *afalg,
18790c3dc60SAlejandro Zeise                                    QCryptoHashAlgo alg,
18890c3dc60SAlejandro Zeise                                    uint8_t **result,
18990c3dc60SAlejandro Zeise                                    size_t *result_len,
19090c3dc60SAlejandro Zeise                                    Error **errp)
19190c3dc60SAlejandro Zeise {
19290c3dc60SAlejandro Zeise     struct iovec outv;
19390c3dc60SAlejandro Zeise     int ret;
19490c3dc60SAlejandro Zeise     const int expected_len = qcrypto_hash_digest_len(alg);
19590c3dc60SAlejandro Zeise 
19690c3dc60SAlejandro Zeise     if (*result_len == 0) {
19790c3dc60SAlejandro Zeise         *result_len = expected_len;
19890c3dc60SAlejandro Zeise         *result = g_new0(uint8_t, *result_len);
19990c3dc60SAlejandro Zeise     } else if (*result_len != expected_len) {
20090c3dc60SAlejandro Zeise         error_setg(errp,
20190c3dc60SAlejandro Zeise                    "Result buffer size %zu is not match hash %d",
20290c3dc60SAlejandro Zeise                    *result_len, expected_len);
20390c3dc60SAlejandro Zeise         return -1;
20490c3dc60SAlejandro Zeise     }
20590c3dc60SAlejandro Zeise 
20690c3dc60SAlejandro Zeise     /* hash && get result */
20790c3dc60SAlejandro Zeise     outv.iov_base = *result;
20890c3dc60SAlejandro Zeise     outv.iov_len = *result_len;
20990c3dc60SAlejandro Zeise     ret = iov_send_recv(afalg->opfd, &outv, 1,
21090c3dc60SAlejandro Zeise                         0, iov_size(&outv, 1), false);
21190c3dc60SAlejandro Zeise     if (ret < 0) {
21290c3dc60SAlejandro Zeise         error_setg_errno(errp, errno, "Recv result from afalg-core failed");
21390c3dc60SAlejandro Zeise         return -1;
21490c3dc60SAlejandro Zeise     }
21590c3dc60SAlejandro Zeise 
21690c3dc60SAlejandro Zeise     return 0;
21790c3dc60SAlejandro Zeise }
21890c3dc60SAlejandro Zeise 
21990c3dc60SAlejandro Zeise static
qcrypto_afalg_hash_update(QCryptoHash * hash,const struct iovec * iov,size_t niov,Error ** errp)22090c3dc60SAlejandro Zeise int qcrypto_afalg_hash_update(QCryptoHash *hash,
22190c3dc60SAlejandro Zeise                               const struct iovec *iov,
22290c3dc60SAlejandro Zeise                               size_t niov,
22390c3dc60SAlejandro Zeise                               Error **errp)
22490c3dc60SAlejandro Zeise {
225*f8395ce8SMarkus Armbruster     return qcrypto_afalg_send_to_kernel((QCryptoAFAlgo *) hash->opaque,
22690c3dc60SAlejandro Zeise                                         iov, niov, true, errp);
22790c3dc60SAlejandro Zeise }
22890c3dc60SAlejandro Zeise 
22990c3dc60SAlejandro Zeise static
qcrypto_afalg_hash_finalize(QCryptoHash * hash,uint8_t ** result,size_t * result_len,Error ** errp)23090c3dc60SAlejandro Zeise int qcrypto_afalg_hash_finalize(QCryptoHash *hash,
23190c3dc60SAlejandro Zeise                                  uint8_t **result,
23290c3dc60SAlejandro Zeise                                  size_t *result_len,
23390c3dc60SAlejandro Zeise                                  Error **errp)
23490c3dc60SAlejandro Zeise {
235*f8395ce8SMarkus Armbruster     return qcrypto_afalg_recv_from_kernel((QCryptoAFAlgo *) hash->opaque,
23690c3dc60SAlejandro Zeise                                           hash->alg, result, result_len, errp);
23790c3dc60SAlejandro Zeise }
23890c3dc60SAlejandro Zeise 
2399a059773SLongpeng(Mike) static int
qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlgo * hmac,QCryptoHashAlgo alg,const struct iovec * iov,size_t niov,uint8_t ** result,size_t * resultlen,Error ** errp)2408f525028SMarkus Armbruster qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlgo *hmac,
241ef834aa2SMarkus Armbruster                                QCryptoHashAlgo alg,
2429a059773SLongpeng(Mike)                                const struct iovec *iov,
2439a059773SLongpeng(Mike)                                size_t niov, uint8_t **result,
2449a059773SLongpeng(Mike)                                size_t *resultlen,
2459a059773SLongpeng(Mike)                                Error **errp)
2469a059773SLongpeng(Mike) {
2479a059773SLongpeng(Mike)     int ret = 0;
2489a059773SLongpeng(Mike) 
2498a70903bSAlejandro Zeise     ret = qcrypto_afalg_send_to_kernel(hmac, iov, niov, false, errp);
2508a70903bSAlejandro Zeise     if (ret == 0) {
2518a70903bSAlejandro Zeise         ret = qcrypto_afalg_recv_from_kernel(hmac, alg, result,
25242e7e15fSLongpeng(Mike)                                              resultlen, errp);
25342e7e15fSLongpeng(Mike)     }
25442e7e15fSLongpeng(Mike) 
2558a70903bSAlejandro Zeise     return ret;
2568a70903bSAlejandro Zeise }
2578a70903bSAlejandro Zeise 
25842e7e15fSLongpeng(Mike) static int
qcrypto_afalg_hmac_bytesv(QCryptoHmac * hmac,const struct iovec * iov,size_t niov,uint8_t ** result,size_t * resultlen,Error ** errp)25942e7e15fSLongpeng(Mike) qcrypto_afalg_hmac_bytesv(QCryptoHmac *hmac,
26042e7e15fSLongpeng(Mike)                           const struct iovec *iov,
26142e7e15fSLongpeng(Mike)                           size_t niov, uint8_t **result,
26242e7e15fSLongpeng(Mike)                           size_t *resultlen,
26342e7e15fSLongpeng(Mike)                           Error **errp)
26442e7e15fSLongpeng(Mike) {
26542e7e15fSLongpeng(Mike)     return qcrypto_afalg_hash_hmac_bytesv(hmac->opaque, hmac->alg,
26642e7e15fSLongpeng(Mike)                                           iov, niov, result, resultlen,
26742e7e15fSLongpeng(Mike)                                           errp);
26842e7e15fSLongpeng(Mike) }
26942e7e15fSLongpeng(Mike) 
qcrypto_afalg_hmac_ctx_free(QCryptoHmac * hmac)27042e7e15fSLongpeng(Mike) static void qcrypto_afalg_hmac_ctx_free(QCryptoHmac *hmac)
27142e7e15fSLongpeng(Mike) {
2728f525028SMarkus Armbruster     QCryptoAFAlgo *afalg;
27342e7e15fSLongpeng(Mike) 
27442e7e15fSLongpeng(Mike)     afalg = hmac->opaque;
27542e7e15fSLongpeng(Mike)     qcrypto_afalg_comm_free(afalg);
27642e7e15fSLongpeng(Mike) }
27742e7e15fSLongpeng(Mike) 
2789a059773SLongpeng(Mike) QCryptoHashDriver qcrypto_hash_afalg_driver = {
27990c3dc60SAlejandro Zeise     .hash_new      = qcrypto_afalg_hash_new,
28090c3dc60SAlejandro Zeise     .hash_free     = qcrypto_afalg_hash_free,
28190c3dc60SAlejandro Zeise     .hash_update   = qcrypto_afalg_hash_update,
28290c3dc60SAlejandro Zeise     .hash_finalize = qcrypto_afalg_hash_finalize
2839a059773SLongpeng(Mike) };
28442e7e15fSLongpeng(Mike) 
28542e7e15fSLongpeng(Mike) QCryptoHmacDriver qcrypto_hmac_afalg_driver = {
28642e7e15fSLongpeng(Mike)     .hmac_bytesv = qcrypto_afalg_hmac_bytesv,
28742e7e15fSLongpeng(Mike)     .hmac_free = qcrypto_afalg_hmac_ctx_free,
28842e7e15fSLongpeng(Mike) };
289