diff options
author | biao716.wang <biao716.wang@samsung.com> | 2023-08-28 14:40:25 +0900 |
---|---|---|
committer | biao716.wang <biao716.wang@samsung.com> | 2023-08-28 14:40:25 +0900 |
commit | d0ba767e7dc0fded6daae31c11d13b538ed8d53f (patch) | |
tree | eaaffe8ef043ee1803a7bbff50a9946e1613f58f /include/crypto | |
parent | 0889ee8339e51dfdf78c39a8f15b6e5fe5ab49d5 (diff) | |
download | qemu-arm-static-d0ba767e7dc0fded6daae31c11d13b538ed8d53f.tar.gz qemu-arm-static-d0ba767e7dc0fded6daae31c11d13b538ed8d53f.tar.bz2 qemu-arm-static-d0ba767e7dc0fded6daae31c11d13b538ed8d53f.zip |
Upgrade version to 5.2upstream/5.2.0sandbox/wangbiao/qemu_5.2
Change-Id: I79199e4f7e9f27b498cd41113833a6158d4f07a2
Signed-off-by: biao716.wang <biao716.wang@samsung.com>
Diffstat (limited to 'include/crypto')
-rw-r--r-- | include/crypto/aes.h | 63 | ||||
-rw-r--r-- | include/crypto/afsplit.h | 134 | ||||
-rw-r--r-- | include/crypto/block.h | 315 | ||||
-rw-r--r-- | include/crypto/cipher.h | 238 | ||||
-rw-r--r-- | include/crypto/desrfb.h | 50 | ||||
-rw-r--r-- | include/crypto/hash.h | 192 | ||||
-rw-r--r-- | include/crypto/hmac.h | 169 | ||||
-rw-r--r-- | include/crypto/init.h | 28 | ||||
-rw-r--r-- | include/crypto/ivgen.h | 208 | ||||
-rw-r--r-- | include/crypto/pbkdf.h | 156 | ||||
-rw-r--r-- | include/crypto/random.h | 50 | ||||
-rw-r--r-- | include/crypto/secret.h | 133 | ||||
-rw-r--r-- | include/crypto/secret_common.h | 60 | ||||
-rw-r--r-- | include/crypto/secret_keyring.h | 40 | ||||
-rw-r--r-- | include/crypto/tls-cipher-suites.h | 40 | ||||
-rw-r--r-- | include/crypto/tlscreds.h | 67 | ||||
-rw-r--r-- | include/crypto/tlscredsanon.h | 112 | ||||
-rw-r--r-- | include/crypto/tlscredspsk.h | 107 | ||||
-rw-r--r-- | include/crypto/tlscredsx509.h | 114 | ||||
-rw-r--r-- | include/crypto/tlssession.h | 324 | ||||
-rw-r--r-- | include/crypto/xts.h | 82 |
21 files changed, 2682 insertions, 0 deletions
diff --git a/include/crypto/aes.h b/include/crypto/aes.h new file mode 100644 index 000000000..ba297d6a7 --- /dev/null +++ b/include/crypto/aes.h @@ -0,0 +1,63 @@ +#ifndef QEMU_AES_H +#define QEMU_AES_H + +#define AES_MAXNR 14 +#define AES_BLOCK_SIZE 16 + +struct aes_key_st { + uint32_t rd_key[4 *(AES_MAXNR + 1)]; + int rounds; +}; +typedef struct aes_key_st AES_KEY; + +/* FreeBSD/OpenSSL have their own AES functions with the same names in -lcrypto + * (which might be pulled in via curl), so redefine to avoid conflicts. */ +#define AES_set_encrypt_key QEMU_AES_set_encrypt_key +#define AES_set_decrypt_key QEMU_AES_set_decrypt_key +#define AES_encrypt QEMU_AES_encrypt +#define AES_decrypt QEMU_AES_decrypt + +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); + +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); + +extern const uint8_t AES_sbox[256]; +extern const uint8_t AES_isbox[256]; + +/* AES ShiftRows and InvShiftRows */ +extern const uint8_t AES_shifts[16]; +extern const uint8_t AES_ishifts[16]; + +/* AES InvMixColumns */ +/* AES_imc[x][0] = [x].[0e, 09, 0d, 0b]; */ +/* AES_imc[x][1] = [x].[0b, 0e, 09, 0d]; */ +/* AES_imc[x][2] = [x].[0d, 0b, 0e, 09]; */ +/* AES_imc[x][3] = [x].[09, 0d, 0b, 0e]; */ +extern const uint32_t AES_imc[256][4]; + +/* +AES_Te0[x] = S [x].[02, 01, 01, 03]; +AES_Te1[x] = S [x].[03, 02, 01, 01]; +AES_Te2[x] = S [x].[01, 03, 02, 01]; +AES_Te3[x] = S [x].[01, 01, 03, 02]; +AES_Te4[x] = S [x].[01, 01, 01, 01]; + +AES_Td0[x] = Si[x].[0e, 09, 0d, 0b]; +AES_Td1[x] = Si[x].[0b, 0e, 09, 0d]; +AES_Td2[x] = Si[x].[0d, 0b, 0e, 09]; +AES_Td3[x] = Si[x].[09, 0d, 0b, 0e]; +AES_Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +extern const uint32_t AES_Te0[256], AES_Te1[256], AES_Te2[256], + AES_Te3[256], AES_Te4[256]; +extern const uint32_t AES_Td0[256], AES_Td1[256], AES_Td2[256], + AES_Td3[256], AES_Td4[256]; + +#endif diff --git a/include/crypto/afsplit.h b/include/crypto/afsplit.h new file mode 100644 index 000000000..4894d6433 --- /dev/null +++ b/include/crypto/afsplit.h @@ -0,0 +1,134 @@ +/* + * QEMU Crypto anti forensic information splitter + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QCRYPTO_AFSPLIT_H +#define QCRYPTO_AFSPLIT_H + +#include "crypto/hash.h" + +/** + * This module implements the anti-forensic splitter that is specified + * as part of the LUKS format: + * + * http://clemens.endorphin.org/cryptography + * http://clemens.endorphin.org/TKS1-draft.pdf + * + * The core idea is to take a short piece of data (key material) + * and process it to expand it to a much larger piece of data. + * The expansion process is reversible, to obtain the original + * short data. The key property of the expansion is that if any + * byte in the larger data set is changed / missing, it should be + * impossible to recreate the original short data. + * + * <example> + * <title>Creating a large split key for storage</title> + * <programlisting> + * size_t nkey = 32; + * uint32_t stripes = 32768; // To produce a 1 MB split key + * uint8_t *masterkey = ....a 32-byte AES key... + * uint8_t *splitkey; + * + * splitkey = g_new0(uint8_t, nkey * stripes); + * + * if (qcrypto_afsplit_encode(QCRYPTO_HASH_ALG_SHA256, + * nkey, stripes, + * masterkey, splitkey, errp) < 0) { + * g_free(splitkey); + * g_free(masterkey); + * return -1; + * } + * + * ...store splitkey somewhere... + * + * g_free(splitkey); + * g_free(masterkey); + * </programlisting> + * </example> + * + * <example> + * <title>Retrieving a master key from storage</title> + * <programlisting> + * size_t nkey = 32; + * uint32_t stripes = 32768; // To produce a 1 MB split key + * uint8_t *masterkey; + * uint8_t *splitkey = .... read in 1 MB of data... + * + * masterkey = g_new0(uint8_t, nkey); + * + * if (qcrypto_afsplit_decode(QCRYPTO_HASH_ALG_SHA256, + * nkey, stripes, + * splitkey, masterkey, errp) < 0) { + * g_free(splitkey); + * g_free(masterkey); + * return -1; + * } + * + * ..decrypt data with masterkey... + * + * g_free(splitkey); + * g_free(masterkey); + * </programlisting> + * </example> + */ + +/** + * qcrypto_afsplit_encode: + * @hash: the hash algorithm to use for data expansion + * @blocklen: the size of @in in bytes + * @stripes: the number of times to expand @in in size + * @in: the master key to be expanded in size + * @out: preallocated buffer to hold the split key + * @errp: pointer to a NULL-initialized error object + * + * Split the data in @in, which is @blocklen bytes in + * size, to form a larger piece of data @out, which is + * @blocklen * @stripes bytes in size. + * + * Returns: 0 on success, -1 on error; + */ +int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash, + size_t blocklen, + uint32_t stripes, + const uint8_t *in, + uint8_t *out, + Error **errp); + +/** + * qcrypto_afsplit_decode: + * @hash: the hash algorithm to use for data compression + * @blocklen: the size of @out in bytes + * @stripes: the number of times to decrease @in in size + * @in: the split key to be recombined + * @out: preallocated buffer to hold the master key + * @errp: pointer to a NULL-initialized error object + * + * Join the data in @in, which is @blocklen * @stripes + * bytes in size, to form the original small piece of + * data @out, which is @blocklen bytes in size. + * + * Returns: 0 on success, -1 on error; + */ +int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash, + size_t blocklen, + uint32_t stripes, + const uint8_t *in, + uint8_t *out, + Error **errp); + +#endif /* QCRYPTO_AFSPLIT_H */ diff --git a/include/crypto/block.h b/include/crypto/block.h new file mode 100644 index 000000000..7a65e8e40 --- /dev/null +++ b/include/crypto/block.h @@ -0,0 +1,315 @@ +/* + * QEMU Crypto block device encryption + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_BLOCK_H +#define QCRYPTO_BLOCK_H + +#include "crypto/cipher.h" +#include "crypto/ivgen.h" + +typedef struct QCryptoBlock QCryptoBlock; + +/* See also QCryptoBlockFormat, QCryptoBlockCreateOptions + * and QCryptoBlockOpenOptions in qapi/crypto.json */ + +typedef ssize_t (*QCryptoBlockReadFunc)(QCryptoBlock *block, + size_t offset, + uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp); + +typedef ssize_t (*QCryptoBlockInitFunc)(QCryptoBlock *block, + size_t headerlen, + void *opaque, + Error **errp); + +typedef ssize_t (*QCryptoBlockWriteFunc)(QCryptoBlock *block, + size_t offset, + const uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp); + +/** + * qcrypto_block_has_format: + * @format: the encryption format + * @buf: the data from head of the volume + * @len: the length of @buf in bytes + * + * Given @len bytes of data from the head of a storage volume + * in @buf, probe to determine if the volume has the encryption + * format specified in @format. + * + * Returns: true if the data in @buf matches @format + */ +bool qcrypto_block_has_format(QCryptoBlockFormat format, + const uint8_t *buf, + size_t buflen); + +typedef enum { + QCRYPTO_BLOCK_OPEN_NO_IO = (1 << 0), +} QCryptoBlockOpenFlags; + +/** + * qcrypto_block_open: + * @options: the encryption options + * @optprefix: name prefix for options + * @readfunc: callback for reading data from the volume + * @opaque: data to pass to @readfunc + * @flags: bitmask of QCryptoBlockOpenFlags values + * @n_threads: allow concurrent I/O from up to @n_threads threads + * @errp: pointer to a NULL-initialized error object + * + * Create a new block encryption object for an existing + * storage volume encrypted with format identified by + * the parameters in @options. + * + * This will use @readfunc to initialize the encryption + * context based on the volume header(s), extracting the + * master key(s) as required. + * + * If @flags contains QCRYPTO_BLOCK_OPEN_NO_IO then + * the open process will be optimized to skip any parts + * that are only required to perform I/O. In particular + * this would usually avoid the need to decrypt any + * master keys. The only thing that can be done with + * the resulting QCryptoBlock object would be to query + * metadata such as the payload offset. There will be + * no cipher or ivgen objects available. + * + * If any part of initializing the encryption context + * fails an error will be returned. This could be due + * to the volume being in the wrong format, a cipher + * or IV generator algorithm that is not supported, + * or incorrect passphrases. + * + * Returns: a block encryption format, or NULL on error + */ +QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, + const char *optprefix, + QCryptoBlockReadFunc readfunc, + void *opaque, + unsigned int flags, + size_t n_threads, + Error **errp); + +/** + * qcrypto_block_create: + * @options: the encryption options + * @optprefix: name prefix for options + * @initfunc: callback for initializing volume header + * @writefunc: callback for writing data to the volume header + * @opaque: data to pass to @initfunc and @writefunc + * @errp: pointer to a NULL-initialized error object + * + * Create a new block encryption object for initializing + * a storage volume to be encrypted with format identified + * by the parameters in @options. + * + * This method will allocate space for a new volume header + * using @initfunc and then write header data using @writefunc, + * generating new master keys, etc as required. Any existing + * data present on the volume will be irrevocably destroyed. + * + * If any part of initializing the encryption context + * fails an error will be returned. This could be due + * to the volume being in the wrong format, a cipher + * or IV generator algorithm that is not supported, + * or incorrect passphrases. + * + * Returns: a block encryption format, or NULL on error + */ +QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, + const char *optprefix, + QCryptoBlockInitFunc initfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + Error **errp); + +/** + * qcrypto_block_amend_options: + * @block: the block encryption object + * + * @readfunc: callback for reading data from the volume header + * @writefunc: callback for writing data to the volume header + * @opaque: data to pass to @readfunc and @writefunc + * @options: the new/amended encryption options + * @force: hint for the driver to allow unsafe operation + * @errp: error pointer + * + * Changes the crypto options of the encryption format + * + */ +int qcrypto_block_amend_options(QCryptoBlock *block, + QCryptoBlockReadFunc readfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + QCryptoBlockAmendOptions *options, + bool force, + Error **errp); + + +/** + * qcrypto_block_calculate_payload_offset: + * @create_opts: the encryption options + * @optprefix: name prefix for options + * @len: output for number of header bytes before payload + * @errp: pointer to a NULL-initialized error object + * + * Calculate the number of header bytes before the payload in an encrypted + * storage volume. The header is an area before the payload that is reserved + * for encryption metadata. + * + * Returns: true on success, false on error + */ +bool +qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts, + const char *optprefix, + size_t *len, + Error **errp); + + +/** + * qcrypto_block_get_info: + * @block: the block encryption object + * @errp: pointer to a NULL-initialized error object + * + * Get information about the configuration options for the + * block encryption object. This includes details such as + * the cipher algorithms, modes, and initialization vector + * generators. + * + * Returns: a block encryption info object, or NULL on error + */ +QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block, + Error **errp); + +/** + * @qcrypto_block_decrypt: + * @block: the block encryption object + * @offset: the position at which @iov was read + * @buf: the buffer to decrypt + * @len: the length of @buf in bytes + * @errp: pointer to a NULL-initialized error object + * + * Decrypt @len bytes of cipher text in @buf, writing + * plain text back into @buf. @len and @offset must be + * a multiple of the encryption format sector size. + * + * Returns 0 on success, -1 on failure + */ +int qcrypto_block_decrypt(QCryptoBlock *block, + uint64_t offset, + uint8_t *buf, + size_t len, + Error **errp); + +/** + * @qcrypto_block_encrypt: + * @block: the block encryption object + * @offset: the position at which @iov will be written + * @buf: the buffer to decrypt + * @len: the length of @buf in bytes + * @errp: pointer to a NULL-initialized error object + * + * Encrypt @len bytes of plain text in @buf, writing + * cipher text back into @buf. @len and @offset must be + * a multiple of the encryption format sector size. + * + * Returns 0 on success, -1 on failure + */ +int qcrypto_block_encrypt(QCryptoBlock *block, + uint64_t offset, + uint8_t *buf, + size_t len, + Error **errp); + +/** + * qcrypto_block_get_cipher: + * @block: the block encryption object + * + * Get the cipher to use for payload encryption + * + * Returns: the cipher object + */ +QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block); + +/** + * qcrypto_block_get_ivgen: + * @block: the block encryption object + * + * Get the initialization vector generator to use for + * payload encryption + * + * Returns: the IV generator object + */ +QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block); + + +/** + * qcrypto_block_get_kdf_hash: + * @block: the block encryption object + * + * Get the hash algorithm used with the key derivation + * function + * + * Returns: the hash algorithm + */ +QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block); + +/** + * qcrypto_block_get_payload_offset: + * @block: the block encryption object + * + * Get the offset to the payload indicated by the + * encryption header, in bytes. + * + * Returns: the payload offset in bytes + */ +uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block); + +/** + * qcrypto_block_get_sector_size: + * @block: the block encryption object + * + * Get the size of sectors used for payload encryption. A new + * IV is used at the start of each sector. The encryption + * sector size is not required to match the sector size of the + * underlying storage. For example LUKS will always use a 512 + * byte sector size, even if the volume is on a disk with 4k + * sectors. + * + * Returns: the sector in bytes + */ +uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block); + +/** + * qcrypto_block_free: + * @block: the block encryption object + * + * Release all resources associated with the encryption + * object + */ +void qcrypto_block_free(QCryptoBlock *block); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoBlock, qcrypto_block_free) + +#endif /* QCRYPTO_BLOCK_H */ diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h new file mode 100644 index 000000000..083e12a7d --- /dev/null +++ b/include/crypto/cipher.h @@ -0,0 +1,238 @@ +/* + * QEMU Crypto cipher algorithms + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_CIPHER_H +#define QCRYPTO_CIPHER_H + +#include "qapi/qapi-types-crypto.h" + +typedef struct QCryptoCipher QCryptoCipher; +typedef struct QCryptoCipherDriver QCryptoCipherDriver; + +/* See also "QCryptoCipherAlgorithm" and "QCryptoCipherMode" + * enums defined in qapi/crypto.json */ + +/** + * QCryptoCipher: + * + * The QCryptoCipher object provides a way to perform encryption + * and decryption of data, with a standard API, regardless of the + * algorithm used. It further isolates the calling code from the + * details of the specific underlying implementation, whether + * built-in, libgcrypt or nettle. + * + * Each QCryptoCipher object is capable of performing both + * encryption and decryption, and can operate in a number + * or modes including ECB, CBC. + * + * <example> + * <title>Encrypting data with AES-128 in CBC mode</title> + * <programlisting> + * QCryptoCipher *cipher; + * uint8_t key = ....; + * size_t keylen = 16; + * uint8_t iv = ....; + * + * if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128)) { + * error_report(errp, "Feature <blah> requires AES cipher support"); + * return -1; + * } + * + * cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128, + * QCRYPTO_CIPHER_MODE_CBC, + * key, keylen, + * errp); + * if (!cipher) { + * return -1; + * } + * + * if (qcrypto_cipher_set_iv(cipher, iv, keylen, errp) < 0) { + * return -1; + * } + * + * if (qcrypto_cipher_encrypt(cipher, rawdata, encdata, datalen, errp) < 0) { + * return -1; + * } + * + * qcrypto_cipher_free(cipher); + * </programlisting> + * </example> + * + */ + +struct QCryptoCipher { + QCryptoCipherAlgorithm alg; + QCryptoCipherMode mode; + const QCryptoCipherDriver *driver; +}; + +/** + * qcrypto_cipher_supports: + * @alg: the cipher algorithm + * @mode: the cipher mode + * + * Determine if @alg cipher algorithm in @mode is supported by the + * current configured build + * + * Returns: true if the algorithm is supported, false otherwise + */ +bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode); + +/** + * qcrypto_cipher_get_block_len: + * @alg: the cipher algorithm + * + * Get the required data block size in bytes. When + * encrypting data, it must be a multiple of the + * block size. + * + * Returns: the block size in bytes + */ +size_t qcrypto_cipher_get_block_len(QCryptoCipherAlgorithm alg); + + +/** + * qcrypto_cipher_get_key_len: + * @alg: the cipher algorithm + * + * Get the required key size in bytes. + * + * Returns: the key size in bytes + */ +size_t qcrypto_cipher_get_key_len(QCryptoCipherAlgorithm alg); + + +/** + * qcrypto_cipher_get_iv_len: + * @alg: the cipher algorithm + * @mode: the cipher mode + * + * Get the required initialization vector size + * in bytes, if one is required. + * + * Returns: the IV size in bytes, or 0 if no IV is permitted + */ +size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode); + + +/** + * qcrypto_cipher_new: + * @alg: the cipher algorithm + * @mode: the cipher usage mode + * @key: the private key bytes + * @nkey: the length of @key + * @errp: pointer to a NULL-initialized error object + * + * Creates a new cipher object for encrypting/decrypting + * data with the algorithm @alg in the usage mode @mode. + * + * The @key parameter provides the bytes representing + * the encryption/decryption key to use. The @nkey parameter + * specifies the length of @key in bytes. Each algorithm has + * one or more valid key lengths, and it is an error to provide + * a key of the incorrect length. + * + * The returned cipher object must be released with + * qcrypto_cipher_free() when no longer required + * + * Returns: a new cipher object, or NULL on error + */ +QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode, + const uint8_t *key, size_t nkey, + Error **errp); + +/** + * qcrypto_cipher_free: + * @cipher: the cipher object + * + * Release the memory associated with @cipher that + * was previously allocated by qcrypto_cipher_new() + */ +void qcrypto_cipher_free(QCryptoCipher *cipher); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoCipher, qcrypto_cipher_free) + +/** + * qcrypto_cipher_encrypt: + * @cipher: the cipher object + * @in: buffer holding the plain text input data + * @out: buffer to fill with the cipher text output data + * @len: the length of @in and @out buffers + * @errp: pointer to a NULL-initialized error object + * + * Encrypts the plain text stored in @in, filling + * @out with the resulting ciphered text. Both the + * @in and @out buffers must have the same size, + * given by @len. + * + * Returns: 0 on success, or -1 on error + */ +int qcrypto_cipher_encrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp); + + +/** + * qcrypto_cipher_decrypt: + * @cipher: the cipher object + * @in: buffer holding the cipher text input data + * @out: buffer to fill with the plain text output data + * @len: the length of @in and @out buffers + * @errp: pointer to a NULL-initialized error object + * + * Decrypts the cipher text stored in @in, filling + * @out with the resulting plain text. Both the + * @in and @out buffers must have the same size, + * given by @len. + * + * Returns: 0 on success, or -1 on error + */ +int qcrypto_cipher_decrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp); + +/** + * qcrypto_cipher_setiv: + * @cipher: the cipher object + * @iv: the initialization vector or counter (CTR mode) bytes + * @niv: the length of @iv + * @errpr: pointer to a NULL-initialized error object + * + * If the @cipher object is setup to use a mode that requires + * initialization vectors or counter, this sets the @niv + * bytes. The @iv data should have the same length as the + * cipher key used when originally constructing the cipher + * object. It is an error to set an initialization vector + * or counter if the cipher mode does not require one. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_cipher_setiv(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp); + +#endif /* QCRYPTO_CIPHER_H */ diff --git a/include/crypto/desrfb.h b/include/crypto/desrfb.h new file mode 100644 index 000000000..7ca596c38 --- /dev/null +++ b/include/crypto/desrfb.h @@ -0,0 +1,50 @@ +/* + * This is D3DES (V5.09) by Richard Outerbridge with the double and + * triple-length support removed for use in VNC. + * + * These changes are: + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * + * This software 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. + */ + +#ifndef QCRYPTO_DESRFB_H +#define QCRYPTO_DESRFB_H + +/* d3des.h - + * + * Headers and defines for d3des.c + * Graven Imagery, 1992. + * + * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge + * (GEnie : OUTER; CIS : [71755,204]) + */ + +#define EN0 0 /* MODE == encrypt */ +#define DE1 1 /* MODE == decrypt */ + +void deskey(unsigned char *, int); +/* hexkey[8] MODE + * Sets the internal key register according to the hexadecimal + * key contained in the 8 bytes of hexkey, according to the DES, + * for encryption or decryption according to MODE. + */ + +void usekey(unsigned long *); +/* cookedkey[32] + * Loads the internal key register with the data in cookedkey. + */ + +void des(unsigned char *, unsigned char *); +/* from[8] to[8] + * Encrypts/Decrypts (according to the key currently loaded in the + * internal key register) one block of eight bytes at address 'from' + * into the block at address 'to'. They can be the same. + */ + +/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery + ********************************************************************/ + +#endif diff --git a/include/crypto/hash.h b/include/crypto/hash.h new file mode 100644 index 000000000..54d87aa2a --- /dev/null +++ b/include/crypto/hash.h @@ -0,0 +1,192 @@ +/* + * QEMU Crypto hash algorithms + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_HASH_H +#define QCRYPTO_HASH_H + +#include "qapi/qapi-types-crypto.h" + +/* See also "QCryptoHashAlgorithm" defined in qapi/crypto.json */ + +/** + * qcrypto_hash_supports: + * @alg: the hash algorithm + * + * Determine if @alg hash algorithm is supported by the + * current configured build. + * + * Returns: true if the algorithm is supported, false otherwise + */ +gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg); + + +/** + * qcrypto_hash_digest_len: + * @alg: the hash algorithm + * + * Determine the size of the hash digest in bytes + * + * Returns: the digest length in bytes + */ +size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg); + +/** + * qcrypto_hash_bytesv: + * @alg: the hash algorithm + * @iov: the array of memory regions to hash + * @niov: the length of @iov + * @result: pointer to hold output hash + * @resultlen: pointer to hold length of @result + * @errp: pointer to a NULL-initialized error object + * + * Computes the hash across all the memory regions + * present in @iov. The @result pointer will be + * filled with raw bytes representing the computed + * hash, which will have length @resultlen. 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_bytesv(QCryptoHashAlgorithm alg, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp); + +/** + * qcrypto_hash_bytes: + * @alg: the hash algorithm + * @buf: the memory region to hash + * @len: the length of @buf + * @result: pointer to hold output hash + * @resultlen: pointer to hold length of @result + * @errp: pointer to a NULL-initialized error object + * + * Computes the hash across all the memory region + * @buf of length @len. The @result pointer will be + * filled with raw bytes representing the computed + * hash, which will have length @resultlen. 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_bytes(QCryptoHashAlgorithm alg, + const char *buf, + size_t len, + uint8_t **result, + size_t *resultlen, + Error **errp); + +/** + * qcrypto_hash_digestv: + * @alg: the hash algorithm + * @iov: the array of memory regions to hash + * @niov: the length of @iov + * @digest: pointer to hold output hash + * @errp: pointer to a NULL-initialized error object + * + * Computes the hash across all the memory regions + * present in @iov. 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_digestv(QCryptoHashAlgorithm alg, + const struct iovec *iov, + size_t niov, + char **digest, + Error **errp); + +/** + * qcrypto_hash_digest: + * @alg: the hash algorithm + * @buf: the memory region to hash + * @len: the length of @buf + * @digest: pointer to hold output hash + * @errp: pointer to a NULL-initialized error object + * + * Computes the hash across all the memory region + * @buf of length @len. 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_digest(QCryptoHashAlgorithm alg, + const char *buf, + size_t len, + char **digest, + Error **errp); + +/** + * qcrypto_hash_base64v: + * @alg: the hash algorithm + * @iov: the array of memory regions to hash + * @niov: the length of @iov + * @base64: pointer to hold output hash + * @errp: pointer to a NULL-initialized error object + * + * Computes the hash across all the memory regions + * present in @iov. 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_base64v(QCryptoHashAlgorithm alg, + const struct iovec *iov, + size_t niov, + char **base64, + Error **errp); + +/** + * qcrypto_hash_base64: + * @alg: the hash algorithm + * @buf: the memory region to hash + * @len: the length of @buf + * @base64: pointer to hold output hash + * @errp: pointer to a NULL-initialized error object + * + * Computes the hash across all the memory region + * @buf of length @len. 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_base64(QCryptoHashAlgorithm alg, + const char *buf, + size_t len, + char **base64, + Error **errp); + +#endif /* QCRYPTO_HASH_H */ diff --git a/include/crypto/hmac.h b/include/crypto/hmac.h new file mode 100644 index 000000000..ad4d77841 --- /dev/null +++ b/include/crypto/hmac.h @@ -0,0 +1,169 @@ +/* + * QEMU Crypto hmac algorithms + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * 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. + * + */ + +#ifndef QCRYPTO_HMAC_H +#define QCRYPTO_HMAC_H + +#include "qapi/qapi-types-crypto.h" + +typedef struct QCryptoHmac QCryptoHmac; +struct QCryptoHmac { + QCryptoHashAlgorithm alg; + void *opaque; + void *driver; +}; + +/** + * qcrypto_hmac_supports: + * @alg: the hmac algorithm + * + * Determine if @alg hmac algorithm is supported by + * the current configured build + * + * Returns: + * true if the algorithm is supported, false otherwise + */ +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg); + +/** + * qcrypto_hmac_new: + * @alg: the hmac algorithm + * @key: the key bytes + * @nkey: the length of @key + * @errp: pointer to a NULL-initialized error object + * + * Creates a new hmac object with the algorithm @alg + * + * The @key parameter provides the bytes representing + * the secret key to use. The @nkey parameter specifies + * the length of @key in bytes + * + * Note: must use qcrypto_hmac_free() to release the + * returned hmac object when no longer required + * + * Returns: + * a new hmac object, or NULL on error + */ +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp); + +/** + * qcrypto_hmac_free: + * @hmac: the hmac object + * + * Release the memory associated with @hmac that was + * previously allocated by qcrypto_hmac_new() + */ +void qcrypto_hmac_free(QCryptoHmac *hmac); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoHmac, qcrypto_hmac_free) + +/** + * qcrypto_hmac_bytesv: + * @hmac: the hmac object + * @iov: the array of memory regions to hmac + * @niov: the length of @iov + * @result: pointer to hold output hmac + * @resultlen: pointer to hold length of @result + * @errp: pointer to a NULL-initialized error object + * + * Computes the hmac across all the memory regions + * present in @iov. The @result pointer will be + * filled with raw bytes representing the computed + * hmac, which will have length @resultlen. 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_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp); + +/** + * qcrypto_hmac_bytes: + * @hmac: the hmac object + * @buf: the memory region to hmac + * @len: the length of @buf + * @result: pointer to hold output hmac + * @resultlen: pointer to hold length of @result + * @errp: pointer to a NULL-initialized error object + * + * Computes the hmac across all the memory region + * @buf of length @len. The @result pointer will be + * filled with raw bytes representing the computed + * hmac, which will have length @resultlen. 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_hmac_bytes(QCryptoHmac *hmac, + const char *buf, + size_t len, + uint8_t **result, + size_t *resultlen, + Error **errp); + +/** + * qcrypto_hmac_digestv: + * @hmac: the hmac object + * @iov: the array of memory regions to hmac + * @niov: the length of @iov + * @digest: pointer to hold output hmac + * @errp: pointer to a NULL-initialized error object + * + * Computes the hmac across all the memory regions + * present in @iov. The @digest pointer will be + * filled with the printable hex digest of the computed + * hmac, 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_hmac_digestv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + char **digest, + Error **errp); + +/** + * qcrypto_hmac_digest: + * @hmac: the hmac object + * @buf: the memory region to hmac + * @len: the length of @buf + * @digest: pointer to hold output hmac + * @errp: pointer to a NULL-initialized error object + * + * Computes the hmac across all the memory region + * @buf of length @len. The @digest pointer will be + * filled with the printable hex digest of the computed + * hmac, 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_hmac_digest(QCryptoHmac *hmac, + const char *buf, + size_t len, + char **digest, + Error **errp); + +#endif diff --git a/include/crypto/init.h b/include/crypto/init.h new file mode 100644 index 000000000..00e0f637c --- /dev/null +++ b/include/crypto/init.h @@ -0,0 +1,28 @@ +/* + * QEMU Crypto initialization + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_INIT_H +#define QCRYPTO_INIT_H + +#include "qapi/error.h" + +int qcrypto_init(Error **errp); + +#endif /* QCRYPTO_INIT_H */ diff --git a/include/crypto/ivgen.h b/include/crypto/ivgen.h new file mode 100644 index 000000000..e41521519 --- /dev/null +++ b/include/crypto/ivgen.h @@ -0,0 +1,208 @@ +/* + * QEMU Crypto block IV generator + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_IVGEN_H +#define QCRYPTO_IVGEN_H + +#include "crypto/cipher.h" +#include "crypto/hash.h" + +/** + * This module provides a framework for generating initialization + * vectors for block encryption schemes using chained cipher modes + * CBC. The principle is that each disk sector is assigned a unique + * initialization vector for use for encryption of data in that + * sector. + * + * <example> + * <title>Encrypting block data with initialiation vectors</title> + * <programlisting> + * uint8_t *data = ....data to encrypt... + * size_t ndata = XXX; + * uint8_t *key = ....some encryption key... + * size_t nkey = XXX; + * uint8_t *iv; + * size_t niv; + * size_t sector = 0; + * + * g_assert((ndata % 512) == 0); + * + * QCryptoIVGen *ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_ESSIV, + * QCRYPTO_CIPHER_ALG_AES_128, + * QCRYPTO_HASH_ALG_SHA256, + * key, nkey, errp); + * if (!ivgen) { + * return -1; + * } + * + * QCryptoCipher *cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128, + * QCRYPTO_CIPHER_MODE_CBC, + * key, nkey, errp); + * if (!cipher) { + * goto error; + * } + * + * niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128, + * QCRYPTO_CIPHER_MODE_CBC); + * iv = g_new0(uint8_t, niv); + * + * + * while (ndata) { + * if (qcrypto_ivgen_calculate(ivgen, sector, iv, niv, errp) < 0) { + * goto error; + * } + * if (qcrypto_cipher_setiv(cipher, iv, niv, errp) < 0) { + * goto error; + * } + * if (qcrypto_cipher_encrypt(cipher, + * data + (sector * 512), + * data + (sector * 512), + * 512, errp) < 0) { + * goto error; + * } + * sector++; + * ndata -= 512; + * } + * + * g_free(iv); + * qcrypto_ivgen_free(ivgen); + * qcrypto_cipher_free(cipher); + * return 0; + * + *error: + * g_free(iv); + * qcrypto_ivgen_free(ivgen); + * qcrypto_cipher_free(cipher); + * return -1; + * </programlisting> + * </example> + */ + +typedef struct QCryptoIVGen QCryptoIVGen; + +/* See also QCryptoIVGenAlgorithm enum in qapi/crypto.json */ + + +/** + * qcrypto_ivgen_new: + * @alg: the initialization vector generation algorithm + * @cipheralg: the cipher algorithm or 0 + * @hash: the hash algorithm or 0 + * @key: the encryption key or NULL + * @nkey: the size of @key in bytes + * + * Create a new initialization vector generator that uses + * the algorithm @alg. Whether the remaining parameters + * are required or not depends on the choice of @alg + * requested. + * + * - QCRYPTO_IVGEN_ALG_PLAIN + * + * The IVs are generated by the 32-bit truncated sector + * number. This should never be used for block devices + * that are larger than 2^32 sectors in size. + * All the other parameters are unused. + * + * - QCRYPTO_IVGEN_ALG_PLAIN64 + * + * The IVs are generated by the 64-bit sector number. + * All the other parameters are unused. + * + * - QCRYPTO_IVGEN_ALG_ESSIV: + * + * The IVs are generated by encrypting the 64-bit sector + * number with a hash of an encryption key. The @cipheralg, + * @hash, @key and @nkey parameters are all required. + * + * Returns: a new IV generator, or NULL on error + */ +QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg, + QCryptoCipherAlgorithm cipheralg, + QCryptoHashAlgorithm hash, + const uint8_t *key, size_t nkey, + Error **errp); + +/** + * qcrypto_ivgen_calculate: + * @ivgen: the IV generator object + * @sector: the 64-bit sector number + * @iv: a pre-allocated buffer to hold the generated IV + * @niv: the number of bytes in @iv + * @errp: pointer to a NULL-initialized error object + * + * Calculate a new initialiation vector for the data + * to be stored in sector @sector. The IV will be + * written into the buffer @iv of size @niv. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen, + uint64_t sector, + uint8_t *iv, size_t niv, + Error **errp); + + +/** + * qcrypto_ivgen_get_algorithm: + * @ivgen: the IV generator object + * + * Get the algorithm used by this IV generator + * + * Returns: the IV generator algorithm + */ +QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen); + + +/** + * qcrypto_ivgen_get_cipher: + * @ivgen: the IV generator object + * + * Get the cipher algorithm used by this IV generator (if + * applicable) + * + * Returns: the cipher algorithm + */ +QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen); + + +/** + * qcrypto_ivgen_get_hash: + * @ivgen: the IV generator object + * + * Get the hash algorithm used by this IV generator (if + * applicable) + * + * Returns: the hash algorithm + */ +QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen); + + +/** + * qcrypto_ivgen_free: + * @ivgen: the IV generator object + * + * Release all resources associated with @ivgen, or a no-op + * if @ivgen is NULL + */ +void qcrypto_ivgen_free(QCryptoIVGen *ivgen); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoIVGen, qcrypto_ivgen_free) + +#endif /* QCRYPTO_IVGEN_H */ diff --git a/include/crypto/pbkdf.h b/include/crypto/pbkdf.h new file mode 100644 index 000000000..2c31a44a2 --- /dev/null +++ b/include/crypto/pbkdf.h @@ -0,0 +1,156 @@ +/* + * QEMU Crypto PBKDF support (Password-Based Key Derivation Function) + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_PBKDF_H +#define QCRYPTO_PBKDF_H + +#include "crypto/hash.h" + +/** + * This module provides an interface to the PBKDF2 algorithm + * + * https://en.wikipedia.org/wiki/PBKDF2 + * + * <example> + * <title>Generating an AES encryption key from a user password</title> + * <programlisting> + * #include "crypto/cipher.h" + * #include "crypto/random.h" + * #include "crypto/pbkdf.h" + * + * .... + * + * char *password = "a-typical-awful-user-password"; + * size_t nkey = qcrypto_cipher_get_key_len(QCRYPTO_CIPHER_ALG_AES_128); + * uint8_t *salt = g_new0(uint8_t, nkey); + * uint8_t *key = g_new0(uint8_t, nkey); + * int iterations; + * QCryptoCipher *cipher; + * + * if (qcrypto_random_bytes(salt, nkey, errp) < 0) { + * g_free(key); + * g_free(salt); + * return -1; + * } + * + * iterations = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256, + * (const uint8_t *)password, + * strlen(password), + * salt, nkey, errp); + * if (iterations < 0) { + * g_free(key); + * g_free(salt); + * return -1; + * } + * + * if (qcrypto_pbkdf2(QCRYPTO_HASH_ALG_SHA256, + * (const uint8_t *)password, strlen(password), + * salt, nkey, iterations, key, nkey, errp) < 0) { + * g_free(key); + * g_free(salt); + * return -1; + * } + * + * g_free(salt); + * + * cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128, + * QCRYPTO_CIPHER_MODE_ECB, + * key, nkey, errp); + * g_free(key); + * + * ....encrypt some data... + * + * qcrypto_cipher_free(cipher); + * </programlisting> + * </example> + * + */ + +/** + * qcrypto_pbkdf2_supports: + * @hash: the hash algorithm + * + * Determine if the current build supports the PBKDF2 algorithm + * in combination with the hash @hash. + * + * Returns true if supported, false otherwise + */ +bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash); + + +/** + * qcrypto_pbkdf2: + * @hash: the hash algorithm to use + * @key: the user password / key + * @nkey: the length of @key in bytes + * @salt: a random salt + * @nsalt: length of @salt in bytes + * @iterations: the number of iterations to compute + * @out: pointer to pre-allocated buffer to hold output + * @nout: length of @out in bytes + * @errp: pointer to a NULL-initialized error object + * + * Apply the PBKDF2 algorithm to derive an encryption + * key from a user password provided in @key. The + * @salt parameter is used to perturb the algorithm. + * The @iterations count determines how many times + * the hashing process is run, which influences how + * hard it is to crack the key. The number of @iterations + * should be large enough such that the algorithm takes + * 1 second or longer to derive a key. The derived key + * will be stored in the preallocated buffer @out. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, + const uint8_t *key, size_t nkey, + const uint8_t *salt, size_t nsalt, + uint64_t iterations, + uint8_t *out, size_t nout, + Error **errp); + +/** + * qcrypto_pbkdf2_count_iters: + * @hash: the hash algorithm to use + * @key: the user password / key + * @nkey: the length of @key in bytes + * @salt: a random salt + * @nsalt: length of @salt in bytes + * @nout: size of desired derived key + * @errp: pointer to a NULL-initialized error object + * + * Time the PBKDF2 algorithm to determine how many + * iterations are required to derive an encryption + * key from a user password provided in @key in 1 + * second of compute time. The result of this can + * be used as a the @iterations parameter of a later + * call to qcrypto_pbkdf2(). The value of @nout should + * match that value that will later be provided with + * a call to qcrypto_pbkdf2(). + * + * Returns: number of iterations in 1 second, -1 on error + */ +uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, + const uint8_t *key, size_t nkey, + const uint8_t *salt, size_t nsalt, + size_t nout, + Error **errp); + +#endif /* QCRYPTO_PBKDF_H */ diff --git a/include/crypto/random.h b/include/crypto/random.h new file mode 100644 index 000000000..325ff075d --- /dev/null +++ b/include/crypto/random.h @@ -0,0 +1,50 @@ +/* + * QEMU Crypto random number provider + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_RANDOM_H +#define QCRYPTO_RANDOM_H + + +/** + * qcrypto_random_bytes: + * @buf: the buffer to fill + * @buflen: length of @buf in bytes + * @errp: pointer to a NULL-initialized error object + * + * Fill @buf with @buflen bytes of cryptographically strong + * random data + * + * Returns 0 on success, -1 on error + */ +int qcrypto_random_bytes(void *buf, + size_t buflen, + Error **errp); + +/** + * qcrypto_random_init: + * @errp: pointer to a NULL-initialized error object + * + * Initializes the handles used by qcrypto_random_bytes + * + * Returns 0 on success, -1 on error + */ +int qcrypto_random_init(Error **errp); + +#endif /* QCRYPTO_RANDOM_H */ diff --git a/include/crypto/secret.h b/include/crypto/secret.h new file mode 100644 index 000000000..5d20ae6d2 --- /dev/null +++ b/include/crypto/secret.h @@ -0,0 +1,133 @@ +/* + * QEMU crypto secret support + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_SECRET_H +#define QCRYPTO_SECRET_H + +#include "qapi/qapi-types-crypto.h" +#include "qom/object.h" +#include "crypto/secret_common.h" + +#define TYPE_QCRYPTO_SECRET "secret" +typedef struct QCryptoSecret QCryptoSecret; +DECLARE_INSTANCE_CHECKER(QCryptoSecret, QCRYPTO_SECRET, + TYPE_QCRYPTO_SECRET) + +typedef struct QCryptoSecretClass QCryptoSecretClass; + +/** + * QCryptoSecret: + * + * The QCryptoSecret object provides storage of secrets, + * which may be user passwords, encryption keys or any + * other kind of sensitive data that is represented as + * a sequence of bytes. + * + * The sensitive data associated with the secret can + * be provided directly via the 'data' property, or + * indirectly via the 'file' property. In the latter + * case there is support for file descriptor passing + * via the usual /dev/fdset/NN syntax that QEMU uses. + * + * The data for a secret can be provided in two formats, + * either as a UTF-8 string (the default), or as base64 + * encoded 8-bit binary data. The latter is appropriate + * for raw encryption keys, while the former is appropriate + * for user entered passwords. + * + * The data may be optionally encrypted with AES-256-CBC, + * and the decryption key provided by another + * QCryptoSecret instance identified by the 'keyid' + * property. When passing sensitive data directly + * via the 'data' property it is strongly recommended + * to use the AES encryption facility to prevent the + * sensitive data being exposed in the process listing + * or system log files. + * + * Providing data directly, insecurely (suitable for + * ad hoc developer testing only) + * + * $QEMU -object secret,id=sec0,data=letmein + * + * Providing data indirectly: + * + * # printf "letmein" > password.txt + * # $QEMU \ + * -object secret,id=sec0,file=password.txt + * + * Using a master encryption key with data. + * + * The master key needs to be created as 32 secure + * random bytes (optionally base64 encoded) + * + * # openssl rand -base64 32 > key.b64 + * # KEY=$(base64 -d key.b64 | hexdump -v -e '/1 "%02X"') + * + * Each secret to be encrypted needs to have a random + * initialization vector generated. These do not need + * to be kept secret + * + * # openssl rand -base64 16 > iv.b64 + * # IV=$(base64 -d iv.b64 | hexdump -v -e '/1 "%02X"') + * + * A secret to be defined can now be encrypted + * + * # SECRET=$(printf "letmein" | + * openssl enc -aes-256-cbc -a -K $KEY -iv $IV) + * + * When launching QEMU, create a master secret pointing + * to key.b64 and specify that to be used to decrypt + * the user password + * + * # $QEMU \ + * -object secret,id=secmaster0,format=base64,file=key.b64 \ + * -object secret,id=sec0,keyid=secmaster0,format=base64,\ + * data=$SECRET,iv=$(<iv.b64) + * + * When encrypting, the data can still be provided via an + * external file, in which case it is possible to use either + * raw binary data, or base64 encoded. This example uses + * raw format + * + * # printf "letmein" | + * openssl enc -aes-256-cbc -K $KEY -iv $IV -o pw.aes + * # $QEMU \ + * -object secret,id=secmaster0,format=base64,file=key.b64 \ + * -object secret,id=sec0,keyid=secmaster0,\ + * file=pw.aes,iv=$(<iv.b64) + * + * Note that the ciphertext can be in either raw or base64 + * format, as indicated by the 'format' parameter, but the + * plaintext resulting from decryption is expected to always + * be in raw format. + */ + +struct QCryptoSecret { + QCryptoSecretCommon parent_obj; + char *data; + char *file; +}; + + +struct QCryptoSecretClass { + QCryptoSecretCommonClass parent_class; +}; + +#endif /* QCRYPTO_SECRET_H */ diff --git a/include/crypto/secret_common.h b/include/crypto/secret_common.h new file mode 100644 index 000000000..42c7ff7af --- /dev/null +++ b/include/crypto/secret_common.h @@ -0,0 +1,60 @@ +/* + * QEMU crypto secret support + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_SECRET_COMMON_H +#define QCRYPTO_SECRET_COMMON_H + +#include "qapi/qapi-types-crypto.h" +#include "qom/object.h" + +#define TYPE_QCRYPTO_SECRET_COMMON "secret_common" +OBJECT_DECLARE_TYPE(QCryptoSecretCommon, QCryptoSecretCommonClass, + QCRYPTO_SECRET_COMMON) + + +struct QCryptoSecretCommon { + Object parent_obj; + uint8_t *rawdata; + size_t rawlen; + QCryptoSecretFormat format; + char *keyid; + char *iv; +}; + + +struct QCryptoSecretCommonClass { + ObjectClass parent_class; + void (*load_data)(QCryptoSecretCommon *secret, + uint8_t **output, + size_t *outputlen, + Error **errp); +}; + + +extern int qcrypto_secret_lookup(const char *secretid, + uint8_t **data, + size_t *datalen, + Error **errp); +extern char *qcrypto_secret_lookup_as_utf8(const char *secretid, + Error **errp); +extern char *qcrypto_secret_lookup_as_base64(const char *secretid, + Error **errp); + +#endif /* QCRYPTO_SECRET_COMMON_H */ diff --git a/include/crypto/secret_keyring.h b/include/crypto/secret_keyring.h new file mode 100644 index 000000000..3758852cb --- /dev/null +++ b/include/crypto/secret_keyring.h @@ -0,0 +1,40 @@ +/* + * QEMU crypto secret support + * + * Copyright 2020 Yandex N.V. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_SECRET_KEYRING_H +#define QCRYPTO_SECRET_KEYRING_H + +#include "qapi/qapi-types-crypto.h" +#include "qom/object.h" +#include "crypto/secret_common.h" + +#define TYPE_QCRYPTO_SECRET_KEYRING "secret_keyring" +OBJECT_DECLARE_SIMPLE_TYPE(QCryptoSecretKeyring, + QCRYPTO_SECRET_KEYRING) + + +struct QCryptoSecretKeyring { + QCryptoSecretCommon parent; + int32_t serial; +}; + + + +#endif /* QCRYPTO_SECRET_KEYRING_H */ diff --git a/include/crypto/tls-cipher-suites.h b/include/crypto/tls-cipher-suites.h new file mode 100644 index 000000000..bb9ee53e0 --- /dev/null +++ b/include/crypto/tls-cipher-suites.h @@ -0,0 +1,40 @@ +/* + * QEMU TLS Cipher Suites Registry (RFC8447) + * + * Copyright (c) 2018-2020 Red Hat, Inc. + * + * Author: Philippe Mathieu-Daudé <philmd@redhat.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef QCRYPTO_TLSCIPHERSUITES_H +#define QCRYPTO_TLSCIPHERSUITES_H + +#include "qom/object.h" +#include "crypto/tlscreds.h" + +#define TYPE_QCRYPTO_TLS_CIPHER_SUITES "tls-cipher-suites" +typedef struct QCryptoTLSCipherSuites QCryptoTLSCipherSuites; +DECLARE_INSTANCE_CHECKER(QCryptoTLSCipherSuites, QCRYPTO_TLS_CIPHER_SUITES, + TYPE_QCRYPTO_TLS_CIPHER_SUITES) + +struct QCryptoTLSCipherSuites { + /* <private> */ + QCryptoTLSCreds parent_obj; + /* <public> */ +}; + +/** + * qcrypto_tls_cipher_suites_get_data: + * @obj: pointer to a TLS cipher suites object + * @errp: pointer to a NULL-initialized error object + * + * Returns: reference to a byte array containing the data. + * The caller should release the reference when no longer + * required. + */ +GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj, + Error **errp); + +#endif /* QCRYPTO_TLSCIPHERSUITES_H */ diff --git a/include/crypto/tlscreds.h b/include/crypto/tlscreds.h new file mode 100644 index 000000000..079e37604 --- /dev/null +++ b/include/crypto/tlscreds.h @@ -0,0 +1,67 @@ +/* + * QEMU crypto TLS credential support + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_TLSCREDS_H +#define QCRYPTO_TLSCREDS_H + +#include "qapi/qapi-types-crypto.h" +#include "qom/object.h" + +#ifdef CONFIG_GNUTLS +#include <gnutls/gnutls.h> +#endif + +#define TYPE_QCRYPTO_TLS_CREDS "tls-creds" +typedef struct QCryptoTLSCreds QCryptoTLSCreds; +DECLARE_INSTANCE_CHECKER(QCryptoTLSCreds, QCRYPTO_TLS_CREDS, + TYPE_QCRYPTO_TLS_CREDS) + +typedef struct QCryptoTLSCredsClass QCryptoTLSCredsClass; + +#define QCRYPTO_TLS_CREDS_DH_PARAMS "dh-params.pem" + + +/** + * QCryptoTLSCreds: + * + * The QCryptoTLSCreds object is an abstract base for different + * types of TLS handshake credentials. Most commonly the + * QCryptoTLSCredsX509 subclass will be used to provide x509 + * certificate credentials. + */ + +struct QCryptoTLSCreds { + Object parent_obj; + char *dir; + QCryptoTLSCredsEndpoint endpoint; +#ifdef CONFIG_GNUTLS + gnutls_dh_params_t dh_params; +#endif + bool verifyPeer; + char *priority; +}; + + +struct QCryptoTLSCredsClass { + ObjectClass parent_class; +}; + + +#endif /* QCRYPTO_TLSCREDS_H */ diff --git a/include/crypto/tlscredsanon.h b/include/crypto/tlscredsanon.h new file mode 100644 index 000000000..3f464a380 --- /dev/null +++ b/include/crypto/tlscredsanon.h @@ -0,0 +1,112 @@ +/* + * QEMU crypto TLS anonymous credential support + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_TLSCREDSANON_H +#define QCRYPTO_TLSCREDSANON_H + +#include "crypto/tlscreds.h" +#include "qom/object.h" + +#define TYPE_QCRYPTO_TLS_CREDS_ANON "tls-creds-anon" +typedef struct QCryptoTLSCredsAnon QCryptoTLSCredsAnon; +DECLARE_INSTANCE_CHECKER(QCryptoTLSCredsAnon, QCRYPTO_TLS_CREDS_ANON, + TYPE_QCRYPTO_TLS_CREDS_ANON) + + +typedef struct QCryptoTLSCredsAnonClass QCryptoTLSCredsAnonClass; + +/** + * QCryptoTLSCredsAnon: + * + * The QCryptoTLSCredsAnon object provides a representation + * of anonymous credentials used perform a TLS handshake. + * This is primarily provided for backwards compatibility and + * its use is discouraged as it has poor security characteristics + * due to lacking MITM attack protection amongst other problems. + * + * This is a user creatable object, which can be instantiated + * via object_new_propv(): + * + * <example> + * <title>Creating anonymous TLS credential objects in code</title> + * <programlisting> + * Object *obj; + * Error *err = NULL; + * obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_ANON, + * "tlscreds0", + * &err, + * "endpoint", "server", + * "dir", "/path/x509/cert/dir", + * "verify-peer", "yes", + * NULL); + * </programlisting> + * </example> + * + * Or via QMP: + * + * <example> + * <title>Creating anonymous TLS credential objects via QMP</title> + * <programlisting> + * { + * "execute": "object-add", "arguments": { + * "id": "tlscreds0", + * "qom-type": "tls-creds-anon", + * "props": { + * "endpoint": "server", + * "dir": "/path/to/x509/cert/dir", + * "verify-peer": false + * } + * } + * } + * </programlisting> + * </example> + * + * + * Or via the CLI: + * + * <example> + * <title>Creating anonymous TLS credential objects via CLI</title> + * <programlisting> + * qemu-system-x86_64 -object tls-creds-anon,id=tlscreds0,\ + * endpoint=server,verify-peer=off,\ + * dir=/path/to/x509/certdir/ + * </programlisting> + * </example> + * + */ + + +struct QCryptoTLSCredsAnon { + QCryptoTLSCreds parent_obj; +#ifdef CONFIG_GNUTLS + union { + gnutls_anon_server_credentials_t server; + gnutls_anon_client_credentials_t client; + } data; +#endif +}; + + +struct QCryptoTLSCredsAnonClass { + QCryptoTLSCredsClass parent_class; +}; + + +#endif /* QCRYPTO_TLSCREDSANON_H */ diff --git a/include/crypto/tlscredspsk.h b/include/crypto/tlscredspsk.h new file mode 100644 index 000000000..d7e6bdb5e --- /dev/null +++ b/include/crypto/tlscredspsk.h @@ -0,0 +1,107 @@ +/* + * QEMU crypto TLS Pre-Shared Key (PSK) support + * + * Copyright (c) 2018 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_TLSCREDSPSK_H +#define QCRYPTO_TLSCREDSPSK_H + +#include "crypto/tlscreds.h" +#include "qom/object.h" + +#define TYPE_QCRYPTO_TLS_CREDS_PSK "tls-creds-psk" +typedef struct QCryptoTLSCredsPSK QCryptoTLSCredsPSK; +DECLARE_INSTANCE_CHECKER(QCryptoTLSCredsPSK, QCRYPTO_TLS_CREDS_PSK, + TYPE_QCRYPTO_TLS_CREDS_PSK) + +typedef struct QCryptoTLSCredsPSKClass QCryptoTLSCredsPSKClass; + +#define QCRYPTO_TLS_CREDS_PSKFILE "keys.psk" + +/** + * QCryptoTLSCredsPSK: + * + * The QCryptoTLSCredsPSK object provides a representation + * of the Pre-Shared Key credential used to perform a TLS handshake. + * + * This is a user creatable object, which can be instantiated + * via object_new_propv(): + * + * <example> + * <title>Creating TLS-PSK credential objects in code</title> + * <programlisting> + * Object *obj; + * Error *err = NULL; + * obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_PSK, + * "tlscreds0", + * &err, + * "dir", "/path/to/dir", + * "endpoint", "client", + * NULL); + * </programlisting> + * </example> + * + * Or via QMP: + * + * <example> + * <title>Creating TLS-PSK credential objects via QMP</title> + * <programlisting> + * { + * "execute": "object-add", "arguments": { + * "id": "tlscreds0", + * "qom-type": "tls-creds-psk", + * "props": { + * "dir": "/path/to/dir", + * "endpoint": "client" + * } + * } + * } + * </programlisting> + * </example> + * + * Or via the CLI: + * + * <example> + * <title>Creating TLS-PSK credential objects via CLI</title> + * <programlisting> + * qemu-system-x86_64 --object tls-creds-psk,id=tlscreds0,\ + * endpoint=client,dir=/path/to/dir[,username=qemu] + * </programlisting> + * </example> + * + * The PSK file can be created and managed using psktool. + */ + +struct QCryptoTLSCredsPSK { + QCryptoTLSCreds parent_obj; + char *username; +#ifdef CONFIG_GNUTLS + union { + gnutls_psk_server_credentials_t server; + gnutls_psk_client_credentials_t client; + } data; +#endif +}; + + +struct QCryptoTLSCredsPSKClass { + QCryptoTLSCredsClass parent_class; +}; + + +#endif /* QCRYPTO_TLSCREDSPSK_H */ diff --git a/include/crypto/tlscredsx509.h b/include/crypto/tlscredsx509.h new file mode 100644 index 000000000..c6d89b788 --- /dev/null +++ b/include/crypto/tlscredsx509.h @@ -0,0 +1,114 @@ +/* + * QEMU crypto TLS x509 credential support + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_TLSCREDSX509_H +#define QCRYPTO_TLSCREDSX509_H + +#include "crypto/tlscreds.h" +#include "qom/object.h" + +#define TYPE_QCRYPTO_TLS_CREDS_X509 "tls-creds-x509" +typedef struct QCryptoTLSCredsX509 QCryptoTLSCredsX509; +DECLARE_INSTANCE_CHECKER(QCryptoTLSCredsX509, QCRYPTO_TLS_CREDS_X509, + TYPE_QCRYPTO_TLS_CREDS_X509) + +typedef struct QCryptoTLSCredsX509Class QCryptoTLSCredsX509Class; + +#define QCRYPTO_TLS_CREDS_X509_CA_CERT "ca-cert.pem" +#define QCRYPTO_TLS_CREDS_X509_CA_CRL "ca-crl.pem" +#define QCRYPTO_TLS_CREDS_X509_SERVER_KEY "server-key.pem" +#define QCRYPTO_TLS_CREDS_X509_SERVER_CERT "server-cert.pem" +#define QCRYPTO_TLS_CREDS_X509_CLIENT_KEY "client-key.pem" +#define QCRYPTO_TLS_CREDS_X509_CLIENT_CERT "client-cert.pem" + + +/** + * QCryptoTLSCredsX509: + * + * The QCryptoTLSCredsX509 object provides a representation + * of x509 credentials used to perform a TLS handshake. + * + * This is a user creatable object, which can be instantiated + * via object_new_propv(): + * + * <example> + * <title>Creating x509 TLS credential objects in code</title> + * <programlisting> + * Object *obj; + * Error *err = NULL; + * obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_X509, + * "tlscreds0", + * &err, + * "endpoint", "server", + * "dir", "/path/x509/cert/dir", + * "verify-peer", "yes", + * NULL); + * </programlisting> + * </example> + * + * Or via QMP: + * + * <example> + * <title>Creating x509 TLS credential objects via QMP</title> + * <programlisting> + * { + * "execute": "object-add", "arguments": { + * "id": "tlscreds0", + * "qom-type": "tls-creds-x509", + * "props": { + * "endpoint": "server", + * "dir": "/path/to/x509/cert/dir", + * "verify-peer": false + * } + * } + * } + * </programlisting> + * </example> + * + * + * Or via the CLI: + * + * <example> + * <title>Creating x509 TLS credential objects via CLI</title> + * <programlisting> + * qemu-system-x86_64 -object tls-creds-x509,id=tlscreds0,\ + * endpoint=server,verify-peer=off,\ + * dir=/path/to/x509/certdir/ + * </programlisting> + * </example> + * + */ + +struct QCryptoTLSCredsX509 { + QCryptoTLSCreds parent_obj; +#ifdef CONFIG_GNUTLS + gnutls_certificate_credentials_t data; +#endif + bool sanityCheck; + char *passwordid; +}; + + +struct QCryptoTLSCredsX509Class { + QCryptoTLSCredsClass parent_class; +}; + + +#endif /* QCRYPTO_TLSCREDSX509_H */ diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h new file mode 100644 index 000000000..15b9cef08 --- /dev/null +++ b/include/crypto/tlssession.h @@ -0,0 +1,324 @@ +/* + * QEMU crypto TLS session support + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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/>. + * + */ + +#ifndef QCRYPTO_TLSSESSION_H +#define QCRYPTO_TLSSESSION_H + +#include "crypto/tlscreds.h" + +/** + * QCryptoTLSSession: + * + * The QCryptoTLSSession object encapsulates the + * logic to integrate with a TLS providing library such + * as GNUTLS, to setup and run TLS sessions. + * + * The API is designed such that it has no assumption about + * the type of transport it is running over. It may be a + * traditional TCP socket, or something else entirely. The + * only requirement is a full-duplex stream of some kind. + * + * <example> + * <title>Using TLS session objects</title> + * <programlisting> + * static ssize_t mysock_send(const char *buf, size_t len, + * void *opaque) + * { + * int fd = GPOINTER_TO_INT(opaque); + * + * return write(*fd, buf, len); + * } + * + * static ssize_t mysock_recv(const char *buf, size_t len, + * void *opaque) + * { + * int fd = GPOINTER_TO_INT(opaque); + * + * return read(*fd, buf, len); + * } + * + * static int mysock_run_tls(int sockfd, + * QCryptoTLSCreds *creds, + * Error **errp) + * { + * QCryptoTLSSession *sess; + * + * sess = qcrypto_tls_session_new(creds, + * "vnc.example.com", + * NULL, + * QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, + * errp); + * if (sess == NULL) { + * return -1; + * } + * + * qcrypto_tls_session_set_callbacks(sess, + * mysock_send, + * mysock_recv + * GINT_TO_POINTER(fd)); + * + * while (1) { + * if (qcrypto_tls_session_handshake(sess, errp) < 0) { + * qcrypto_tls_session_free(sess); + * return -1; + * } + * + * switch(qcrypto_tls_session_get_handshake_status(sess)) { + * case QCRYPTO_TLS_HANDSHAKE_COMPLETE: + * if (qcrypto_tls_session_check_credentials(sess, errp) < )) { + * qcrypto_tls_session_free(sess); + * return -1; + * } + * goto done; + * case QCRYPTO_TLS_HANDSHAKE_RECVING: + * ...wait for GIO_IN event on fd... + * break; + * case QCRYPTO_TLS_HANDSHAKE_SENDING: + * ...wait for GIO_OUT event on fd... + * break; + * } + * } + * done: + * + * ....send/recv payload data on sess... + * + * qcrypto_tls_session_free(sess): + * } + * </programlisting> + * </example> + */ + +typedef struct QCryptoTLSSession QCryptoTLSSession; + + +/** + * qcrypto_tls_session_new: + * @creds: pointer to a TLS credentials object + * @hostname: optional hostname to validate + * @aclname: optional ACL to validate peer credentials against + * @endpoint: role of the TLS session, client or server + * @errp: pointer to a NULL-initialized error object + * + * Create a new TLS session object that will be used to + * negotiate a TLS session over an arbitrary data channel. + * The session object can operate as either the server or + * client, according to the value of the @endpoint argument. + * + * For clients, the @hostname parameter should hold the full + * unmodified hostname as requested by the user. This will + * be used to verify the against the hostname reported in + * the server's credentials (aka x509 certificate). + * + * The @aclname parameter (optionally) specifies the name + * of an access control list that will be used to validate + * the peer's credentials. For x509 credentials, the ACL + * will be matched against the CommonName shown in the peer's + * certificate. If the session is acting as a server, setting + * an ACL will require that the client provide a validate + * x509 client certificate. + * + * After creating the session object, the I/O callbacks + * must be set using the qcrypto_tls_session_set_callbacks() + * method. A TLS handshake sequence must then be completed + * using qcrypto_tls_session_handshake(), before payload + * data is permitted to be sent/received. + * + * The session object must be released by calling + * qcrypto_tls_session_free() when no longer required + * + * Returns: a TLS session object, or NULL on error. + */ +QCryptoTLSSession *qcrypto_tls_session_new(QCryptoTLSCreds *creds, + const char *hostname, + const char *aclname, + QCryptoTLSCredsEndpoint endpoint, + Error **errp); + +/** + * qcrypto_tls_session_free: + * @sess: the TLS session object + * + * Release all memory associated with the TLS session + * object previously allocated by qcrypto_tls_session_new() + */ +void qcrypto_tls_session_free(QCryptoTLSSession *sess); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free) + +/** + * qcrypto_tls_session_check_credentials: + * @sess: the TLS session object + * @errp: pointer to a NULL-initialized error object + * + * Validate the peer's credentials after a successful + * TLS handshake. It is an error to call this before + * qcrypto_tls_session_get_handshake_status() returns + * QCRYPTO_TLS_HANDSHAKE_COMPLETE + * + * Returns 0 if the credentials validated, -1 on error + */ +int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess, + Error **errp); + +typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const char *buf, + size_t len, + void *opaque); +typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf, + size_t len, + void *opaque); + +/** + * qcrypto_tls_session_set_callbacks: + * @sess: the TLS session object + * @writeFunc: callback for sending data + * @readFunc: callback to receiving data + * @opaque: data to pass to callbacks + * + * Sets the callback functions that are to be used for sending + * and receiving data on the underlying data channel. Typically + * the callbacks to write/read to/from a TCP socket, but there + * is no assumption made about the type of channel used. + * + * The @writeFunc callback will be passed the encrypted + * data to send to the remote peer. + * + * The @readFunc callback will be passed a pointer to fill + * with encrypted data received from the remote peer + */ +void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess, + QCryptoTLSSessionWriteFunc writeFunc, + QCryptoTLSSessionReadFunc readFunc, + void *opaque); + +/** + * qcrypto_tls_session_write: + * @sess: the TLS session object + * @buf: the plain text to send + * @len: the length of @buf + * + * Encrypt @len bytes of the data in @buf and send + * it to the remote peer using the callback previously + * registered with qcrypto_tls_session_set_callbacks() + * + * It is an error to call this before + * qcrypto_tls_session_get_handshake_status() returns + * QCRYPTO_TLS_HANDSHAKE_COMPLETE + * + * Returns: the number of bytes sent, or -1 on error + */ +ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess, + const char *buf, + size_t len); + +/** + * qcrypto_tls_session_read: + * @sess: the TLS session object + * @buf: to fill with plain text received + * @len: the length of @buf + * + * Receive up to @len bytes of data from the remote peer + * using the callback previously registered with + * qcrypto_tls_session_set_callbacks(), decrypt it and + * store it in @buf. + * + * It is an error to call this before + * qcrypto_tls_session_get_handshake_status() returns + * QCRYPTO_TLS_HANDSHAKE_COMPLETE + * + * Returns: the number of bytes received, or -1 on error + */ +ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess, + char *buf, + size_t len); + +/** + * qcrypto_tls_session_handshake: + * @sess: the TLS session object + * @errp: pointer to a NULL-initialized error object + * + * Start, or continue, a TLS handshake sequence. If + * the underlying data channel is non-blocking, then + * this method may return control before the handshake + * is complete. On non-blocking channels the + * qcrypto_tls_session_get_handshake_status() method + * should be used to determine whether the handshake + * has completed, or is waiting to send or receive + * data. In the latter cases, the caller should setup + * an event loop watch and call this method again + * once the underlying data channel is ready to read + * or write again + */ +int qcrypto_tls_session_handshake(QCryptoTLSSession *sess, + Error **errp); + +typedef enum { + QCRYPTO_TLS_HANDSHAKE_COMPLETE, + QCRYPTO_TLS_HANDSHAKE_SENDING, + QCRYPTO_TLS_HANDSHAKE_RECVING, +} QCryptoTLSSessionHandshakeStatus; + +/** + * qcrypto_tls_session_get_handshake_status: + * @sess: the TLS session object + * + * Check the status of the TLS handshake. This + * is used with non-blocking data channels to + * determine whether the handshake is waiting + * to send or receive further data to/from the + * remote peer. + * + * Once this returns QCRYPTO_TLS_HANDSHAKE_COMPLETE + * it is permitted to send/receive payload data on + * the channel + */ +QCryptoTLSSessionHandshakeStatus +qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess); + +/** + * qcrypto_tls_session_get_key_size: + * @sess: the TLS session object + * @errp: pointer to a NULL-initialized error object + * + * Check the size of the data channel encryption key + * + * Returns: the length in bytes of the encryption key + * or -1 on error + */ +int qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess, + Error **errp); + +/** + * qcrypto_tls_session_get_peer_name: + * @sess: the TLS session object + * + * Get the identified name of the remote peer. If the + * TLS session was negotiated using x509 certificate + * credentials, this will return the CommonName from + * the peer's certificate. If no identified name is + * available it will return NULL. + * + * The returned data must be released with g_free() + * when no longer required. + * + * Returns: the peer's name or NULL. + */ +char *qcrypto_tls_session_get_peer_name(QCryptoTLSSession *sess); + +#endif /* QCRYPTO_TLSSESSION_H */ diff --git a/include/crypto/xts.h b/include/crypto/xts.h new file mode 100644 index 000000000..f267b7824 --- /dev/null +++ b/include/crypto/xts.h @@ -0,0 +1,82 @@ +/* + * QEMU Crypto XTS cipher mode + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * 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.1 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/>. + * + * This code is originally derived from public domain / WTFPL code in + * LibTomCrypt crytographic library http://libtom.org. The XTS code + * was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com) + * to the LibTom Projects + * + */ + +#ifndef QCRYPTO_XTS_H +#define QCRYPTO_XTS_H + + +#define XTS_BLOCK_SIZE 16 + +typedef void xts_cipher_func(const void *ctx, + size_t length, + uint8_t *dst, + const uint8_t *src); + +/** + * xts_decrypt: + * @datactx: the cipher context for data decryption + * @tweakctx: the cipher context for tweak decryption + * @encfunc: the cipher function for encryption + * @decfunc: the cipher function for decryption + * @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes + * @length: the length of @dst and @src + * @dst: buffer to hold the decrypted plaintext + * @src: buffer providing the ciphertext + * + * Decrypts @src into @dst + */ +void xts_decrypt(const void *datactx, + const void *tweakctx, + xts_cipher_func *encfunc, + xts_cipher_func *decfunc, + uint8_t *iv, + size_t length, + uint8_t *dst, + const uint8_t *src); + +/** + * xts_decrypt: + * @datactx: the cipher context for data encryption + * @tweakctx: the cipher context for tweak encryption + * @encfunc: the cipher function for encryption + * @decfunc: the cipher function for decryption + * @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes + * @length: the length of @dst and @src + * @dst: buffer to hold the encrypted ciphertext + * @src: buffer providing the plaintext + * + * Decrypts @src into @dst + */ +void xts_encrypt(const void *datactx, + const void *tweakctx, + xts_cipher_func *encfunc, + xts_cipher_func *decfunc, + uint8_t *iv, + size_t length, + uint8_t *dst, + const uint8_t *src); + + +#endif /* QCRYPTO_XTS_H */ |