mirror of https://github.com/xemu-project/xemu.git
Introduce new cryptography hashing APIs
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmcH/iIACgkQvobrtBUQ T9+Yjg/+NReYV5BDjOLk6vfgTsK6Ku0/hdis2cf9OS8Ud1VXzKaxfhwkchtw9QVI kuAthesQNocEPfQfl2K4+f4oaKfysO7awDwYto/JhY/m1iCZ8iqofZWehOITszvM EvWlNBr83NtpGFIwQWIxFEVZo42gaUnA69iAjBo7YQnE5xufJuPIbgMjB/O4/zar Xlo15A69TP9dBJTvIDdrhkt3Quiysa7a68BW+piAAKvplOjOfugCEo3ebLwlZYOh dK0Cg9v24+BMAqQ7kDMroS4uHC+OEs2AOvfYh01QqWxNkk7RsPjb9VAA60Ng89eC 6BU4jw17zUAqL67of+M1cTTX4UPGBWGIUXt8CtO1DpByxiGXXfEkBrBmIyDJvxn9 EzB4WpAXpVo2AG6vYpYSBGyxycWQs33ljfBb/qR6xu5PnA+Jc/jfJkVv5iYP96wW F6pJm6FoK69aTJU7K4kAJPjD2fZum+iHVWc283NIkq9HQJLz2EYE0LIfOOY5feJK S0tjEE5ZLqKG5JAdpsaCe5V/vExc512/D56Xb5fY4mC2DPb/b6fM66Oc5M7DTuK1 LxCgnEuqm1Lo3CMR0k4W8Xezs7hWp+u3tr+i705l5qFxklYkmFeVAzTWdQ56JOGk Z1XKUbcPUnweormPMxMQXyxXpey4DBwUGbjC98iqE8tjUg6NA3o= =yVgk -----END PGP SIGNATURE----- Merge tag 'crypto-fixes-pull-request' of https://gitlab.com/berrange/qemu into staging Introduce new cryptography hashing APIs # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmcH/iIACgkQvobrtBUQ # T9+Yjg/+NReYV5BDjOLk6vfgTsK6Ku0/hdis2cf9OS8Ud1VXzKaxfhwkchtw9QVI # kuAthesQNocEPfQfl2K4+f4oaKfysO7awDwYto/JhY/m1iCZ8iqofZWehOITszvM # EvWlNBr83NtpGFIwQWIxFEVZo42gaUnA69iAjBo7YQnE5xufJuPIbgMjB/O4/zar # Xlo15A69TP9dBJTvIDdrhkt3Quiysa7a68BW+piAAKvplOjOfugCEo3ebLwlZYOh # dK0Cg9v24+BMAqQ7kDMroS4uHC+OEs2AOvfYh01QqWxNkk7RsPjb9VAA60Ng89eC # 6BU4jw17zUAqL67of+M1cTTX4UPGBWGIUXt8CtO1DpByxiGXXfEkBrBmIyDJvxn9 # EzB4WpAXpVo2AG6vYpYSBGyxycWQs33ljfBb/qR6xu5PnA+Jc/jfJkVv5iYP96wW # F6pJm6FoK69aTJU7K4kAJPjD2fZum+iHVWc283NIkq9HQJLz2EYE0LIfOOY5feJK # S0tjEE5ZLqKG5JAdpsaCe5V/vExc512/D56Xb5fY4mC2DPb/b6fM66Oc5M7DTuK1 # LxCgnEuqm1Lo3CMR0k4W8Xezs7hWp+u3tr+i705l5qFxklYkmFeVAzTWdQ56JOGk # Z1XKUbcPUnweormPMxMQXyxXpey4DBwUGbjC98iqE8tjUg6NA3o= # =yVgk # -----END PGP SIGNATURE----- # gpg: Signature made Thu 10 Oct 2024 17:17:38 BST # gpg: using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full] # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [full] # Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF * tag 'crypto-fixes-pull-request' of https://gitlab.com/berrange/qemu: tests/unit: Add a assert for test_io_channel_unix_listen_cleanup crypto: drop obsolete back compat logic for old nettle crypto/hashpriv: Remove old hash API function crypto/hash-afalg: Remove old hash API functions crypto/hash-nettle: Remove old hash API functions crypto/hash-gnutls: Remove old hash API functions crypto/hash-gcrypt: Remove old hash API functions crypto/hash-glib: Remove old hash API functions tests/unit/test-crypto-hash: accumulative hashing crypto/hash: Implement and use new hash API crypto/hash-afalg: Implement new hash API util/iov: Introduce iov_send_recv_with_flags() crypto/hash-nettle: Implement new hash API crypto/hash-gnutls: Implement new hash API crypto/hash-gcrypt: Implement new hash API crypto/hash-glib: Implement new hash API crypto: accumulative hashing API Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7e3b6d8063
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* QEMU Crypto af_alg-backend hash/hmac support
|
* QEMU Crypto af_alg-backend hash/hmac support
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
* Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
|
* Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
|
@ -113,6 +114,128 @@ qcrypto_afalg_hmac_ctx_new(QCryptoHashAlgo alg,
|
||||||
return qcrypto_afalg_hash_hmac_ctx_new(alg, key, nkey, true, errp);
|
return qcrypto_afalg_hash_hmac_ctx_new(alg, key, nkey, true, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
QCryptoHash *qcrypto_afalg_hash_new(QCryptoHashAlgo alg, Error **errp)
|
||||||
|
{
|
||||||
|
/* Check if hash algorithm is supported */
|
||||||
|
char *alg_name = qcrypto_afalg_hash_format_name(alg, false, NULL);
|
||||||
|
QCryptoHash *hash;
|
||||||
|
|
||||||
|
if (alg_name == NULL) {
|
||||||
|
error_setg(errp, "Unknown hash algorithm %d", alg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(alg_name);
|
||||||
|
|
||||||
|
hash = g_new(QCryptoHash, 1);
|
||||||
|
hash->alg = alg;
|
||||||
|
hash->opaque = qcrypto_afalg_hash_ctx_new(alg, errp);
|
||||||
|
if (!hash->opaque) {
|
||||||
|
free(hash);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void qcrypto_afalg_hash_free(QCryptoHash *hash)
|
||||||
|
{
|
||||||
|
QCryptoAFAlg *ctx = hash->opaque;
|
||||||
|
|
||||||
|
if (ctx) {
|
||||||
|
qcrypto_afalg_comm_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send data to the kernel's crypto core.
|
||||||
|
*
|
||||||
|
* The more_data parameter is used to notify the crypto engine
|
||||||
|
* that this is an "update" operation, and that more data will
|
||||||
|
* be provided to calculate the final hash.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int qcrypto_afalg_send_to_kernel(QCryptoAFAlg *afalg,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
bool more_data,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int flags = (more_data ? MSG_MORE : 0);
|
||||||
|
|
||||||
|
/* send data to kernel's crypto core */
|
||||||
|
ret = iov_send_recv_with_flags(afalg->opfd, flags, iov, niov,
|
||||||
|
0, iov_size(iov, niov), true);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, errno, "Send data to afalg-core failed");
|
||||||
|
ret = -1;
|
||||||
|
} else {
|
||||||
|
/* No error, so return 0 */
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_afalg_recv_from_kernel(QCryptoAFAlg *afalg,
|
||||||
|
QCryptoHashAlgo alg,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *result_len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
struct iovec outv;
|
||||||
|
int ret;
|
||||||
|
const int expected_len = qcrypto_hash_digest_len(alg);
|
||||||
|
|
||||||
|
if (*result_len == 0) {
|
||||||
|
*result_len = expected_len;
|
||||||
|
*result = g_new0(uint8_t, *result_len);
|
||||||
|
} else if (*result_len != expected_len) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Result buffer size %zu is not match hash %d",
|
||||||
|
*result_len, expected_len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hash && get result */
|
||||||
|
outv.iov_base = *result;
|
||||||
|
outv.iov_len = *result_len;
|
||||||
|
ret = iov_send_recv(afalg->opfd, &outv, 1,
|
||||||
|
0, iov_size(&outv, 1), false);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, errno, "Recv result from afalg-core failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_afalg_hash_update(QCryptoHash *hash,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return qcrypto_afalg_send_to_kernel((QCryptoAFAlg *) hash->opaque,
|
||||||
|
iov, niov, true, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_afalg_hash_finalize(QCryptoHash *hash,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *result_len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return qcrypto_afalg_recv_from_kernel((QCryptoAFAlg *) hash->opaque,
|
||||||
|
hash->alg, result, result_len, errp);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlgo *hmac,
|
qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlgo *hmac,
|
||||||
QCryptoHashAlgo alg,
|
QCryptoHashAlgo alg,
|
||||||
|
@ -121,68 +244,17 @@ qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlgo *hmac,
|
||||||
size_t *resultlen,
|
size_t *resultlen,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
QCryptoAFAlgo *afalg;
|
|
||||||
struct iovec outv;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
bool is_hmac = (hmac != NULL) ? true : false;
|
|
||||||
const int expect_len = qcrypto_hash_digest_len(alg);
|
|
||||||
|
|
||||||
if (*resultlen == 0) {
|
ret = qcrypto_afalg_send_to_kernel(hmac, iov, niov, false, errp);
|
||||||
*resultlen = expect_len;
|
if (ret == 0) {
|
||||||
*result = g_new0(uint8_t, *resultlen);
|
ret = qcrypto_afalg_recv_from_kernel(hmac, alg, result,
|
||||||
} else if (*resultlen != expect_len) {
|
resultlen, errp);
|
||||||
error_setg(errp,
|
|
||||||
"Result buffer size %zu is not match hash %d",
|
|
||||||
*resultlen, expect_len);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_hmac) {
|
|
||||||
afalg = hmac;
|
|
||||||
} else {
|
|
||||||
afalg = qcrypto_afalg_hash_ctx_new(alg, errp);
|
|
||||||
if (!afalg) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send data to kernel's crypto core */
|
|
||||||
ret = iov_send_recv(afalg->opfd, iov, niov,
|
|
||||||
0, iov_size(iov, niov), true);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_setg_errno(errp, errno, "Send data to afalg-core failed");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* hash && get result */
|
|
||||||
outv.iov_base = *result;
|
|
||||||
outv.iov_len = *resultlen;
|
|
||||||
ret = iov_send_recv(afalg->opfd, &outv, 1,
|
|
||||||
0, iov_size(&outv, 1), false);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_setg_errno(errp, errno, "Recv result from afalg-core failed");
|
|
||||||
} else {
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (!is_hmac) {
|
|
||||||
qcrypto_afalg_comm_free(afalg);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
qcrypto_afalg_hash_bytesv(QCryptoHashAlgo alg,
|
|
||||||
const struct iovec *iov,
|
|
||||||
size_t niov, uint8_t **result,
|
|
||||||
size_t *resultlen,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
return qcrypto_afalg_hash_hmac_bytesv(NULL, alg, iov, niov, result,
|
|
||||||
resultlen, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qcrypto_afalg_hmac_bytesv(QCryptoHmac *hmac,
|
qcrypto_afalg_hmac_bytesv(QCryptoHmac *hmac,
|
||||||
const struct iovec *iov,
|
const struct iovec *iov,
|
||||||
|
@ -204,7 +276,10 @@ static void qcrypto_afalg_hmac_ctx_free(QCryptoHmac *hmac)
|
||||||
}
|
}
|
||||||
|
|
||||||
QCryptoHashDriver qcrypto_hash_afalg_driver = {
|
QCryptoHashDriver qcrypto_hash_afalg_driver = {
|
||||||
.hash_bytesv = qcrypto_afalg_hash_bytesv,
|
.hash_new = qcrypto_afalg_hash_new,
|
||||||
|
.hash_free = qcrypto_afalg_hash_free,
|
||||||
|
.hash_update = qcrypto_afalg_hash_update,
|
||||||
|
.hash_finalize = qcrypto_afalg_hash_finalize
|
||||||
};
|
};
|
||||||
|
|
||||||
QCryptoHmacDriver qcrypto_hmac_afalg_driver = {
|
QCryptoHmacDriver qcrypto_hmac_afalg_driver = {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* QEMU Crypto hash algorithms
|
* QEMU Crypto hash algorithms
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
* Copyright (c) 2016 Red Hat, Inc.
|
* Copyright (c) 2016 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
|
@ -44,73 +45,84 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgo alg)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
static int
|
QCryptoHash *qcrypto_gcrypt_hash_new(QCryptoHashAlgo alg, Error **errp)
|
||||||
qcrypto_gcrypt_hash_bytesv(QCryptoHashAlgo alg,
|
|
||||||
const struct iovec *iov,
|
|
||||||
size_t niov,
|
|
||||||
uint8_t **result,
|
|
||||||
size_t *resultlen,
|
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
int i, ret;
|
QCryptoHash *hash;
|
||||||
gcry_md_hd_t md;
|
int ret;
|
||||||
unsigned char *digest;
|
|
||||||
|
|
||||||
if (!qcrypto_hash_supports(alg)) {
|
hash = g_new(QCryptoHash, 1);
|
||||||
error_setg(errp,
|
hash->alg = alg;
|
||||||
"Unknown hash algorithm %d",
|
hash->opaque = g_new(gcry_md_hd_t, 1);
|
||||||
alg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gcry_md_open(&md, qcrypto_hash_alg_map[alg], 0);
|
|
||||||
|
|
||||||
|
ret = gcry_md_open((gcry_md_hd_t *) hash->opaque,
|
||||||
|
qcrypto_hash_alg_map[alg], 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
"Unable to initialize hash algorithm: %s",
|
"Unable to initialize hash algorithm: %s",
|
||||||
gcry_strerror(ret));
|
gcry_strerror(ret));
|
||||||
return -1;
|
g_free(hash->opaque);
|
||||||
|
g_free(hash);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void qcrypto_gcrypt_hash_free(QCryptoHash *hash)
|
||||||
|
{
|
||||||
|
gcry_md_hd_t *ctx = hash->opaque;
|
||||||
|
|
||||||
|
if (ctx) {
|
||||||
|
gcry_md_close(*ctx);
|
||||||
|
g_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < niov; i++) {
|
g_free(hash);
|
||||||
gcry_md_write(md, iov[i].iov_base, iov[i].iov_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[alg]);
|
|
||||||
if (ret <= 0) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Unable to get hash length: %s",
|
|
||||||
gcry_strerror(ret));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (*resultlen == 0) {
|
|
||||||
*resultlen = ret;
|
|
||||||
*result = g_new0(uint8_t, *resultlen);
|
|
||||||
} else if (*resultlen != ret) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Result buffer size %zu is smaller than hash %d",
|
|
||||||
*resultlen, ret);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
digest = gcry_md_read(md, 0);
|
|
||||||
if (!digest) {
|
|
||||||
error_setg(errp,
|
|
||||||
"No digest produced");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
memcpy(*result, digest, *resultlen);
|
|
||||||
|
|
||||||
gcry_md_close(md);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
gcry_md_close(md);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_gcrypt_hash_update(QCryptoHash *hash,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
gcry_md_hd_t *ctx = hash->opaque;
|
||||||
|
|
||||||
|
for (int i = 0; i < niov; i++) {
|
||||||
|
gcry_md_write(*ctx, iov[i].iov_base, iov[i].iov_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_gcrypt_hash_finalize(QCryptoHash *hash,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *result_len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
unsigned char *digest;
|
||||||
|
gcry_md_hd_t *ctx = hash->opaque;
|
||||||
|
|
||||||
|
*result_len = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[hash->alg]);
|
||||||
|
if (*result_len == 0) {
|
||||||
|
error_setg(errp, "Unable to get hash length");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = g_new(uint8_t, *result_len);
|
||||||
|
|
||||||
|
/* Digest is freed by gcry_md_close(), copy it */
|
||||||
|
digest = gcry_md_read(*ctx, 0);
|
||||||
|
memcpy(*result, digest, *result_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
QCryptoHashDriver qcrypto_hash_lib_driver = {
|
QCryptoHashDriver qcrypto_hash_lib_driver = {
|
||||||
.hash_bytesv = qcrypto_gcrypt_hash_bytesv,
|
.hash_new = qcrypto_gcrypt_hash_new,
|
||||||
|
.hash_update = qcrypto_gcrypt_hash_update,
|
||||||
|
.hash_finalize = qcrypto_gcrypt_hash_finalize,
|
||||||
|
.hash_free = qcrypto_gcrypt_hash_free,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* QEMU Crypto hash algorithms
|
* QEMU Crypto hash algorithms
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
* Copyright (c) 2016 Red Hat, Inc.
|
* Copyright (c) 2016 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
|
@ -43,58 +44,71 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgo alg)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
static int
|
QCryptoHash *qcrypto_glib_hash_new(QCryptoHashAlgo alg,
|
||||||
qcrypto_glib_hash_bytesv(QCryptoHashAlgo alg,
|
Error **errp)
|
||||||
const struct iovec *iov,
|
|
||||||
size_t niov,
|
|
||||||
uint8_t **result,
|
|
||||||
size_t *resultlen,
|
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
int i, ret;
|
QCryptoHash *hash;
|
||||||
GChecksum *cs;
|
|
||||||
|
|
||||||
if (!qcrypto_hash_supports(alg)) {
|
hash = g_new(QCryptoHash, 1);
|
||||||
error_setg(errp,
|
hash->alg = alg;
|
||||||
"Unknown hash algorithm %d",
|
hash->opaque = g_checksum_new(qcrypto_hash_alg_map[alg]);
|
||||||
alg);
|
|
||||||
return -1;
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void qcrypto_glib_hash_free(QCryptoHash *hash)
|
||||||
|
{
|
||||||
|
if (hash->opaque) {
|
||||||
|
g_checksum_free(hash->opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
cs = g_checksum_new(qcrypto_hash_alg_map[alg]);
|
g_free(hash);
|
||||||
|
|
||||||
for (i = 0; i < niov; i++) {
|
|
||||||
g_checksum_update(cs, iov[i].iov_base, iov[i].iov_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = g_checksum_type_get_length(qcrypto_hash_alg_map[alg]);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_setg(errp, "%s",
|
|
||||||
"Unable to get hash length");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (*resultlen == 0) {
|
|
||||||
*resultlen = ret;
|
|
||||||
*result = g_new0(uint8_t, *resultlen);
|
|
||||||
} else if (*resultlen != ret) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Result buffer size %zu is smaller than hash %d",
|
|
||||||
*resultlen, ret);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_checksum_get_digest(cs, *result, resultlen);
|
|
||||||
|
|
||||||
g_checksum_free(cs);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
g_checksum_free(cs);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_glib_hash_update(QCryptoHash *hash,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
GChecksum *ctx = hash->opaque;
|
||||||
|
|
||||||
|
for (int i = 0; i < niov; i++) {
|
||||||
|
g_checksum_update(ctx, iov[i].iov_base, iov[i].iov_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_glib_hash_finalize(QCryptoHash *hash,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *result_len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
GChecksum *ctx = hash->opaque;
|
||||||
|
|
||||||
|
ret = g_checksum_type_get_length(qcrypto_hash_alg_map[hash->alg]);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Unable to get hash length");
|
||||||
|
*result_len = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result_len = ret;
|
||||||
|
*result = g_new(uint8_t, *result_len);
|
||||||
|
|
||||||
|
g_checksum_get_digest(ctx, *result, result_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
QCryptoHashDriver qcrypto_hash_lib_driver = {
|
QCryptoHashDriver qcrypto_hash_lib_driver = {
|
||||||
.hash_bytesv = qcrypto_glib_hash_bytesv,
|
.hash_new = qcrypto_glib_hash_new,
|
||||||
|
.hash_update = qcrypto_glib_hash_update,
|
||||||
|
.hash_finalize = qcrypto_glib_hash_finalize,
|
||||||
|
.hash_free = qcrypto_glib_hash_free,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* QEMU Crypto hash algorithms
|
* QEMU Crypto hash algorithms
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
* Copyright (c) 2021 Red Hat, Inc.
|
* Copyright (c) 2021 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
|
@ -52,53 +53,83 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgo alg)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
static int
|
QCryptoHash *qcrypto_gnutls_hash_new(QCryptoHashAlgo alg, Error **errp)
|
||||||
qcrypto_gnutls_hash_bytesv(QCryptoHashAlgo alg,
|
|
||||||
const struct iovec *iov,
|
|
||||||
size_t niov,
|
|
||||||
uint8_t **result,
|
|
||||||
size_t *resultlen,
|
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
int i, ret;
|
QCryptoHash *hash;
|
||||||
gnutls_hash_hd_t hash;
|
int ret;
|
||||||
|
|
||||||
if (!qcrypto_hash_supports(alg)) {
|
hash = g_new(QCryptoHash, 1);
|
||||||
error_setg(errp,
|
hash->alg = alg;
|
||||||
"Unknown hash algorithm %d",
|
hash->opaque = g_new(gnutls_hash_hd_t, 1);
|
||||||
alg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]);
|
ret = gnutls_hash_init(hash->opaque, qcrypto_hash_alg_map[alg]);
|
||||||
if (*resultlen == 0) {
|
|
||||||
*resultlen = ret;
|
|
||||||
*result = g_new0(uint8_t, *resultlen);
|
|
||||||
} else if (*resultlen != ret) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Result buffer size %zu is smaller than hash %d",
|
|
||||||
*resultlen, ret);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gnutls_hash_init(&hash, qcrypto_hash_alg_map[alg]);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
"Unable to initialize hash algorithm: %s",
|
"Unable to initialize hash algorithm: %s",
|
||||||
gnutls_strerror(ret));
|
gnutls_strerror(ret));
|
||||||
return -1;
|
g_free(hash->opaque);
|
||||||
|
g_free(hash);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < niov; i++) {
|
return hash;
|
||||||
gnutls_hash(hash, iov[i].iov_base, iov[i].iov_len);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
gnutls_hash_deinit(hash, *result);
|
static
|
||||||
return 0;
|
void qcrypto_gnutls_hash_free(QCryptoHash *hash)
|
||||||
|
{
|
||||||
|
gnutls_hash_hd_t *ctx = hash->opaque;
|
||||||
|
|
||||||
|
gnutls_hash_deinit(*ctx, NULL);
|
||||||
|
g_free(ctx);
|
||||||
|
g_free(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_gnutls_hash_update(QCryptoHash *hash,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
gnutls_hash_hd_t *ctx = hash->opaque;
|
||||||
|
|
||||||
|
for (int i = 0; i < niov; i++) {
|
||||||
|
ret = gnutls_hash(*ctx, iov[i].iov_base, iov[i].iov_len);
|
||||||
|
if (ret != 0) {
|
||||||
|
error_setg(errp, "Failed to hash data: %s",
|
||||||
|
gnutls_strerror(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_gnutls_hash_finalize(QCryptoHash *hash,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *result_len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
gnutls_hash_hd_t *ctx = hash->opaque;
|
||||||
|
|
||||||
|
*result_len = gnutls_hash_get_len(qcrypto_hash_alg_map[hash->alg]);
|
||||||
|
if (*result_len == 0) {
|
||||||
|
error_setg(errp, "Unable to get hash length");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = g_new(uint8_t, *result_len);
|
||||||
|
gnutls_hash_output(*ctx, *result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
QCryptoHashDriver qcrypto_hash_lib_driver = {
|
QCryptoHashDriver qcrypto_hash_lib_driver = {
|
||||||
.hash_bytesv = qcrypto_gnutls_hash_bytesv,
|
.hash_new = qcrypto_gnutls_hash_new,
|
||||||
|
.hash_update = qcrypto_gnutls_hash_update,
|
||||||
|
.hash_finalize = qcrypto_gnutls_hash_finalize,
|
||||||
|
.hash_free = qcrypto_gnutls_hash_free,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* QEMU Crypto hash algorithms
|
* QEMU Crypto hash algorithms
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
* Copyright (c) 2016 Red Hat, Inc.
|
* Copyright (c) 2016 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
|
@ -103,59 +104,64 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgo alg)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
static int
|
QCryptoHash *qcrypto_nettle_hash_new(QCryptoHashAlgo alg, Error **errp)
|
||||||
qcrypto_nettle_hash_bytesv(QCryptoHashAlgo alg,
|
|
||||||
const struct iovec *iov,
|
|
||||||
size_t niov,
|
|
||||||
uint8_t **result,
|
|
||||||
size_t *resultlen,
|
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
size_t i;
|
QCryptoHash *hash;
|
||||||
union qcrypto_hash_ctx ctx;
|
|
||||||
|
|
||||||
if (!qcrypto_hash_supports(alg)) {
|
hash = g_new(QCryptoHash, 1);
|
||||||
error_setg(errp,
|
hash->alg = alg;
|
||||||
"Unknown hash algorithm %d",
|
hash->opaque = g_new(union qcrypto_hash_ctx, 1);
|
||||||
alg);
|
|
||||||
return -1;
|
qcrypto_hash_alg_map[alg].init(hash->opaque);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void qcrypto_nettle_hash_free(QCryptoHash *hash)
|
||||||
|
{
|
||||||
|
union qcrypto_hash_ctx *ctx = hash->opaque;
|
||||||
|
|
||||||
|
g_free(ctx);
|
||||||
|
g_free(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_nettle_hash_update(QCryptoHash *hash,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
union qcrypto_hash_ctx *ctx = hash->opaque;
|
||||||
|
|
||||||
|
for (int i = 0; i < niov; i++) {
|
||||||
|
qcrypto_hash_alg_map[hash->alg].write(ctx,
|
||||||
|
iov[i].iov_len,
|
||||||
|
iov[i].iov_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
qcrypto_hash_alg_map[alg].init(&ctx);
|
|
||||||
|
|
||||||
for (i = 0; i < niov; i++) {
|
|
||||||
/* Some versions of nettle have functions
|
|
||||||
* declared with 'int' instead of 'size_t'
|
|
||||||
* so to be safe avoid writing more than
|
|
||||||
* UINT_MAX bytes at a time
|
|
||||||
*/
|
|
||||||
size_t len = iov[i].iov_len;
|
|
||||||
uint8_t *base = iov[i].iov_base;
|
|
||||||
while (len) {
|
|
||||||
size_t shortlen = MIN(len, UINT_MAX);
|
|
||||||
qcrypto_hash_alg_map[alg].write(&ctx, len, base);
|
|
||||||
len -= shortlen;
|
|
||||||
base += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*resultlen == 0) {
|
|
||||||
*resultlen = qcrypto_hash_alg_map[alg].len;
|
|
||||||
*result = g_new0(uint8_t, *resultlen);
|
|
||||||
} else if (*resultlen != qcrypto_hash_alg_map[alg].len) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Result buffer size %zu is smaller than hash %zu",
|
|
||||||
*resultlen, qcrypto_hash_alg_map[alg].len);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
qcrypto_hash_alg_map[alg].result(&ctx, *resultlen, *result);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int qcrypto_nettle_hash_finalize(QCryptoHash *hash,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *result_len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
union qcrypto_hash_ctx *ctx = hash->opaque;
|
||||||
|
|
||||||
|
*result_len = qcrypto_hash_alg_map[hash->alg].len;
|
||||||
|
*result = g_new(uint8_t, *result_len);
|
||||||
|
|
||||||
|
qcrypto_hash_alg_map[hash->alg].result(ctx, *result_len, *result);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
QCryptoHashDriver qcrypto_hash_lib_driver = {
|
QCryptoHashDriver qcrypto_hash_lib_driver = {
|
||||||
.hash_bytesv = qcrypto_nettle_hash_bytesv,
|
.hash_new = qcrypto_nettle_hash_new,
|
||||||
|
.hash_update = qcrypto_nettle_hash_update,
|
||||||
|
.hash_finalize = qcrypto_nettle_hash_finalize,
|
||||||
|
.hash_free = qcrypto_nettle_hash_free,
|
||||||
};
|
};
|
||||||
|
|
163
crypto/hash.c
163
crypto/hash.c
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* QEMU Crypto hash algorithms
|
* QEMU Crypto hash algorithms
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
* Copyright (c) 2015 Red Hat, Inc.
|
* Copyright (c) 2015 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
|
@ -19,6 +20,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qapi-types-crypto.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
#include "hashpriv.h"
|
#include "hashpriv.h"
|
||||||
|
|
||||||
|
@ -45,23 +48,18 @@ int qcrypto_hash_bytesv(QCryptoHashAlgo alg,
|
||||||
size_t *resultlen,
|
size_t *resultlen,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_AF_ALG
|
g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
|
||||||
int ret;
|
|
||||||
/*
|
|
||||||
* TODO:
|
|
||||||
* Maybe we should treat some afalg errors as fatal
|
|
||||||
*/
|
|
||||||
ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
|
|
||||||
result, resultlen,
|
|
||||||
NULL);
|
|
||||||
if (ret == 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return qcrypto_hash_lib_driver.hash_bytesv(alg, iov, niov,
|
if (!ctx) {
|
||||||
result, resultlen,
|
return -1;
|
||||||
errp);
|
}
|
||||||
|
|
||||||
|
if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
|
||||||
|
qcrypto_hash_finalize_bytes(ctx, result, resultlen, errp) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,29 +75,130 @@ int qcrypto_hash_bytes(QCryptoHashAlgo alg,
|
||||||
return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp);
|
return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int qcrypto_hash_updatev(QCryptoHash *hash,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoHashDriver *drv = hash->driver;
|
||||||
|
|
||||||
|
return drv->hash_update(hash, iov, niov, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_hash_update(QCryptoHash *hash,
|
||||||
|
const char *buf,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
|
||||||
|
|
||||||
|
return qcrypto_hash_updatev(hash, &iov, 1, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCryptoHash *qcrypto_hash_new(QCryptoHashAlgo alg, Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoHash *hash = NULL;
|
||||||
|
|
||||||
|
if (!qcrypto_hash_supports(alg)) {
|
||||||
|
error_setg(errp, "Unsupported hash algorithm %s",
|
||||||
|
QCryptoHashAlgo_str(alg));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_AF_ALG
|
||||||
|
hash = qcrypto_hash_afalg_driver.hash_new(alg, NULL);
|
||||||
|
if (hash) {
|
||||||
|
hash->driver = &qcrypto_hash_afalg_driver;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hash = qcrypto_hash_lib_driver.hash_new(alg, errp);
|
||||||
|
if (!hash) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash->driver = &qcrypto_hash_lib_driver;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qcrypto_hash_free(QCryptoHash *hash)
|
||||||
|
{
|
||||||
|
QCryptoHashDriver *drv;
|
||||||
|
|
||||||
|
if (hash) {
|
||||||
|
drv = hash->driver;
|
||||||
|
drv->hash_free(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_hash_finalize_bytes(QCryptoHash *hash,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *result_len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoHashDriver *drv = hash->driver;
|
||||||
|
|
||||||
|
return drv->hash_finalize(hash, result, result_len, errp);
|
||||||
|
}
|
||||||
|
|
||||||
static const char hex[] = "0123456789abcdef";
|
static const char hex[] = "0123456789abcdef";
|
||||||
|
|
||||||
|
int qcrypto_hash_finalize_digest(QCryptoHash *hash,
|
||||||
|
char **digest,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
g_autofree uint8_t *result = NULL;
|
||||||
|
size_t resultlen = 0;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp);
|
||||||
|
if (ret == 0) {
|
||||||
|
*digest = g_new0(char, (resultlen * 2) + 1);
|
||||||
|
for (i = 0 ; i < resultlen ; i++) {
|
||||||
|
(*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf];
|
||||||
|
(*digest)[(i * 2) + 1] = hex[result[i] & 0xf];
|
||||||
|
}
|
||||||
|
(*digest)[resultlen * 2] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_hash_finalize_base64(QCryptoHash *hash,
|
||||||
|
char **base64,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
g_autofree uint8_t *result = NULL;
|
||||||
|
size_t resultlen = 0;
|
||||||
|
|
||||||
|
ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp);
|
||||||
|
if (ret == 0) {
|
||||||
|
*base64 = g_base64_encode(result, resultlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int qcrypto_hash_digestv(QCryptoHashAlgo alg,
|
int qcrypto_hash_digestv(QCryptoHashAlgo alg,
|
||||||
const struct iovec *iov,
|
const struct iovec *iov,
|
||||||
size_t niov,
|
size_t niov,
|
||||||
char **digest,
|
char **digest,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
uint8_t *result = NULL;
|
g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
|
||||||
size_t resultlen = 0;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) {
|
if (!ctx) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*digest = g_new0(char, (resultlen * 2) + 1);
|
if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
|
||||||
for (i = 0 ; i < resultlen ; i++) {
|
qcrypto_hash_finalize_digest(ctx, digest, errp) < 0) {
|
||||||
(*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf];
|
return -1;
|
||||||
(*digest)[(i * 2) + 1] = hex[result[i] & 0xf];
|
|
||||||
}
|
}
|
||||||
(*digest)[resultlen * 2] = '\0';
|
|
||||||
g_free(result);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,15 +219,17 @@ int qcrypto_hash_base64v(QCryptoHashAlgo alg,
|
||||||
char **base64,
|
char **base64,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
uint8_t *result = NULL;
|
g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
|
||||||
size_t resultlen = 0;
|
|
||||||
|
|
||||||
if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) {
|
if (!ctx) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
|
||||||
|
qcrypto_hash_finalize_base64(ctx, base64, errp) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*base64 = g_base64_encode(result, resultlen);
|
|
||||||
g_free(result);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* QEMU Crypto hash driver supports
|
* QEMU Crypto hash driver supports
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
* Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
|
* Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
|
@ -15,15 +16,21 @@
|
||||||
#ifndef QCRYPTO_HASHPRIV_H
|
#ifndef QCRYPTO_HASHPRIV_H
|
||||||
#define QCRYPTO_HASHPRIV_H
|
#define QCRYPTO_HASHPRIV_H
|
||||||
|
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
|
||||||
typedef struct QCryptoHashDriver QCryptoHashDriver;
|
typedef struct QCryptoHashDriver QCryptoHashDriver;
|
||||||
|
|
||||||
struct QCryptoHashDriver {
|
struct QCryptoHashDriver {
|
||||||
int (*hash_bytesv)(QCryptoHashAlgo alg,
|
QCryptoHash *(*hash_new)(QCryptoHashAlgo alg, Error **errp);
|
||||||
|
int (*hash_update)(QCryptoHash *hash,
|
||||||
const struct iovec *iov,
|
const struct iovec *iov,
|
||||||
size_t niov,
|
size_t niov,
|
||||||
uint8_t **result,
|
|
||||||
size_t *resultlen,
|
|
||||||
Error **errp);
|
Error **errp);
|
||||||
|
int (*hash_finalize)(QCryptoHash *hash,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *resultlen,
|
||||||
|
Error **errp);
|
||||||
|
void (*hash_free)(QCryptoHash *hash);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern QCryptoHashDriver qcrypto_hash_lib_driver;
|
extern QCryptoHashDriver qcrypto_hash_lib_driver;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* QEMU Crypto hash algorithms
|
* QEMU Crypto hash algorithms
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
* Copyright (c) 2015 Red Hat, Inc.
|
* Copyright (c) 2015 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
|
@ -33,6 +34,13 @@
|
||||||
|
|
||||||
/* See also "QCryptoHashAlgo" defined in qapi/crypto.json */
|
/* See also "QCryptoHashAlgo" defined in qapi/crypto.json */
|
||||||
|
|
||||||
|
typedef struct QCryptoHash QCryptoHash;
|
||||||
|
struct QCryptoHash {
|
||||||
|
QCryptoHashAlgo alg;
|
||||||
|
void *opaque;
|
||||||
|
void *driver;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qcrypto_hash_supports:
|
* qcrypto_hash_supports:
|
||||||
* @alg: the hash algorithm
|
* @alg: the hash algorithm
|
||||||
|
@ -128,6 +136,117 @@ int qcrypto_hash_digestv(QCryptoHashAlgo alg,
|
||||||
char **digest,
|
char **digest,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_hash_updatev:
|
||||||
|
* @hash: hash object from qcrypto_hash_new
|
||||||
|
* @iov: the array of memory regions to hash
|
||||||
|
* @niov: the length of @iov
|
||||||
|
* @errp: pointer to a NULL-initialized error object
|
||||||
|
*
|
||||||
|
* Updates the given hash object with all the memory regions
|
||||||
|
* present in @iov.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
|
int qcrypto_hash_updatev(QCryptoHash *hash,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
Error **errp);
|
||||||
|
/**
|
||||||
|
* qcrypto_hash_update:
|
||||||
|
* @hash: hash object from qcrypto_hash_new
|
||||||
|
* @buf: the memory region to hash
|
||||||
|
* @len: the length of @buf
|
||||||
|
* @errp: pointer to a NULL-initialized error object
|
||||||
|
*
|
||||||
|
* Updates the given hash object with the data from
|
||||||
|
* the given buffer.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
|
int qcrypto_hash_update(QCryptoHash *hash,
|
||||||
|
const char *buf,
|
||||||
|
size_t len,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_hash_finalize_digest:
|
||||||
|
* @hash: the hash object to finalize
|
||||||
|
* @digest: pointer to hold output hash
|
||||||
|
* @errp: pointer to a NULL-initialized error object
|
||||||
|
*
|
||||||
|
* Computes the hash from the given hash object. Hash object
|
||||||
|
* is expected to have its data updated from the qcrypto_hash_update function.
|
||||||
|
* The @digest pointer will be filled with the printable hex digest of the
|
||||||
|
* computed hash, which will be terminated by '\0'. The memory pointer
|
||||||
|
* in @digest must be released with a call to g_free() when
|
||||||
|
* no longer required.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
|
int qcrypto_hash_finalize_digest(QCryptoHash *hash,
|
||||||
|
char **digest,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_hash_finalize_base64:
|
||||||
|
* @hash_ctx: hash object to finalize
|
||||||
|
* @base64: pointer to store the hash result in
|
||||||
|
* @errp: pointer to a NULL-initialized error object
|
||||||
|
*
|
||||||
|
* Computes the hash from the given hash object. Hash object
|
||||||
|
* is expected to have it's data updated from the qcrypto_hash_update function.
|
||||||
|
* The @base64 pointer will be filled with the base64 encoding of the computed
|
||||||
|
* hash, which will be terminated by '\0'. The memory pointer in @base64
|
||||||
|
* must be released with a call to g_free() when no longer required.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
|
int qcrypto_hash_finalize_base64(QCryptoHash *hash,
|
||||||
|
char **base64,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_hash_finalize_bytes:
|
||||||
|
* @hash_ctx: hash object to finalize
|
||||||
|
* @result: pointer to store the hash result in
|
||||||
|
* @result_len: Pointer to store the length of the result in
|
||||||
|
* @errp: pointer to a NULL-initialized error object
|
||||||
|
*
|
||||||
|
* Computes the hash from the given hash object. Hash object
|
||||||
|
* is expected to have it's data updated from the qcrypto_hash_update function.
|
||||||
|
* The memory pointer in @result must be released with a call to g_free()
|
||||||
|
* when no longer required.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
|
int qcrypto_hash_finalize_bytes(QCryptoHash *hash,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *result_len,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_hash_new:
|
||||||
|
* @alg: the hash algorithm
|
||||||
|
* @errp: pointer to a NULL-initialized error object
|
||||||
|
*
|
||||||
|
* Creates a new hashing context for the chosen algorithm for
|
||||||
|
* usage with qcrypto_hash_update.
|
||||||
|
*
|
||||||
|
* Returns: New hash object with the given algorithm, or NULL on error.
|
||||||
|
*/
|
||||||
|
QCryptoHash *qcrypto_hash_new(QCryptoHashAlgo alg, Error **errp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_hash_free:
|
||||||
|
* @hash: hash object to free
|
||||||
|
*
|
||||||
|
* Frees a hashing context for the chosen algorithm.
|
||||||
|
*/
|
||||||
|
void qcrypto_hash_free(QCryptoHash *hash);
|
||||||
|
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoHash, qcrypto_hash_free)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qcrypto_hash_digest:
|
* qcrypto_hash_digest:
|
||||||
* @alg: the hash algorithm
|
* @alg: the hash algorithm
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Helpers for using (partial) iovecs.
|
* Helpers for using (partial) iovecs.
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
* Copyright (C) 2010 Red Hat, Inc.
|
* Copyright (C) 2010 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
|
@ -75,6 +76,32 @@ iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
|
||||||
size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
|
size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
|
||||||
size_t offset, int fillc, size_t bytes);
|
size_t offset, int fillc, size_t bytes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send/recv data from/to iovec buffers directly, with the provided
|
||||||
|
* socket flags.
|
||||||
|
*
|
||||||
|
* `offset' bytes in the beginning of iovec buffer are skipped and
|
||||||
|
* next `bytes' bytes are used, which must be within data of iovec.
|
||||||
|
*
|
||||||
|
* r = iov_send_recv_with_flags(sockfd, sockflags, iov, iovcnt,
|
||||||
|
* offset, bytes, true);
|
||||||
|
*
|
||||||
|
* is logically equivalent to
|
||||||
|
*
|
||||||
|
* char *buf = malloc(bytes);
|
||||||
|
* iov_to_buf(iov, iovcnt, offset, buf, bytes);
|
||||||
|
* r = send(sockfd, buf, bytes, sockflags);
|
||||||
|
* free(buf);
|
||||||
|
*
|
||||||
|
* For iov_send_recv_with_flags() _whole_ area being sent or received
|
||||||
|
* should be within the iovec, not only beginning of it.
|
||||||
|
*/
|
||||||
|
ssize_t iov_send_recv_with_flags(int sockfd, int sockflags,
|
||||||
|
const struct iovec *iov,
|
||||||
|
unsigned iov_cnt, size_t offset,
|
||||||
|
size_t bytes,
|
||||||
|
bool do_send);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send/recv data from/to iovec buffers directly
|
* Send/recv data from/to iovec buffers directly
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* QEMU Crypto hash algorithms
|
* QEMU Crypto hash algorithms
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
* Copyright (c) 2015 Red Hat, Inc.
|
* Copyright (c) 2015 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
|
@ -241,6 +242,50 @@ static void test_hash_base64(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_hash_accumulate(void)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) {
|
||||||
|
g_autoptr(QCryptoHash) hash = NULL;
|
||||||
|
struct iovec iov[] = {
|
||||||
|
{ .iov_base = (char *)INPUT_TEXT1, .iov_len = strlen(INPUT_TEXT1) },
|
||||||
|
{ .iov_base = (char *)INPUT_TEXT2, .iov_len = strlen(INPUT_TEXT2) },
|
||||||
|
{ .iov_base = (char *)INPUT_TEXT3, .iov_len = strlen(INPUT_TEXT3) },
|
||||||
|
};
|
||||||
|
g_autofree uint8_t *result = NULL;
|
||||||
|
size_t resultlen = 0;
|
||||||
|
int ret;
|
||||||
|
size_t j;
|
||||||
|
|
||||||
|
if (!qcrypto_hash_supports(i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = qcrypto_hash_new(i, &error_fatal);
|
||||||
|
g_assert(hash != NULL);
|
||||||
|
|
||||||
|
/* Add each iovec to the hash context separately */
|
||||||
|
for (j = 0; j < G_N_ELEMENTS(iov); j++) {
|
||||||
|
ret = qcrypto_hash_updatev(hash,
|
||||||
|
&iov[j], 1,
|
||||||
|
&error_fatal);
|
||||||
|
|
||||||
|
g_assert(ret == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen,
|
||||||
|
&error_fatal);
|
||||||
|
|
||||||
|
g_assert(ret == 0);
|
||||||
|
g_assert(resultlen == expected_lens[i]);
|
||||||
|
for (j = 0; j < resultlen; j++) {
|
||||||
|
g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]);
|
||||||
|
g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ret = qcrypto_init(&error_fatal);
|
int ret = qcrypto_init(&error_fatal);
|
||||||
|
@ -252,5 +297,6 @@ int main(int argc, char **argv)
|
||||||
g_test_add_func("/crypto/hash/prealloc", test_hash_prealloc);
|
g_test_add_func("/crypto/hash/prealloc", test_hash_prealloc);
|
||||||
g_test_add_func("/crypto/hash/digest", test_hash_digest);
|
g_test_add_func("/crypto/hash/digest", test_hash_digest);
|
||||||
g_test_add_func("/crypto/hash/base64", test_hash_base64);
|
g_test_add_func("/crypto/hash/base64", test_hash_base64);
|
||||||
|
g_test_add_func("/crypto/hash/accumulate", test_hash_accumulate);
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -506,7 +506,7 @@ static void test_io_channel_unix_listen_cleanup(void)
|
||||||
{
|
{
|
||||||
QIOChannelSocket *ioc;
|
QIOChannelSocket *ioc;
|
||||||
struct sockaddr_un un;
|
struct sockaddr_un un;
|
||||||
int sock;
|
int sock, ret = 0;
|
||||||
|
|
||||||
#define TEST_SOCKET "test-io-channel-socket.sock"
|
#define TEST_SOCKET "test-io-channel-socket.sock"
|
||||||
|
|
||||||
|
@ -519,7 +519,9 @@ static void test_io_channel_unix_listen_cleanup(void)
|
||||||
un.sun_family = AF_UNIX;
|
un.sun_family = AF_UNIX;
|
||||||
snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET);
|
snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET);
|
||||||
unlink(TEST_SOCKET);
|
unlink(TEST_SOCKET);
|
||||||
bind(sock, (struct sockaddr *)&un, sizeof(un));
|
ret = bind(sock, (struct sockaddr *)&un, sizeof(un));
|
||||||
|
g_assert_cmpint(ret, ==, 0);
|
||||||
|
|
||||||
ioc->fd = sock;
|
ioc->fd = sock;
|
||||||
ioc->localAddrLen = sizeof(ioc->localAddr);
|
ioc->localAddrLen = sizeof(ioc->localAddr);
|
||||||
getsockname(sock, (struct sockaddr *)&ioc->localAddr,
|
getsockname(sock, (struct sockaddr *)&ioc->localAddr,
|
||||||
|
|
25
util/iov.c
25
util/iov.c
|
@ -3,6 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright IBM, Corp. 2007, 2008
|
* Copyright IBM, Corp. 2007, 2008
|
||||||
* Copyright (C) 2010 Red Hat, Inc.
|
* Copyright (C) 2010 Red Hat, Inc.
|
||||||
|
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* Anthony Liguori <aliguori@us.ibm.com>
|
* Anthony Liguori <aliguori@us.ibm.com>
|
||||||
|
@ -92,7 +93,8 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
|
||||||
|
|
||||||
/* helper function for iov_send_recv() */
|
/* helper function for iov_send_recv() */
|
||||||
static ssize_t
|
static ssize_t
|
||||||
do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
|
do_send_recv(int sockfd, int flags, struct iovec *iov, unsigned iov_cnt,
|
||||||
|
bool do_send)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_POSIX
|
#ifdef CONFIG_POSIX
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
@ -102,8 +104,8 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
|
||||||
msg.msg_iovlen = iov_cnt;
|
msg.msg_iovlen = iov_cnt;
|
||||||
do {
|
do {
|
||||||
ret = do_send
|
ret = do_send
|
||||||
? sendmsg(sockfd, &msg, 0)
|
? sendmsg(sockfd, &msg, flags)
|
||||||
: recvmsg(sockfd, &msg, 0);
|
: recvmsg(sockfd, &msg, flags);
|
||||||
} while (ret < 0 && errno == EINTR);
|
} while (ret < 0 && errno == EINTR);
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
#else
|
||||||
|
@ -114,8 +116,8 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
|
||||||
ssize_t off = 0;
|
ssize_t off = 0;
|
||||||
while (i < iov_cnt) {
|
while (i < iov_cnt) {
|
||||||
ssize_t r = do_send
|
ssize_t r = do_send
|
||||||
? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0)
|
? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, flags)
|
||||||
: recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0);
|
: recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, flags);
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
ret += r;
|
ret += r;
|
||||||
off += r;
|
off += r;
|
||||||
|
@ -144,6 +146,15 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
|
||||||
ssize_t iov_send_recv(int sockfd, const struct iovec *_iov, unsigned iov_cnt,
|
ssize_t iov_send_recv(int sockfd, const struct iovec *_iov, unsigned iov_cnt,
|
||||||
size_t offset, size_t bytes,
|
size_t offset, size_t bytes,
|
||||||
bool do_send)
|
bool do_send)
|
||||||
|
{
|
||||||
|
return iov_send_recv_with_flags(sockfd, 0, _iov, iov_cnt, offset, bytes,
|
||||||
|
do_send);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t iov_send_recv_with_flags(int sockfd, int sockflags,
|
||||||
|
const struct iovec *_iov,
|
||||||
|
unsigned iov_cnt, size_t offset,
|
||||||
|
size_t bytes, bool do_send)
|
||||||
{
|
{
|
||||||
ssize_t total = 0;
|
ssize_t total = 0;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
@ -192,11 +203,11 @@ ssize_t iov_send_recv(int sockfd, const struct iovec *_iov, unsigned iov_cnt,
|
||||||
assert(iov[niov].iov_len > tail);
|
assert(iov[niov].iov_len > tail);
|
||||||
orig_len = iov[niov].iov_len;
|
orig_len = iov[niov].iov_len;
|
||||||
iov[niov++].iov_len = tail;
|
iov[niov++].iov_len = tail;
|
||||||
ret = do_send_recv(sockfd, iov, niov, do_send);
|
ret = do_send_recv(sockfd, sockflags, iov, niov, do_send);
|
||||||
/* Undo the changes above before checking for errors */
|
/* Undo the changes above before checking for errors */
|
||||||
iov[niov-1].iov_len = orig_len;
|
iov[niov-1].iov_len = orig_len;
|
||||||
} else {
|
} else {
|
||||||
ret = do_send_recv(sockfd, iov, niov, do_send);
|
ret = do_send_recv(sockfd, sockflags, iov, niov, do_send);
|
||||||
}
|
}
|
||||||
if (offset) {
|
if (offset) {
|
||||||
iov[0].iov_base -= offset;
|
iov[0].iov_base -= offset;
|
||||||
|
|
Loading…
Reference in New Issue