On 03/22/2016 10:08 AM, Daniel P. Berrange wrote: > On Mon, Mar 21, 2016 at 02:29:00PM -0400, John Ferlan wrote: >> Add a masterKey to _qemuDomainObjPrivate to store a base64 encoded domain >> master key in order to support the ability to encrypt/decrypt sensitive >> data shared between libvirt and qemu. The base64 encoded value will be >> written to the domain XML file for consistency between domain restarts. > > Ohh, no, we don't want the master key to ever appear in any XML file, > because that in turn leads to compromise of user data when reporting > bugs. For example if the user provides the CLI args + runtime XML > then you can decrypt their passwords from the CLI args. The master > key must only ever be in its own file, which minimises the chance of > the user ever uploading the master key for their VM with bug reports. > OK - well that simplifies certain things; however, I would think that means on libvirtd restart we would then have to read the master key file in order to repopulate the priv->masterKey, right? >> Two APIs qemuDomainWriteMasterKeyFile and qemuDomainGetMasterKeyFilePath >> will manage the details of the file manipulation. >> >> The Get*Path API can be used in order to return a path to the master >> secret key file, which will be a combination of the domain's libDir >> (e.g. /var/lib/libvirt/qemu/domain-#-$NAME/) and a name 'master.key'. >> Use of the domain's libDir was chosen as opposed to a more generic >> /var/lib/libvirt/qemu/$NAME-master.key since it's a domain specific >> area rather than repeating issues found as a result of using the >> domain name in a file. The Get*Path API doesn't check if the >> libDir exists, it just generates the path. >> >> The Write*File API will be used to create the on disk master secret file >> once the domain lib infrastructure is generated during qemuProcessLaunch. >> >> The masterKey is generated as a series of 8 bit random numbers stored >> as a 32 byte string and then base64 encoded before saving in the domain >> private object. >> >> A separate function will generate the key as it's expected to be utilized >> by future patches to support the generation of the initialization vector. >> >> Object removal will clear and free the secret as well as check for the >> presence of the master key file and remove it if necessary (although it >> shouldn't be necessary by this point in time, but being extra safe). >> >> During process launch, the key value will additionally be stored in >> the domain libDir. This is what will be used to share the secret with >> qemu via a secret object. The secret file will only present while the >> domain is active (e.g. create at Launch, delete at Stop). > > Process launch is the place where we should *first* generate the > key and store it directly into the domain libDir. > > Also we should be generating a new key every time the guest > starts. There is no reason we need to persist the same key > forever, as it only needs to be valid for lifetime of a single > QEMU process. This further mimizes risks of actual user passwords > leaking, as they'll be encrypted with a new throw-away key every > time QEMU is started > It didn't dawn on me when first going through this that the priv was only generated once at define time. But yeah, now that that realization is fresh in my mind, I certainly see the point. I guess I was initially thinking that the object was generated later, but I never revisited once it became more obvious that the private object was generated when the domain was defined. I will move it... >> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c >> index 9f9fae3..507ae9e 100644 >> --- a/src/qemu/qemu_domain.c >> +++ b/src/qemu/qemu_domain.c >> @@ -23,6 +23,7 @@ >> >> #include <config.h> >> >> +#include <assert.h> > > We have a general rule that libvirt should never assert() in its > code, so don't add this. Errors should always propagate back > to a virErrorPtr. > > OK - although it is used today in virsh/vsh and remote_driver... >> +/* qemuDomainGenerateRandomKey >> + * @nbytes: Size in bytes of random key to generate - expect multiple of 8 >> + * >> + * Generate a random key of nbytes length and return it. >> + * >> + * Returns pointer memory containing key on success, NULL on failure >> + */ >> +static unsigned char * >> +qemuDomainGenerateRandomKey(int nbytes) >> +{ >> + unsigned char *key; >> + size_t i; >> + >> + assert((nbytes % 8) == 0); >> + >> + if (VIR_ALLOC_N(key, nbytes) < 0) >> + return NULL; >> + >> + /* Generate a random master key based on the nbytes passed */ >> + for (i = 0; i < nbytes; i++) >> + key[i] = virRandomBits(8); >> + >> + return key; >> +} > > The virRandomBits API doesn't provide cryptographically strong > random data. Since we already link to gnutls, we should call > out to > > ret = gnutls_rnd(GNUTLS_RND_RANDOM, key, nbytes); > Ahhh.. I wasn't aware of that API in gnutls - I was searching on "other" strings using cscope. Thanks for the feedback - John -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list