Message ID | 1492392806-53720-14-git-send-email-longpeng2@huawei.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
> -----Original Message----- > From: longpeng > Sent: Monday, April 17, 2017 9:33 AM > To: berrange@redhat.com > Cc: Gonglei (Arei); Huangweidong (C); armbru@redhat.com; > eblake@redhat.com; mst@redhat.com; qemu-devel@nongnu.org; longpeng > Subject: [PATCH v2 for-2.10 13/18] crypto: cipher: add afalg-backend cipher > support > > Adds afalg-backend cipher support: introduces some private APIs > firstly, and then intergrates them into qcrypto_cipher_afalg_driver. > > Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com> > --- > crypto/Makefile.objs | 1 + > crypto/afalgpriv.h | 9 ++ > crypto/cipher-afalg.c | 225 > +++++++++++++++++++++++++++++++++++++++++++++ > crypto/cipher.c | 28 +++++- > crypto/cipherpriv.h | 11 +++ > include/crypto/cipher.h | 8 ++ > tests/test-crypto-cipher.c | 10 +- > 7 files changed, 290 insertions(+), 2 deletions(-) > create mode 100644 crypto/cipher-afalg.c > > diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs > index 2be5a3a..d2e8fa8 100644 > --- a/crypto/Makefile.objs > +++ b/crypto/Makefile.objs > @@ -11,6 +11,7 @@ crypto-obj-y += aes.o > crypto-obj-y += desrfb.o > crypto-obj-y += cipher.o > crypto-obj-$(CONFIG_AF_ALG) += afalg.o > +crypto-obj-$(CONFIG_AF_ALG) += cipher-afalg.o > crypto-obj-y += tlscreds.o > crypto-obj-y += tlscredsanon.o > crypto-obj-y += tlscredsx509.o > diff --git a/crypto/afalgpriv.h b/crypto/afalgpriv.h > index 155130b..7db0597 100644 > --- a/crypto/afalgpriv.h > +++ b/crypto/afalgpriv.h > @@ -19,6 +19,15 @@ > #define SALG_TYPE_LEN_MAX 14 > #define SALG_NAME_LEN_MAX 64 > > +#ifndef SOL_ALG > +#define SOL_ALG 279 > +#endif > + > +#define AFALG_TYPE_CIPHER "skcipher" > + > +#define ALG_OPTYPE_LEN 4 > +#define ALG_MSGIV_LEN(len) (sizeof(struct af_alg_iv) + (len)) > + > typedef struct QCryptoAFAlg QCryptoAFAlg; > > struct QCryptoAFAlg { > diff --git a/crypto/cipher-afalg.c b/crypto/cipher-afalg.c > new file mode 100644 > index 0000000..a2b2f53 > --- /dev/null > +++ b/crypto/cipher-afalg.c > @@ -0,0 +1,225 @@ > +/* > + * QEMU Crypto af_alg-backend cipher support > + * > + * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD. > + * > + * Authors: > + * Longpeng(Mike) <longpeng2@huawei.com> > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or > + * (at your option) any later version. See the COPYING file in the > + * top-level directory. > + */ > +#include "qemu/osdep.h" > +#include "qemu/sockets.h" > +#include "qemu-common.h" > +#include "qapi/error.h" > +#include "crypto/cipher.h" > +#include "cipherpriv.h" > + > + > +static char * > +qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg, > + QCryptoCipherMode mode, > + Error **errp) > +{ > + char *name; > + const char *alg_name = NULL; > + const char *mode_name = NULL; Superfluous initialization. > + int ret; > + > + switch (alg) { > + case QCRYPTO_CIPHER_ALG_AES_128: > + case QCRYPTO_CIPHER_ALG_AES_192: > + case QCRYPTO_CIPHER_ALG_AES_256: > + alg_name = "aes"; > + break; > + case QCRYPTO_CIPHER_ALG_CAST5_128: > + alg_name = "cast5"; > + break; > + case QCRYPTO_CIPHER_ALG_SERPENT_128: > + case QCRYPTO_CIPHER_ALG_SERPENT_192: > + case QCRYPTO_CIPHER_ALG_SERPENT_256: > + alg_name = "serpent"; > + break; > + case QCRYPTO_CIPHER_ALG_TWOFISH_128: > + case QCRYPTO_CIPHER_ALG_TWOFISH_192: > + case QCRYPTO_CIPHER_ALG_TWOFISH_256: > + alg_name = "twofish"; > + break; > + > + default: > + error_setg(errp, "Unsupported cipher algorithm %d", alg); > + return NULL; > + } > + > + mode_name = QCryptoCipherMode_lookup[mode]; > + > + name = (char *)g_new0(int8_t, SALG_NAME_LEN_MAX); s/ (char *)g_new0(int8_t, SALG_NAME_LEN_MAX)/g_new0(char, SALG_NAME_LEN_MAX)/ > + ret = snprintf(name, SALG_NAME_LEN_MAX, "%s(%s)", mode_name, > + alg_name); > + if (ret < 0 || ret >= SALG_NAME_LEN_MAX) { > + error_setg(errp, "Build ciphername(name='%s',mode='%s') failed", > + alg_name, mode_name); > + g_free(name); > + return NULL; > + } > + > + return name; > +} > + > +QCryptoAFAlg * > +qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg, > + QCryptoCipherMode mode, > + const uint8_t *key, > + size_t nkey, Error **errp) > +{ > + QCryptoAFAlg *afalg; > + size_t except_niv = 0; Doesn't need to initialize it. > + char *name; > + > + name = qcrypto_afalg_cipher_format_name(alg, mode, errp); > + if (!name) { > + return NULL; > + } > + > + afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp); > + if (!afalg) { > + goto error; Leak memory pointed by name. > + } > + > + /* setkey */ > + if (qemu_setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, key, > + nkey) != 0) { > + error_setg_errno(errp, errno, "Set key failed"); > + goto error; Leak memory pointed by name. > + } > + > + /* prepare msg header */ > + afalg->msg = g_new0(struct msghdr, 1); > + afalg->msg->msg_controllen += CMSG_SPACE(ALG_OPTYPE_LEN); > + except_niv = qcrypto_cipher_get_iv_len(alg, mode); > + if (except_niv) { > + afalg->msg->msg_controllen += > CMSG_SPACE(ALG_MSGIV_LEN(except_niv)); > + } > + afalg->msg->msg_control = g_new0(uint8_t, > afalg->msg->msg_controllen); > + > + /* We use 1st msghdr for crypto-info and 2nd msghdr for IV-info */ > + afalg->cmsg = CMSG_FIRSTHDR(afalg->msg); > + afalg->cmsg->cmsg_level = SOL_ALG; > + afalg->cmsg->cmsg_type = ALG_SET_OP; > + afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_OPTYPE_LEN); > + > +cleanup: > + g_free(name); > + return afalg; > + > +error: > + qcrypto_afalg_comm_free(afalg); > + afalg = NULL; > + goto cleanup; > +} > + > +static int > +qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher, > + const uint8_t *iv, > + size_t niv, Error **errp) > +{ > + struct af_alg_iv *alg_iv = NULL; Superfluous initialization. > + QCryptoAFAlg *afalg = cipher->opaque; > + > + /* move ->cmsg to next msghdr, for IV-info */ > + afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg); > + > + /* build setiv msg */ > + afalg->cmsg->cmsg_level = SOL_ALG; > + afalg->cmsg->cmsg_type = ALG_SET_IV; > + afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_MSGIV_LEN(niv)); > + alg_iv = (struct af_alg_iv *)CMSG_DATA(afalg->cmsg); > + alg_iv->ivlen = niv; > + memcpy(alg_iv->iv, iv, niv); Is it possible trigger memory overflow by vicious attacks ? > + > + return 0; > +} > + > +static int > +qcrypto_afalg_cipher_op(QCryptoAFAlg *afalg, > + const void *in, void *out, > + size_t len, bool do_encrypt, > + Error **errp) > +{ > + uint32_t *type = NULL; > + struct iovec iov; > + size_t ret, done = 0; > + uint32_t origin_contorllen; > + > + origin_contorllen = afalg->msg->msg_controllen; > + /* movev ->cmsg to first header, for crypto-info */ > + afalg->cmsg = CMSG_FIRSTHDR(afalg->msg); > + > + /* build encrypt msg */ > + afalg->msg->msg_iov = &iov; > + afalg->msg->msg_iovlen = 1; > + type = (uint32_t *)CMSG_DATA(afalg->cmsg); > + if (do_encrypt) { > + *type = ALG_OP_ENCRYPT; > + } else { > + *type = ALG_OP_DECRYPT; > + } > + > + do { > + iov.iov_base = (void *)in + done; > + iov.iov_len = len - done; > + > + /* send info to AF_ALG core */ > + ret = sendmsg(afalg->opfd, afalg->msg, 0); > + if (ret == -1) { > + error_setg_errno(errp, errno, "Send data to AF_ALG core > failed"); > + return -1; > + } > + > + /* encrypto && get result */ > + if (ret != read(afalg->opfd, out, ret)) { > + error_setg_errno(errp, errno, "Get result from AF_ALG core > failed"); > + return -1; > + } > + > + /* do not update IV for following chunks */ > + afalg->msg->msg_controllen = 0; > + done += ret; > + } while (done < len); > + > + afalg->msg->msg_controllen = origin_contorllen; > + > + return 0; > +} > + > +static int > +qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher, > + const void *in, void *out, > + size_t len, Error **errp) > +{ > + return qcrypto_afalg_cipher_op(cipher->opaque, in, out, > + len, true, errp); > +} > + > +static int > +qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher, > + const void *in, void *out, > + size_t len, Error **errp) > +{ > + return qcrypto_afalg_cipher_op(cipher->opaque, in, out, > + len, false, errp); > +} > + > +static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher) > +{ > + qcrypto_afalg_comm_free(cipher->opaque); > +} > + > +struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = { > + .cipher_encrypt = qcrypto_afalg_cipher_encrypt, > + .cipher_decrypt = qcrypto_afalg_cipher_decrypt, > + .cipher_setiv = qcrypto_afalg_cipher_setiv, > + .cipher_free = qcrypto_afalg_comm_ctx_free, > +}; > diff --git a/crypto/cipher.c b/crypto/cipher.c > index a6e052c..4a6f548 100644 > --- a/crypto/cipher.c > +++ b/crypto/cipher.c > @@ -164,17 +164,34 @@ QCryptoCipher > *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, > { > QCryptoCipher *cipher; > void *ctx; > + Error *err2 = NULL; > + QCryptoCipherDriver *drv; > + > +#ifdef CONFIG_AF_ALG > + ctx = qcrypto_afalg_cipher_ctx_new(alg, mode, key, nkey, &err2); > + if (ctx) { > + drv = &qcrypto_cipher_afalg_driver; > + goto set_cipher; > + } > +#endif > > ctx = qcrypto_cipher_ctx_new(alg, mode, key, nkey, errp); > if (ctx == NULL) { > + error_free(err2); > return NULL; > } > > + drv = &qcrypto_cipher_lib_driver; > + error_free(err2); > + > +#ifdef CONFIG_AF_ALG > +set_cipher: > +#endif > cipher = g_new0(QCryptoCipher, 1); > cipher->alg = alg; > cipher->mode = mode; > cipher->opaque = ctx; > - cipher->driver = (void *)&qcrypto_cipher_lib_driver; > + cipher->driver = (void *)drv; > > return cipher; > } > @@ -220,3 +237,12 @@ void qcrypto_cipher_free(QCryptoCipher *cipher) > g_free(cipher); > } > } > + > +bool qcrypto_cipher_using_afalg_drv(QCryptoCipher *cipher) > +{ > +#ifdef CONFIG_AF_ALG > + return cipher->driver == (void *)&qcrypto_cipher_afalg_driver; > +#else > + return false; > +#endif > +} > diff --git a/crypto/cipherpriv.h b/crypto/cipherpriv.h > index 4af5e85..91c6a7e 100644 > --- a/crypto/cipherpriv.h > +++ b/crypto/cipherpriv.h > @@ -15,6 +15,9 @@ > #ifndef QCRYPTO_CIPHERPRIV_H > #define QCRYPTO_CIPHERPRIV_H > > +#include "qapi-types.h" > +#include "afalgpriv.h" > + > typedef struct QCryptoCipherDriver QCryptoCipherDriver; > > struct QCryptoCipherDriver { > @@ -37,4 +40,12 @@ struct QCryptoCipherDriver { > void (*cipher_free)(QCryptoCipher *cipher); > }; > > +extern QCryptoAFAlg * > +qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg, > + QCryptoCipherMode mode, > + const uint8_t *key, > + size_t nkey, Error **errp); > + > +extern struct QCryptoCipherDriver qcrypto_cipher_afalg_driver; > + > #endif > diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h > index 984fb82..037f602 100644 > --- a/include/crypto/cipher.h > +++ b/include/crypto/cipher.h > @@ -233,4 +233,12 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher, > const uint8_t *iv, size_t niv, > Error **errp); > > +/** > + * qcrypto_cipher_using_afalg_drv: > + * @ the cipher object > + * > + * Returns: true if @cipher is using afalg driver, otherwise false. > + */ > +bool qcrypto_cipher_using_afalg_drv(QCryptoCipher *cipher); > + > #endif /* QCRYPTO_CIPHER_H */ > diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c > index 07fa2fa..8bb3308 100644 > --- a/tests/test-crypto-cipher.c > +++ b/tests/test-crypto-cipher.c > @@ -715,6 +715,7 @@ static void test_cipher_null_iv(void) > uint8_t key[32] = { 0 }; > uint8_t plaintext[32] = { 0 }; > uint8_t ciphertext[32] = { 0 }; > + Error *err = NULL; > > cipher = qcrypto_cipher_new( > QCRYPTO_CIPHER_ALG_AES_256, > @@ -729,7 +730,14 @@ static void test_cipher_null_iv(void) > plaintext, > ciphertext, > sizeof(plaintext), > - &error_abort); > + &err); > + > + if (qcrypto_cipher_using_afalg_drv(cipher)) { > + g_assert(err != NULL); > + error_free_or_abort(&err); > + } else { > + g_assert(err == NULL); > + } > > qcrypto_cipher_free(cipher); > } > -- > 1.8.3.1 >
On 2017/4/21 20:59, Gonglei (Arei) wrote: > >> -----Original Message----- >> From: longpeng >> Sent: Monday, April 17, 2017 9:33 AM >> To: berrange@redhat.com >> Cc: Gonglei (Arei); Huangweidong (C); armbru@redhat.com; >> eblake@redhat.com; mst@redhat.com; qemu-devel@nongnu.org; longpeng >> Subject: [PATCH v2 for-2.10 13/18] crypto: cipher: add afalg-backend cipher >> support >> >> Adds afalg-backend cipher support: introduces some private APIs >> firstly, and then intergrates them into qcrypto_cipher_afalg_driver. >> >> Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com> >> --- >> crypto/Makefile.objs | 1 + >> crypto/afalgpriv.h | 9 ++ >> crypto/cipher-afalg.c | 225 >> +++++++++++++++++++++++++++++++++++++++++++++ >> crypto/cipher.c | 28 +++++- >> crypto/cipherpriv.h | 11 +++ >> include/crypto/cipher.h | 8 ++ >> tests/test-crypto-cipher.c | 10 +- >> 7 files changed, 290 insertions(+), 2 deletions(-) >> create mode 100644 crypto/cipher-afalg.c >> + >> +static char * >> +qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg, >> + QCryptoCipherMode mode, >> + Error **errp) >> +{ >> + char *name; >> + const char *alg_name = NULL; >> + const char *mode_name = NULL; > > Superfluous initialization. Ok. > >> + int ret; >> + >> + >> + mode_name = QCryptoCipherMode_lookup[mode]; >> + >> + name = (char *)g_new0(int8_t, SALG_NAME_LEN_MAX); > > s/ (char *)g_new0(int8_t, SALG_NAME_LEN_MAX)/g_new0(char, SALG_NAME_LEN_MAX)/ > Ok. > >> + ret = snprintf(name, SALG_NAME_LEN_MAX, "%s(%s)", mode_name, >> + alg_name); >> + if (ret < 0 || ret >= SALG_NAME_LEN_MAX) { >> + >> +QCryptoAFAlg * >> +qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg, >> + QCryptoCipherMode mode, >> + const uint8_t *key, >> + size_t nkey, Error **errp) >> +{ >> + QCryptoAFAlg *afalg; >> + size_t except_niv = 0; > > Doesn't need to initialize it. > Ok. >> + char *name; >> + >> + name = qcrypto_afalg_cipher_format_name(alg, mode, errp); >> + if (!name) { >> + return NULL; >> + } >> + >> + afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp); >> + if (!afalg) { >> + goto error; > > Leak memory pointed by name. > It won't. If failed, the control flow is error->cleanup->return, and 'name' will be freed in 'cleanup'. If this method success, then the control flow is cleanup->return, 'name' will also be freed. >> + } >> + >> + /* setkey */ >> + if (qemu_setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, key, >> + nkey) != 0) { >> + error_setg_errno(errp, errno, "Set key failed"); >> + goto error; > > Leak memory pointed by name. > As above. >> + } >> + >> + /* prepare msg header */ >> + afalg->msg = g_new0(struct msghdr, 1); >> + afalg->msg->msg_controllen += CMSG_SPACE(ALG_OPTYPE_LEN); >> + except_niv = qcrypto_cipher_get_iv_len(alg, mode); >> + if (except_niv) { >> + afalg->msg->msg_controllen += >> CMSG_SPACE(ALG_MSGIV_LEN(except_niv)); >> + } >> + afalg->msg->msg_control = g_new0(uint8_t, >> afalg->msg->msg_controllen); >> + >> + /* We use 1st msghdr for crypto-info and 2nd msghdr for IV-info */ >> + afalg->cmsg = CMSG_FIRSTHDR(afalg->msg); >> + afalg->cmsg->cmsg_level = SOL_ALG; >> + afalg->cmsg->cmsg_type = ALG_SET_OP; >> + afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_OPTYPE_LEN); >> + >> +cleanup: >> + g_free(name); >> + return afalg; >> + >> +error: >> + qcrypto_afalg_comm_free(afalg); >> + afalg = NULL; >> + goto cleanup; >> +} >> + >> +static int >> +qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher, >> + const uint8_t *iv, >> + size_t niv, Error **errp) >> +{ >> + struct af_alg_iv *alg_iv = NULL; > > Superfluous initialization. > Ok. >> + QCryptoAFAlg *afalg = cipher->opaque; >> + >> + /* move ->cmsg to next msghdr, for IV-info */ >> + afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg); >> + >> + /* build setiv msg */ >> + afalg->cmsg->cmsg_level = SOL_ALG; >> + afalg->cmsg->cmsg_type = ALG_SET_IV; >> + afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_MSGIV_LEN(niv)); >> + alg_iv = (struct af_alg_iv *)CMSG_DATA(afalg->cmsg); >> + alg_iv->ivlen = niv; >> + memcpy(alg_iv->iv, iv, niv); > > Is it possible trigger memory overflow by vicious attacks ? Oh, it's possible for a virtio-crypto user. I'll check the 'niv' in v3. Thanks. >> + >> + return 0; >> +} >> + >> +static int >> +qcrypto_afalg_cipher_op(QCryptoAFAlg *afalg, >> + const void *in, void *out, >> + size_t len, bool do_encrypt, >> + Error **errp) >> +{ >> + uint32_t *type = NULL; >> + struct iovec iov; >> + size_t ret, done = 0; >> + uint32_t origin_contorllen; >> + >> + origin_contorllen = afalg->msg->msg_controllen; >> + /* movev ->cmsg to first header, for crypto-info */ >> + afalg->cmsg = CMSG_FIRSTHDR(afalg->msg); >> + >> + /* build encrypt msg */ >> + afalg->msg->msg_iov = &iov; >> + afalg->msg->msg_iovlen = 1; >> + type = (uint32_t *)CMSG_DATA(afalg->cmsg); >> + if (do_encrypt) { >> + *type = ALG_OP_ENCRYPT; >> + } else { >> + *type = ALG_OP_DECRYPT; >> + } >> + >> + do { >> + iov.iov_base = (void *)in + done; >> + iov.iov_len = len - done; >> + >> + /* send info to AF_ALG core */ >> + ret = sendmsg(afalg->opfd, afalg->msg, 0); >> + if (ret == -1) { >> + error_setg_errno(errp, errno, "Send data to AF_ALG core >> failed"); >> + return -1; >> + } >> + >> + /* encrypto && get result */ >> + if (ret != read(afalg->opfd, out, ret)) { >> + error_setg_errno(errp, errno, "Get result from AF_ALG core >> failed"); >> + return -1; >> + } >> + >> + /* do not update IV for following chunks */ >> + afalg->msg->msg_controllen = 0; >> + done += ret; >> + } while (done < len); >> + >> + afalg->msg->msg_controllen = origin_contorllen; >> + >> + return 0; >> +} >> + >> +static int >> +qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher, >> + const void *in, void *out, >> + size_t len, Error **errp) >> +{ >> + return qcrypto_afalg_cipher_op(cipher->opaque, in, out, >> + len, true, errp); >> +} >> + >> +static int >> +qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher, >> + const void *in, void *out, >> + size_t len, Error **errp) >> +{ >> + return qcrypto_afalg_cipher_op(cipher->opaque, in, out, >> + len, false, errp); >> +} >> + >> +static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher) >> +{ >> + qcrypto_afalg_comm_free(cipher->opaque); >> +} >> + >> +struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = { >> + .cipher_encrypt = qcrypto_afalg_cipher_encrypt, >> + .cipher_decrypt = qcrypto_afalg_cipher_decrypt, >> + .cipher_setiv = qcrypto_afalg_cipher_setiv, >> + .cipher_free = qcrypto_afalg_comm_ctx_free, >> +}; >> diff --git a/crypto/cipher.c b/crypto/cipher.c >> index a6e052c..4a6f548 100644 >> --- a/crypto/cipher.c >> +++ b/crypto/cipher.c >> @@ -164,17 +164,34 @@ QCryptoCipher >> *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, >> { >> QCryptoCipher *cipher; >> void *ctx; >> + Error *err2 = NULL; >> + QCryptoCipherDriver *drv; >> + >> +#ifdef CONFIG_AF_ALG >> + ctx = qcrypto_afalg_cipher_ctx_new(alg, mode, key, nkey, &err2); >> + if (ctx) { >> + drv = &qcrypto_cipher_afalg_driver; >> + goto set_cipher; >> + } >> +#endif >> >> ctx = qcrypto_cipher_ctx_new(alg, mode, key, nkey, errp); >> if (ctx == NULL) { >> + error_free(err2); >> return NULL; >> } >> >> + drv = &qcrypto_cipher_lib_driver; >> + error_free(err2); >> + >> +#ifdef CONFIG_AF_ALG >> +set_cipher: >> +#endif >> cipher = g_new0(QCryptoCipher, 1); >> cipher->alg = alg; >> cipher->mode = mode; >> cipher->opaque = ctx; >> - cipher->driver = (void *)&qcrypto_cipher_lib_driver; >> + cipher->driver = (void *)drv; >> >> return cipher; >> } >> @@ -220,3 +237,12 @@ void qcrypto_cipher_free(QCryptoCipher *cipher) >> g_free(cipher); >> } >> } >> + >> +bool qcrypto_cipher_using_afalg_drv(QCryptoCipher *cipher) >> +{ >> +#ifdef CONFIG_AF_ALG >> + return cipher->driver == (void *)&qcrypto_cipher_afalg_driver; >> +#else >> + return false; >> +#endif >> +} >> diff --git a/crypto/cipherpriv.h b/crypto/cipherpriv.h >> index 4af5e85..91c6a7e 100644 >> --- a/crypto/cipherpriv.h >> +++ b/crypto/cipherpriv.h >> @@ -15,6 +15,9 @@ >> #ifndef QCRYPTO_CIPHERPRIV_H >> #define QCRYPTO_CIPHERPRIV_H >> >> +#include "qapi-types.h" >> +#include "afalgpriv.h" >> + >> typedef struct QCryptoCipherDriver QCryptoCipherDriver; >> >> struct QCryptoCipherDriver { >> @@ -37,4 +40,12 @@ struct QCryptoCipherDriver { >> void (*cipher_free)(QCryptoCipher *cipher); >> }; >> >> +extern QCryptoAFAlg * >> +qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg, >> + QCryptoCipherMode mode, >> + const uint8_t *key, >> + size_t nkey, Error **errp); >> + >> +extern struct QCryptoCipherDriver qcrypto_cipher_afalg_driver; >> + >> #endif >> diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h >> index 984fb82..037f602 100644 >> --- a/include/crypto/cipher.h >> +++ b/include/crypto/cipher.h >> @@ -233,4 +233,12 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher, >> const uint8_t *iv, size_t niv, >> Error **errp); >> >> +/** >> + * qcrypto_cipher_using_afalg_drv: >> + * @ the cipher object >> + * >> + * Returns: true if @cipher is using afalg driver, otherwise false. >> + */ >> +bool qcrypto_cipher_using_afalg_drv(QCryptoCipher *cipher); >> + >> #endif /* QCRYPTO_CIPHER_H */ >> diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c >> index 07fa2fa..8bb3308 100644 >> --- a/tests/test-crypto-cipher.c >> +++ b/tests/test-crypto-cipher.c >> @@ -715,6 +715,7 @@ static void test_cipher_null_iv(void) >> uint8_t key[32] = { 0 }; >> uint8_t plaintext[32] = { 0 }; >> uint8_t ciphertext[32] = { 0 }; >> + Error *err = NULL; >> >> cipher = qcrypto_cipher_new( >> QCRYPTO_CIPHER_ALG_AES_256, >> @@ -729,7 +730,14 @@ static void test_cipher_null_iv(void) >> plaintext, >> ciphertext, >> sizeof(plaintext), >> - &error_abort); >> + &err); >> + >> + if (qcrypto_cipher_using_afalg_drv(cipher)) { >> + g_assert(err != NULL); >> + error_free_or_abort(&err); >> + } else { >> + g_assert(err == NULL); >> + } >> >> qcrypto_cipher_free(cipher); >> } >> -- >> 1.8.3.1 >> > > . >
> > > On 2017/4/21 20:59, Gonglei (Arei) wrote: > > > > >> -----Original Message----- > >> From: longpeng > >> Sent: Monday, April 17, 2017 9:33 AM > >> To: berrange@redhat.com > >> Cc: Gonglei (Arei); Huangweidong (C); armbru@redhat.com; > >> eblake@redhat.com; mst@redhat.com; qemu-devel@nongnu.org; > longpeng > >> Subject: [PATCH v2 for-2.10 13/18] crypto: cipher: add afalg-backend cipher > >> support > >> > >> Adds afalg-backend cipher support: introduces some private APIs > >> firstly, and then intergrates them into qcrypto_cipher_afalg_driver. > >> > >> Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com> > >> --- > >> crypto/Makefile.objs | 1 + > >> crypto/afalgpriv.h | 9 ++ > >> crypto/cipher-afalg.c | 225 > >> +++++++++++++++++++++++++++++++++++++++++++++ > >> crypto/cipher.c | 28 +++++- > >> crypto/cipherpriv.h | 11 +++ > >> include/crypto/cipher.h | 8 ++ > >> tests/test-crypto-cipher.c | 10 +- > >> 7 files changed, 290 insertions(+), 2 deletions(-) > >> create mode 100644 crypto/cipher-afalg.c > > >> + > >> +static char * > >> +qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg, > >> + QCryptoCipherMode mode, > >> + Error **errp) > >> +{ > >> + char *name; > >> + const char *alg_name = NULL; > >> + const char *mode_name = NULL; > > > > Superfluous initialization. > > > Ok. > > > > >> + int ret; > >> + > > >> + > >> + mode_name = QCryptoCipherMode_lookup[mode]; > >> + > >> + name = (char *)g_new0(int8_t, SALG_NAME_LEN_MAX); > > > > s/ (char *)g_new0(int8_t, SALG_NAME_LEN_MAX)/g_new0(char, > SALG_NAME_LEN_MAX)/ > > > > > Ok. > > > > >> + ret = snprintf(name, SALG_NAME_LEN_MAX, "%s(%s)", mode_name, > >> + alg_name); > >> + if (ret < 0 || ret >= SALG_NAME_LEN_MAX) { > > >> + > >> +QCryptoAFAlg * > >> +qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg, > >> + QCryptoCipherMode mode, > >> + const uint8_t *key, > >> + size_t nkey, Error **errp) > >> +{ > >> + QCryptoAFAlg *afalg; > >> + size_t except_niv = 0; > > > > Doesn't need to initialize it. > > > > > Ok. > > >> + char *name; > >> + > >> + name = qcrypto_afalg_cipher_format_name(alg, mode, errp); > >> + if (!name) { > >> + return NULL; > >> + } > >> + > >> + afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp); > >> + if (!afalg) { > >> + goto error; > > > > Leak memory pointed by name. > > > > > It won't. > > If failed, the control flow is error->cleanup->return, and 'name' will be freed > in 'cleanup'. > > If this method success, then the control flow is cleanup->return, 'name' will > also be freed. > I see. I suggest you can store the name pointer in afalg, then its easily to free it in qcrypto_afalg_comm_free(), and we can get enough information about the alg/mode if needed. Thanks, -Gonglei
On 2017/4/22 9:51, Gonglei (Arei) wrote: >> >> >> On 2017/4/21 20:59, Gonglei (Arei) wrote: >> >>> >>>> -----Original Message----- >>>> From: longpeng >>>> Sent: Monday, April 17, 2017 9:33 AM >>>> To: berrange@redhat.com >>>> Cc: Gonglei (Arei); Huangweidong (C); armbru@redhat.com; >>>> eblake@redhat.com; mst@redhat.com; qemu-devel@nongnu.org; >> longpeng >>>> Subject: [PATCH v2 for-2.10 13/18] crypto: cipher: add afalg-backend cipher >>>> support >>>> >>>> Adds afalg-backend cipher support: introduces some private APIs >>>> firstly, and then intergrates them into qcrypto_cipher_afalg_driver. >>>> >>>> Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com> >>>> --- >>>> + char *name; >>>> + >>>> + name = qcrypto_afalg_cipher_format_name(alg, mode, errp); >>>> + if (!name) { >>>> + return NULL; >>>> + } >>>> + >>>> + afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp); >>>> + if (!afalg) { >>>> + goto error; >>> >>> Leak memory pointed by name. >>> >> >> >> It won't. >> >> If failed, the control flow is error->cleanup->return, and 'name' will be freed >> in 'cleanup'. >> >> If this method success, then the control flow is cleanup->return, 'name' will >> also be freed. >> > I see. I suggest you can store the name pointer in afalg, then its easily to free > it in qcrypto_afalg_comm_free(), and we can get enough information about > the alg/mode if needed. > All right, thanks. :) > Thanks, > -Gonglei > > . >
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs index 2be5a3a..d2e8fa8 100644 --- a/crypto/Makefile.objs +++ b/crypto/Makefile.objs @@ -11,6 +11,7 @@ crypto-obj-y += aes.o crypto-obj-y += desrfb.o crypto-obj-y += cipher.o crypto-obj-$(CONFIG_AF_ALG) += afalg.o +crypto-obj-$(CONFIG_AF_ALG) += cipher-afalg.o crypto-obj-y += tlscreds.o crypto-obj-y += tlscredsanon.o crypto-obj-y += tlscredsx509.o diff --git a/crypto/afalgpriv.h b/crypto/afalgpriv.h index 155130b..7db0597 100644 --- a/crypto/afalgpriv.h +++ b/crypto/afalgpriv.h @@ -19,6 +19,15 @@ #define SALG_TYPE_LEN_MAX 14 #define SALG_NAME_LEN_MAX 64 +#ifndef SOL_ALG +#define SOL_ALG 279 +#endif + +#define AFALG_TYPE_CIPHER "skcipher" + +#define ALG_OPTYPE_LEN 4 +#define ALG_MSGIV_LEN(len) (sizeof(struct af_alg_iv) + (len)) + typedef struct QCryptoAFAlg QCryptoAFAlg; struct QCryptoAFAlg { diff --git a/crypto/cipher-afalg.c b/crypto/cipher-afalg.c new file mode 100644 index 0000000..a2b2f53 --- /dev/null +++ b/crypto/cipher-afalg.c @@ -0,0 +1,225 @@ +/* + * QEMU Crypto af_alg-backend cipher support + * + * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Longpeng(Mike) <longpeng2@huawei.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ +#include "qemu/osdep.h" +#include "qemu/sockets.h" +#include "qemu-common.h" +#include "qapi/error.h" +#include "crypto/cipher.h" +#include "cipherpriv.h" + + +static char * +qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode, + Error **errp) +{ + char *name; + const char *alg_name = NULL; + const char *mode_name = NULL; + int ret; + + switch (alg) { + case QCRYPTO_CIPHER_ALG_AES_128: + case QCRYPTO_CIPHER_ALG_AES_192: + case QCRYPTO_CIPHER_ALG_AES_256: + alg_name = "aes"; + break; + case QCRYPTO_CIPHER_ALG_CAST5_128: + alg_name = "cast5"; + break; + case QCRYPTO_CIPHER_ALG_SERPENT_128: + case QCRYPTO_CIPHER_ALG_SERPENT_192: + case QCRYPTO_CIPHER_ALG_SERPENT_256: + alg_name = "serpent"; + break; + case QCRYPTO_CIPHER_ALG_TWOFISH_128: + case QCRYPTO_CIPHER_ALG_TWOFISH_192: + case QCRYPTO_CIPHER_ALG_TWOFISH_256: + alg_name = "twofish"; + break; + + default: + error_setg(errp, "Unsupported cipher algorithm %d", alg); + return NULL; + } + + mode_name = QCryptoCipherMode_lookup[mode]; + + name = (char *)g_new0(int8_t, SALG_NAME_LEN_MAX); + ret = snprintf(name, SALG_NAME_LEN_MAX, "%s(%s)", mode_name, + alg_name); + if (ret < 0 || ret >= SALG_NAME_LEN_MAX) { + error_setg(errp, "Build ciphername(name='%s',mode='%s') failed", + alg_name, mode_name); + g_free(name); + return NULL; + } + + return name; +} + +QCryptoAFAlg * +qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode, + const uint8_t *key, + size_t nkey, Error **errp) +{ + QCryptoAFAlg *afalg; + size_t except_niv = 0; + char *name; + + name = qcrypto_afalg_cipher_format_name(alg, mode, errp); + if (!name) { + return NULL; + } + + afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp); + if (!afalg) { + goto error; + } + + /* setkey */ + if (qemu_setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, key, + nkey) != 0) { + error_setg_errno(errp, errno, "Set key failed"); + goto error; + } + + /* prepare msg header */ + afalg->msg = g_new0(struct msghdr, 1); + afalg->msg->msg_controllen += CMSG_SPACE(ALG_OPTYPE_LEN); + except_niv = qcrypto_cipher_get_iv_len(alg, mode); + if (except_niv) { + afalg->msg->msg_controllen += CMSG_SPACE(ALG_MSGIV_LEN(except_niv)); + } + afalg->msg->msg_control = g_new0(uint8_t, afalg->msg->msg_controllen); + + /* We use 1st msghdr for crypto-info and 2nd msghdr for IV-info */ + afalg->cmsg = CMSG_FIRSTHDR(afalg->msg); + afalg->cmsg->cmsg_level = SOL_ALG; + afalg->cmsg->cmsg_type = ALG_SET_OP; + afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_OPTYPE_LEN); + +cleanup: + g_free(name); + return afalg; + +error: + qcrypto_afalg_comm_free(afalg); + afalg = NULL; + goto cleanup; +} + +static int +qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher, + const uint8_t *iv, + size_t niv, Error **errp) +{ + struct af_alg_iv *alg_iv = NULL; + QCryptoAFAlg *afalg = cipher->opaque; + + /* move ->cmsg to next msghdr, for IV-info */ + afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg); + + /* build setiv msg */ + afalg->cmsg->cmsg_level = SOL_ALG; + afalg->cmsg->cmsg_type = ALG_SET_IV; + afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_MSGIV_LEN(niv)); + alg_iv = (struct af_alg_iv *)CMSG_DATA(afalg->cmsg); + alg_iv->ivlen = niv; + memcpy(alg_iv->iv, iv, niv); + + return 0; +} + +static int +qcrypto_afalg_cipher_op(QCryptoAFAlg *afalg, + const void *in, void *out, + size_t len, bool do_encrypt, + Error **errp) +{ + uint32_t *type = NULL; + struct iovec iov; + size_t ret, done = 0; + uint32_t origin_contorllen; + + origin_contorllen = afalg->msg->msg_controllen; + /* movev ->cmsg to first header, for crypto-info */ + afalg->cmsg = CMSG_FIRSTHDR(afalg->msg); + + /* build encrypt msg */ + afalg->msg->msg_iov = &iov; + afalg->msg->msg_iovlen = 1; + type = (uint32_t *)CMSG_DATA(afalg->cmsg); + if (do_encrypt) { + *type = ALG_OP_ENCRYPT; + } else { + *type = ALG_OP_DECRYPT; + } + + do { + iov.iov_base = (void *)in + done; + iov.iov_len = len - done; + + /* send info to AF_ALG core */ + ret = sendmsg(afalg->opfd, afalg->msg, 0); + if (ret == -1) { + error_setg_errno(errp, errno, "Send data to AF_ALG core failed"); + return -1; + } + + /* encrypto && get result */ + if (ret != read(afalg->opfd, out, ret)) { + error_setg_errno(errp, errno, "Get result from AF_ALG core failed"); + return -1; + } + + /* do not update IV for following chunks */ + afalg->msg->msg_controllen = 0; + done += ret; + } while (done < len); + + afalg->msg->msg_controllen = origin_contorllen; + + return 0; +} + +static int +qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher, + const void *in, void *out, + size_t len, Error **errp) +{ + return qcrypto_afalg_cipher_op(cipher->opaque, in, out, + len, true, errp); +} + +static int +qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher, + const void *in, void *out, + size_t len, Error **errp) +{ + return qcrypto_afalg_cipher_op(cipher->opaque, in, out, + len, false, errp); +} + +static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher) +{ + qcrypto_afalg_comm_free(cipher->opaque); +} + +struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = { + .cipher_encrypt = qcrypto_afalg_cipher_encrypt, + .cipher_decrypt = qcrypto_afalg_cipher_decrypt, + .cipher_setiv = qcrypto_afalg_cipher_setiv, + .cipher_free = qcrypto_afalg_comm_ctx_free, +}; diff --git a/crypto/cipher.c b/crypto/cipher.c index a6e052c..4a6f548 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -164,17 +164,34 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, { QCryptoCipher *cipher; void *ctx; + Error *err2 = NULL; + QCryptoCipherDriver *drv; + +#ifdef CONFIG_AF_ALG + ctx = qcrypto_afalg_cipher_ctx_new(alg, mode, key, nkey, &err2); + if (ctx) { + drv = &qcrypto_cipher_afalg_driver; + goto set_cipher; + } +#endif ctx = qcrypto_cipher_ctx_new(alg, mode, key, nkey, errp); if (ctx == NULL) { + error_free(err2); return NULL; } + drv = &qcrypto_cipher_lib_driver; + error_free(err2); + +#ifdef CONFIG_AF_ALG +set_cipher: +#endif cipher = g_new0(QCryptoCipher, 1); cipher->alg = alg; cipher->mode = mode; cipher->opaque = ctx; - cipher->driver = (void *)&qcrypto_cipher_lib_driver; + cipher->driver = (void *)drv; return cipher; } @@ -220,3 +237,12 @@ void qcrypto_cipher_free(QCryptoCipher *cipher) g_free(cipher); } } + +bool qcrypto_cipher_using_afalg_drv(QCryptoCipher *cipher) +{ +#ifdef CONFIG_AF_ALG + return cipher->driver == (void *)&qcrypto_cipher_afalg_driver; +#else + return false; +#endif +} diff --git a/crypto/cipherpriv.h b/crypto/cipherpriv.h index 4af5e85..91c6a7e 100644 --- a/crypto/cipherpriv.h +++ b/crypto/cipherpriv.h @@ -15,6 +15,9 @@ #ifndef QCRYPTO_CIPHERPRIV_H #define QCRYPTO_CIPHERPRIV_H +#include "qapi-types.h" +#include "afalgpriv.h" + typedef struct QCryptoCipherDriver QCryptoCipherDriver; struct QCryptoCipherDriver { @@ -37,4 +40,12 @@ struct QCryptoCipherDriver { void (*cipher_free)(QCryptoCipher *cipher); }; +extern QCryptoAFAlg * +qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode, + const uint8_t *key, + size_t nkey, Error **errp); + +extern struct QCryptoCipherDriver qcrypto_cipher_afalg_driver; + #endif diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h index 984fb82..037f602 100644 --- a/include/crypto/cipher.h +++ b/include/crypto/cipher.h @@ -233,4 +233,12 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher, const uint8_t *iv, size_t niv, Error **errp); +/** + * qcrypto_cipher_using_afalg_drv: + * @ the cipher object + * + * Returns: true if @cipher is using afalg driver, otherwise false. + */ +bool qcrypto_cipher_using_afalg_drv(QCryptoCipher *cipher); + #endif /* QCRYPTO_CIPHER_H */ diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c index 07fa2fa..8bb3308 100644 --- a/tests/test-crypto-cipher.c +++ b/tests/test-crypto-cipher.c @@ -715,6 +715,7 @@ static void test_cipher_null_iv(void) uint8_t key[32] = { 0 }; uint8_t plaintext[32] = { 0 }; uint8_t ciphertext[32] = { 0 }; + Error *err = NULL; cipher = qcrypto_cipher_new( QCRYPTO_CIPHER_ALG_AES_256, @@ -729,7 +730,14 @@ static void test_cipher_null_iv(void) plaintext, ciphertext, sizeof(plaintext), - &error_abort); + &err); + + if (qcrypto_cipher_using_afalg_drv(cipher)) { + g_assert(err != NULL); + error_free_or_abort(&err); + } else { + g_assert(err == NULL); + } qcrypto_cipher_free(cipher); }
Adds afalg-backend cipher support: introduces some private APIs firstly, and then intergrates them into qcrypto_cipher_afalg_driver. Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com> --- crypto/Makefile.objs | 1 + crypto/afalgpriv.h | 9 ++ crypto/cipher-afalg.c | 225 +++++++++++++++++++++++++++++++++++++++++++++ crypto/cipher.c | 28 +++++- crypto/cipherpriv.h | 11 +++ include/crypto/cipher.h | 8 ++ tests/test-crypto-cipher.c | 10 +- 7 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 crypto/cipher-afalg.c