cryptodev: introduce a new cryptodev backend
The new cryptodev backend named cryptodev-builtin, which realized by QEMU cipher APIs. These APIs can be backed by either nettle or gcrypt. Signed-off-by: Gonglei <arei.gonglei@huawei.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
		
							parent
							
								
									5551e3a88e
								
							
						
					
					
						commit
						1653a5f3fc
					
				| @ -11,3 +11,4 @@ common-obj-y += hostmem.o hostmem-ram.o | ||||
| common-obj-$(CONFIG_LINUX) += hostmem-file.o | ||||
| 
 | ||||
| common-obj-y += cryptodev.o | ||||
| common-obj-y += cryptodev-builtin.o | ||||
|  | ||||
							
								
								
									
										361
									
								
								backends/cryptodev-builtin.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										361
									
								
								backends/cryptodev-builtin.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,361 @@ | ||||
| /*
 | ||||
|  * QEMU Cryptodev backend for QEMU cipher APIs | ||||
|  * | ||||
|  * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. | ||||
|  * | ||||
|  * Authors: | ||||
|  *    Gonglei <arei.gonglei@huawei.com> | ||||
|  * | ||||
|  * This library is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * This library is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "qemu/osdep.h" | ||||
| #include "sysemu/cryptodev.h" | ||||
| #include "hw/boards.h" | ||||
| #include "qapi/error.h" | ||||
| #include "standard-headers/linux/virtio_crypto.h" | ||||
| #include "crypto/cipher.h" | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * @TYPE_CRYPTODEV_BACKEND_BUILTIN: | ||||
|  * name of backend that uses QEMU cipher API | ||||
|  */ | ||||
| #define TYPE_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin" | ||||
| 
 | ||||
| #define CRYPTODEV_BACKEND_BUILTIN(obj) \ | ||||
|     OBJECT_CHECK(CryptoDevBackendBuiltin, \ | ||||
|                  (obj), TYPE_CRYPTODEV_BACKEND_BUILTIN) | ||||
| 
 | ||||
| typedef struct CryptoDevBackendBuiltin | ||||
|                          CryptoDevBackendBuiltin; | ||||
| 
 | ||||
| typedef struct CryptoDevBackendBuiltinSession { | ||||
|     QCryptoCipher *cipher; | ||||
|     uint8_t direction; /* encryption or decryption */ | ||||
|     uint8_t type; /* cipher? hash? aead? */ | ||||
|     QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next; | ||||
| } CryptoDevBackendBuiltinSession; | ||||
| 
 | ||||
| /* Max number of symmetric sessions */ | ||||
| #define MAX_NUM_SESSIONS 256 | ||||
| 
 | ||||
| #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN    512 | ||||
| #define CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN  64 | ||||
| 
 | ||||
| struct CryptoDevBackendBuiltin { | ||||
|     CryptoDevBackend parent_obj; | ||||
| 
 | ||||
|     CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS]; | ||||
| }; | ||||
| 
 | ||||
| static void cryptodev_builtin_init( | ||||
|              CryptoDevBackend *backend, Error **errp) | ||||
| { | ||||
|     /* Only support one queue */ | ||||
|     int queues = backend->conf.peers.queues; | ||||
|     CryptoDevBackendClient *cc; | ||||
| 
 | ||||
|     if (queues != 1) { | ||||
|         error_setg(errp, | ||||
|                   "Only support one queue in cryptdov-builtin backend"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     cc = cryptodev_backend_new_client( | ||||
|               "cryptodev-builtin", NULL); | ||||
|     cc->info_str = g_strdup_printf("cryptodev-builtin0"); | ||||
|     cc->queue_index = 0; | ||||
|     backend->conf.peers.ccs[0] = cc; | ||||
| 
 | ||||
|     backend->conf.crypto_services = | ||||
|                          1u << VIRTIO_CRYPTO_SERVICE_CIPHER | | ||||
|                          1u << VIRTIO_CRYPTO_SERVICE_HASH | | ||||
|                          1u << VIRTIO_CRYPTO_SERVICE_MAC; | ||||
|     backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC; | ||||
|     backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1; | ||||
|     /*
 | ||||
|      * Set the Maximum length of crypto request. | ||||
|      * Why this value? Just avoid to overflow when | ||||
|      * memory allocation for each crypto request. | ||||
|      */ | ||||
|     backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo); | ||||
|     backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN; | ||||
|     backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| cryptodev_builtin_get_unused_session_index( | ||||
|                  CryptoDevBackendBuiltin *builtin) | ||||
| { | ||||
|     size_t i; | ||||
| 
 | ||||
|     for (i = 0; i < MAX_NUM_SESSIONS; i++) { | ||||
|         if (builtin->sessions[i] == NULL) { | ||||
|             return i; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| cryptodev_builtin_get_aes_algo(uint32_t key_len, Error **errp) | ||||
| { | ||||
|     int algo; | ||||
| 
 | ||||
|     if (key_len == 128 / 8) { | ||||
|         algo = QCRYPTO_CIPHER_ALG_AES_128; | ||||
|     } else if (key_len == 192 / 8) { | ||||
|         algo = QCRYPTO_CIPHER_ALG_AES_192; | ||||
|     } else if (key_len == 256 / 8) { | ||||
|         algo = QCRYPTO_CIPHER_ALG_AES_256; | ||||
|     } else { | ||||
|         error_setg(errp, "Unsupported key length :%u", key_len); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     return algo; | ||||
| } | ||||
| 
 | ||||
| static int cryptodev_builtin_create_cipher_session( | ||||
|                     CryptoDevBackendBuiltin *builtin, | ||||
|                     CryptoDevBackendSymSessionInfo *sess_info, | ||||
|                     Error **errp) | ||||
| { | ||||
|     int algo; | ||||
|     int mode; | ||||
|     QCryptoCipher *cipher; | ||||
|     int index; | ||||
|     CryptoDevBackendBuiltinSession *sess; | ||||
| 
 | ||||
|     if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) { | ||||
|         error_setg(errp, "Unsupported optype :%u", sess_info->op_type); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     index = cryptodev_builtin_get_unused_session_index(builtin); | ||||
|     if (index < 0) { | ||||
|         error_setg(errp, "Total number of sessions created exceeds %u", | ||||
|                   MAX_NUM_SESSIONS); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     switch (sess_info->cipher_alg) { | ||||
|     case VIRTIO_CRYPTO_CIPHER_AES_ECB: | ||||
|         algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, | ||||
|                                                           errp); | ||||
|         if (algo < 0)  { | ||||
|             return -1; | ||||
|         } | ||||
|         mode = QCRYPTO_CIPHER_MODE_ECB; | ||||
|         break; | ||||
|     case VIRTIO_CRYPTO_CIPHER_AES_CBC: | ||||
|         algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, | ||||
|                                                           errp); | ||||
|         if (algo < 0)  { | ||||
|             return -1; | ||||
|         } | ||||
|         mode = QCRYPTO_CIPHER_MODE_CBC; | ||||
|         break; | ||||
|     case VIRTIO_CRYPTO_CIPHER_AES_CTR: | ||||
|         algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, | ||||
|                                                           errp); | ||||
|         if (algo < 0)  { | ||||
|             return -1; | ||||
|         } | ||||
|         mode = QCRYPTO_CIPHER_MODE_CTR; | ||||
|         break; | ||||
|     case VIRTIO_CRYPTO_CIPHER_DES_ECB: | ||||
|         algo = QCRYPTO_CIPHER_ALG_DES_RFB; | ||||
|         mode = QCRYPTO_CIPHER_MODE_ECB; | ||||
|         break; | ||||
|     default: | ||||
|         error_setg(errp, "Unsupported cipher alg :%u", | ||||
|                    sess_info->cipher_alg); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     cipher = qcrypto_cipher_new(algo, mode, | ||||
|                                sess_info->cipher_key, | ||||
|                                sess_info->key_len, | ||||
|                                errp); | ||||
|     if (!cipher) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     sess = g_new0(CryptoDevBackendBuiltinSession, 1); | ||||
|     sess->cipher = cipher; | ||||
|     sess->direction = sess_info->direction; | ||||
|     sess->type = sess_info->op_type; | ||||
| 
 | ||||
|     builtin->sessions[index] = sess; | ||||
| 
 | ||||
|     return index; | ||||
| } | ||||
| 
 | ||||
| static int64_t cryptodev_builtin_sym_create_session( | ||||
|            CryptoDevBackend *backend, | ||||
|            CryptoDevBackendSymSessionInfo *sess_info, | ||||
|            uint32_t queue_index, Error **errp) | ||||
| { | ||||
|     CryptoDevBackendBuiltin *builtin = | ||||
|                       CRYPTODEV_BACKEND_BUILTIN(backend); | ||||
|     int64_t session_id = -1; | ||||
|     int ret; | ||||
| 
 | ||||
|     switch (sess_info->op_code) { | ||||
|     case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: | ||||
|         ret = cryptodev_builtin_create_cipher_session( | ||||
|                            builtin, sess_info, errp); | ||||
|         if (ret < 0) { | ||||
|             return ret; | ||||
|         } else { | ||||
|             session_id = ret; | ||||
|         } | ||||
|         break; | ||||
|     case VIRTIO_CRYPTO_HASH_CREATE_SESSION: | ||||
|     case VIRTIO_CRYPTO_MAC_CREATE_SESSION: | ||||
|     default: | ||||
|         error_setg(errp, "Unsupported opcode :%" PRIu32 "", | ||||
|                    sess_info->op_code); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     return session_id; | ||||
| } | ||||
| 
 | ||||
| static int cryptodev_builtin_sym_close_session( | ||||
|            CryptoDevBackend *backend, | ||||
|            uint64_t session_id, | ||||
|            uint32_t queue_index, Error **errp) | ||||
| { | ||||
|     CryptoDevBackendBuiltin *builtin = | ||||
|                       CRYPTODEV_BACKEND_BUILTIN(backend); | ||||
| 
 | ||||
|     if (session_id >= MAX_NUM_SESSIONS || | ||||
|               builtin->sessions[session_id] == NULL) { | ||||
|         error_setg(errp, "Cannot find a valid session id: %" PRIu64 "", | ||||
|                       session_id); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     qcrypto_cipher_free(builtin->sessions[session_id]->cipher); | ||||
|     g_free(builtin->sessions[session_id]); | ||||
|     builtin->sessions[session_id] = NULL; | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int cryptodev_builtin_sym_operation( | ||||
|                  CryptoDevBackend *backend, | ||||
|                  CryptoDevBackendSymOpInfo *op_info, | ||||
|                  uint32_t queue_index, Error **errp) | ||||
| { | ||||
|     CryptoDevBackendBuiltin *builtin = | ||||
|                       CRYPTODEV_BACKEND_BUILTIN(backend); | ||||
|     CryptoDevBackendBuiltinSession *sess; | ||||
|     int ret; | ||||
| 
 | ||||
|     if (op_info->session_id >= MAX_NUM_SESSIONS || | ||||
|               builtin->sessions[op_info->session_id] == NULL) { | ||||
|         error_setg(errp, "Cannot find a valid session id: %" PRIu64 "", | ||||
|                    op_info->session_id); | ||||
|         return -VIRTIO_CRYPTO_INVSESS; | ||||
|     } | ||||
| 
 | ||||
|     if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { | ||||
|         error_setg(errp, | ||||
|                "Algorithm chain is unsupported for cryptdoev-builtin"); | ||||
|         return -VIRTIO_CRYPTO_NOTSUPP; | ||||
|     } | ||||
| 
 | ||||
|     sess = builtin->sessions[op_info->session_id]; | ||||
| 
 | ||||
|     ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv, | ||||
|                                op_info->iv_len, errp); | ||||
|     if (ret < 0) { | ||||
|         return -VIRTIO_CRYPTO_ERR; | ||||
|     } | ||||
| 
 | ||||
|     if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) { | ||||
|         ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src, | ||||
|                                      op_info->dst, op_info->src_len, errp); | ||||
|         if (ret < 0) { | ||||
|             return -VIRTIO_CRYPTO_ERR; | ||||
|         } | ||||
|     } else { | ||||
|         ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src, | ||||
|                                      op_info->dst, op_info->src_len, errp); | ||||
|         if (ret < 0) { | ||||
|             return -VIRTIO_CRYPTO_ERR; | ||||
|         } | ||||
|     } | ||||
|     return VIRTIO_CRYPTO_OK; | ||||
| } | ||||
| 
 | ||||
| static void cryptodev_builtin_cleanup( | ||||
|              CryptoDevBackend *backend, | ||||
|              Error **errp) | ||||
| { | ||||
|     CryptoDevBackendBuiltin *builtin = | ||||
|                       CRYPTODEV_BACKEND_BUILTIN(backend); | ||||
|     size_t i; | ||||
|     int queues = backend->conf.peers.queues; | ||||
|     CryptoDevBackendClient *cc; | ||||
| 
 | ||||
|     for (i = 0; i < MAX_NUM_SESSIONS; i++) { | ||||
|         if (builtin->sessions[i] != NULL) { | ||||
|             cryptodev_builtin_sym_close_session( | ||||
|                     backend, i, 0, errp); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     assert(queues == 1); | ||||
| 
 | ||||
|     for (i = 0; i < queues; i++) { | ||||
|         cc = backend->conf.peers.ccs[i]; | ||||
|         if (cc) { | ||||
|             cryptodev_backend_free_client(cc); | ||||
|             backend->conf.peers.ccs[i] = NULL; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| cryptodev_builtin_class_init(ObjectClass *oc, void *data) | ||||
| { | ||||
|     CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc); | ||||
| 
 | ||||
|     bc->init = cryptodev_builtin_init; | ||||
|     bc->cleanup = cryptodev_builtin_cleanup; | ||||
|     bc->create_session = cryptodev_builtin_sym_create_session; | ||||
|     bc->close_session = cryptodev_builtin_sym_close_session; | ||||
|     bc->do_sym_op = cryptodev_builtin_sym_operation; | ||||
| } | ||||
| 
 | ||||
| static const TypeInfo cryptodev_builtin_info = { | ||||
|     .name = TYPE_CRYPTODEV_BACKEND_BUILTIN, | ||||
|     .parent = TYPE_CRYPTODEV_BACKEND, | ||||
|     .class_init = cryptodev_builtin_class_init, | ||||
|     .instance_size = sizeof(CryptoDevBackendBuiltin), | ||||
| }; | ||||
| 
 | ||||
| static void | ||||
| cryptodev_builtin_register_types(void) | ||||
| { | ||||
|     type_register_static(&cryptodev_builtin_info); | ||||
| } | ||||
| 
 | ||||
| type_init(cryptodev_builtin_register_types); | ||||
| @ -3948,6 +3948,24 @@ secondary: | ||||
| If you want to know the detail of above command line, you can read | ||||
| the colo-compare git log. | ||||
| 
 | ||||
| @item -object cryptodev-backend-builtin,id=@var{id}[,queues=@var{queues}] | ||||
| 
 | ||||
| Creates a cryptodev backend which executes crypto opreation from | ||||
| the QEMU cipher APIS. The @var{id} parameter is | ||||
| a unique ID that will be used to reference this cryptodev backend from | ||||
| the @option{virtio-crypto} device. The @var{queues} parameter is optional, | ||||
| which specify the queue number of cryptodev backend, the default of | ||||
| @var{queues} is 1. | ||||
| 
 | ||||
| @example | ||||
| 
 | ||||
|  # qemu-system-x86_64 \ | ||||
|    [...] \ | ||||
|        -object cryptodev-backend-builtin,id=cryptodev0 \ | ||||
|        -device virtio-crypto-pci,id=crypto0,cryptodev=cryptodev0 \ | ||||
|    [...] | ||||
| @end example | ||||
| 
 | ||||
| @item -object secret,id=@var{id},data=@var{string},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}] | ||||
| @item -object secret,id=@var{id},file=@var{filename},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}] | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Gonglei
						Gonglei