From: Eric Blake <eblake@redhat.com>
To: "Daniel P. Berrange" <berrange@redhat.com>, qemu-devel@nongnu.org
Cc: Markus Armbruster <armbru@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v2 4/5] crypto: add QCryptoSecret object class for password/key handling
Date: Tue, 24 Nov 2015 11:29:55 -0700 [thread overview]
Message-ID: <5654ACA3.6030907@redhat.com> (raw)
In-Reply-To: <1448377362-18117-5-git-send-email-berrange@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 8484 bytes --]
On 11/24/2015 08:02 AM, Daniel P. Berrange wrote:
> Introduce a new QCryptoSecret object class which will be used
> for providing passwords and keys to other objects which need
> sensitive credentials.
>
> The new object can provide secret values directly as properties,
> or indirectly via a file. The latter includes support for file
> descriptor passing syntax on UNIX platforms. Ordinarily passing
> secret values directly as properties is insecure, since they
> are visible in process listings, or in log files showing the
> CLI args / QMP commands. It is possible to use AES-256-CBC to
> encrypt the secret values though, in which case all that is
> visible is the ciphertext. For adhoc developer testing though,
dictionary.com says it's always 'ad hoc' (since it is literally two
Latin words), even though the two are always spoken together in English.
And although 'ad-hoc' is starting to gain some traction in modern
usage, squashing it to 'adhoc' just feels like a typo.
> it is fine to provide the secrets directly without encryption
> so this is not explicitly forbidden.
>
> The anticipated scenario is that libvirtd will create a random
> master key per QEMU instance (eg /var/run/libvirt/qemu/$VMNAME.key)
> and will use that key to encrypt all passwords it provides to
> QEMU via '-object secret,....'. This avoids the need for libvirt
> (or other mgmt apps) to worry about file descriptor passing.
>
> It also makes life easier for people who are scripting the
> management of QEMU, for whom FD passing is significantly more
> complex.
>
> Providing data inline (insecure, only for adhoc dev testing)
Of course, if we touch it up in one place, you should use consistent
spelling throughout :)
>
> $QEMU -object secret,id=sec0,data=letmein
>
> Providing data indirectly in raw format
>
> printf "letmein" > mypasswd.txt
> $QEMU -object secret,id=sec0,file=mypasswd.txt
>
> Providing data indirectly in base64 format
>
> $QEMU -object secret,id=sec0,file=mykey.b64,format=base64
>
> Providing data with encryption
>
> $QEMU -object secret,id=master0,file=mykey.b64,format=base64 \
> -object secret,id=sec0,data=[base64 ciphertext],\
> keyid=master0,iv=[base64 IV],format=base64
>
> Note that 'format' here refers to the format of the ciphertext
> data. The decrypted data must always be in raw byte format.
>
> More examples are shown in the updated docs.
>
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
> +static void
> +qcrypto_secret_load_data(QCryptoSecret *secret,
> + uint8_t **output,
> + size_t *outputlen,
> + Error **errp)
> +{
> + int fd;
> + char *data = NULL;
> + size_t offset = 0;
> + size_t length = 0;
> +
> + *output = NULL;
> + *outputlen = 0;
> +
> + if (secret->file) {
> + if (secret->data) {
> + error_setg(errp,
> + "'file' and 'data' are mutually exclusive");
Is it worth trying to use a qapi flat union to make the mutual exclusion
inherent in the type definition, rather than something we have to
enforce manually? (I've got more experience with qapi than with Object,
so my question may be nonsensical)
> + return;
> + }
> + fd = qemu_open(secret->file, O_RDONLY);
> + if (fd < 0) {
> + error_setg_errno(errp, errno,
> + "Unable to open %s", secret->file);
Using error_setg_file_open() makes for a consistent message on open()
failure.
> + return;
> + }
> + while (length < (1024 * 1024)) { /* Limit secrets to 1 MB */
> + if ((length - offset) < 1024) {
> + length += 1024;
> + data = g_renew(char, data, length);
> + }
> + ssize_t ret = read(fd, data + offset, length - offset);
> + if (ret == 0) {
> + break;
> + }
> + if (ret < 0) {
> + error_setg_errno(errp, errno,
> + "Unable to read from %s", secret->file);
Does glib have a convenience function for reading contents of a file?
> + close(fd);
> + g_free(data);
> + return;
> + }
> + offset += ret;
> + }
> + close(fd);
> + if (offset) {
> + /* Even though data is raw 8-bit, so may contain
> + * arbitrary NULs, ensure it is explicitly NUL
> + * terminated */
> + *output = g_renew(uint8_t, data, offset + 1);
> + (*output)[offset] = '\0';
> + *outputlen = offset;
> + } else {
> + error_setg(errp, "Secret file %s is empty",
> + secret->file);
> + g_free(data);
> + }
> + } else if (secret->data) {
> + *outputlen = strlen(secret->data);
> + *output = g_new(uint8_t, *outputlen + 1);
> + memcpy(*output, secret->data, *outputlen + 1);
> + } else {
> + error_setg(errp, "Either 'file' or 'data' must be provided");
> + }
> +}
> +
> +
> +static void qcrypto_secret_decrypt(QCryptoSecret *secret,
> + const uint8_t *input,
> + size_t inputlen,
> + uint8_t **output,
> + size_t *outputlen,
> + Error **errp)
> +{
> + uint8_t *key = NULL, *ciphertext = NULL, *iv = NULL;
> + size_t keylen, ciphertextlen, ivlen;
> + QCryptoCipher *aes = NULL;
> + uint8_t *plaintext = NULL;
> +
> + *output = NULL;
> + *outputlen = 0;
> +
> + if (qcrypto_secret_lookup(secret->keyid,
> + &key, &keylen,
> + errp) < 0) {
> + goto cleanup;
> + }
> +
> + if (keylen != 32) {
> + error_setg(errp, "Key should be 32 bytes in length");
> + goto cleanup;
> + }
> +
> + if (!secret->iv) {
> + error_setg(errp, "IV is required to decrypt secret");
> + goto cleanup;
> + }
> +
> + iv = (uint8_t *)g_base64_decode(secret->iv, &ivlen);
Shouldn't this be using qbase64_decode()?
> +++ b/include/crypto/secret.h
> +/**
> + * 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.
> + *
> + * Providing data directly, insecurely (suitable for
> + * adhoc developer testing only)
Another instance.
> +++ b/qapi/crypto.json
> @@ -19,3 +19,17 @@
> { 'enum': 'QCryptoTLSCredsEndpoint',
> 'prefix': 'QCRYPTO_TLS_CREDS_ENDPOINT',
> 'data': ['client', 'server']}
> +
> +
> +##
> +# QCryptoSecretFormat:
> +#
> +# The data format that the secret is provided in
> +#
> +# @raw: raw bytes. When encoded in JSON only valid UTF-8 sequences can be used
> +# @base64: arbitrary base64 encoded binary data
> +# Since: 2.6
> +##
> +{ 'enum': 'QCryptoSecretFormat',
> + 'prefix': 'QCRYPTO_SECRET_FORMAT',
> + 'data': ['raw', 'base64']}
This part is fine.
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 0eea4ee..41c0e59 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -3677,6 +3677,83 @@ Dump the network traffic on netdev @var{dev} to the file specified by
> The file format is libpcap, so it can be analyzed with tools such as tcpdump
> or Wireshark.
>
> +@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}]
> +
> +Defines a secret to store a password, encryption key, or some other sensitive
> +data. The senstive data can either be passed directly via the @var{data}
s/senstive/sensitive/
> +parameter, or indirectly via the @var{file} parameter. Using the @var{data}
> +parameter is insecure unless the sensitive data is encrypted.
> +
Overall looks fairly reasonable.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
next prev parent reply other threads:[~2015-11-24 18:30 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-11-24 15:02 [Qemu-devel] [PATCH v2 0/5] Add framework for passing secrets to QEMU Daniel P. Berrange
2015-11-24 15:02 ` [Qemu-devel] [PATCH v2 1/5] util: add base64 decoding function Daniel P. Berrange
2015-11-24 15:54 ` Eric Blake
2015-11-24 16:02 ` Daniel P. Berrange
2015-11-24 15:02 ` [Qemu-devel] [PATCH v2 2/5] qemu-char: convert to use error checked base64 decode Daniel P. Berrange
2015-11-24 15:56 ` Eric Blake
2015-11-24 15:02 ` [Qemu-devel] [PATCH v2 3/5] qga: " Daniel P. Berrange
2015-11-24 16:39 ` Eric Blake
2015-11-24 15:02 ` [Qemu-devel] [PATCH v2 4/5] crypto: add QCryptoSecret object class for password/key handling Daniel P. Berrange
2015-11-24 18:29 ` Eric Blake [this message]
2015-11-24 18:52 ` Daniel P. Berrange
2015-11-24 15:02 ` [Qemu-devel] [PATCH v2 5/5] crypto: add support for loading encrypted x509 keys Daniel P. Berrange
2015-11-24 18:33 ` Eric Blake
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5654ACA3.6030907@redhat.com \
--to=eblake@redhat.com \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).