qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

hmac-gnutls.c (3550B)


      1 /*
      2  * QEMU Crypto hmac algorithms
      3  *
      4  * Copyright (c) 2021 Red Hat, Inc.
      5  *
      6  * Derived from hmac-gcrypt.c:
      7  *
      8  *   Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
      9  *
     10  * This work is licensed under the terms of the GNU GPL, version 2 or
     11  * (at your option) any later version.  See the COPYING file in the
     12  * top-level directory.
     13  *
     14  */
     15 
     16 #include "qemu/osdep.h"
     17 #include <gnutls/crypto.h>
     18 
     19 #include "qapi/error.h"
     20 #include "crypto/hmac.h"
     21 #include "hmacpriv.h"
     22 
     23 static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
     24     [QCRYPTO_HASH_ALG_MD5] = GNUTLS_MAC_MD5,
     25     [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_MAC_SHA1,
     26     [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_MAC_SHA224,
     27     [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_MAC_SHA256,
     28     [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_MAC_SHA384,
     29     [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_MAC_SHA512,
     30     [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_MAC_RMD160,
     31 };
     32 
     33 typedef struct QCryptoHmacGnutls QCryptoHmacGnutls;
     34 struct QCryptoHmacGnutls {
     35     gnutls_hmac_hd_t handle;
     36 };
     37 
     38 bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
     39 {
     40     size_t i;
     41     const gnutls_digest_algorithm_t *algs;
     42     if (alg >= G_N_ELEMENTS(qcrypto_hmac_alg_map) ||
     43         qcrypto_hmac_alg_map[alg] == GNUTLS_DIG_UNKNOWN) {
     44         return false;
     45     }
     46     algs = gnutls_digest_list();
     47     for (i = 0; algs[i] != GNUTLS_DIG_UNKNOWN; i++) {
     48         if (algs[i] == qcrypto_hmac_alg_map[alg]) {
     49             return true;
     50         }
     51     }
     52     return false;
     53 }
     54 
     55 void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
     56                            const uint8_t *key, size_t nkey,
     57                            Error **errp)
     58 {
     59     QCryptoHmacGnutls *ctx;
     60     int err;
     61 
     62     if (!qcrypto_hmac_supports(alg)) {
     63         error_setg(errp, "Unsupported hmac algorithm %s",
     64                    QCryptoHashAlgorithm_str(alg));
     65         return NULL;
     66     }
     67 
     68     ctx = g_new0(QCryptoHmacGnutls, 1);
     69 
     70     err = gnutls_hmac_init(&ctx->handle,
     71                            qcrypto_hmac_alg_map[alg],
     72                            (const void *)key, nkey);
     73     if (err != 0) {
     74         error_setg(errp, "Cannot initialize hmac: %s",
     75                    gnutls_strerror(err));
     76         goto error;
     77     }
     78 
     79     return ctx;
     80 
     81 error:
     82     g_free(ctx);
     83     return NULL;
     84 }
     85 
     86 static void
     87 qcrypto_gnutls_hmac_ctx_free(QCryptoHmac *hmac)
     88 {
     89     QCryptoHmacGnutls *ctx;
     90 
     91     ctx = hmac->opaque;
     92     gnutls_hmac_deinit(ctx->handle, NULL);
     93 
     94     g_free(ctx);
     95 }
     96 
     97 static int
     98 qcrypto_gnutls_hmac_bytesv(QCryptoHmac *hmac,
     99                            const struct iovec *iov,
    100                            size_t niov,
    101                            uint8_t **result,
    102                            size_t *resultlen,
    103                            Error **errp)
    104 {
    105     QCryptoHmacGnutls *ctx;
    106     uint32_t ret;
    107     int i;
    108 
    109     ctx = hmac->opaque;
    110 
    111     for (i = 0; i < niov; i++) {
    112         gnutls_hmac(ctx->handle, iov[i].iov_base, iov[i].iov_len);
    113     }
    114 
    115     ret = gnutls_hmac_get_len(qcrypto_hmac_alg_map[hmac->alg]);
    116     if (ret <= 0) {
    117         error_setg(errp, "Unable to get hmac length: %s",
    118                    gnutls_strerror(ret));
    119         return -1;
    120     }
    121 
    122     if (*resultlen == 0) {
    123         *resultlen = ret;
    124         *result = g_new0(uint8_t, *resultlen);
    125     } else if (*resultlen != ret) {
    126         error_setg(errp, "Result buffer size %zu is smaller than hmac %d",
    127                    *resultlen, ret);
    128         return -1;
    129     }
    130 
    131     gnutls_hmac_output(ctx->handle, *result);
    132 
    133     return 0;
    134 }
    135 
    136 QCryptoHmacDriver qcrypto_hmac_lib_driver = {
    137     .hmac_bytesv = qcrypto_gnutls_hmac_bytesv,
    138     .hmac_free = qcrypto_gnutls_hmac_ctx_free,
    139 };