Commit 1d7b5b4a authored by Daniel P. Berrangé's avatar Daniel P. Berrangé
Browse files

crypto: add support for loading encrypted x509 keys



Make use of the QCryptoSecret object to support loading of
encrypted x509 keys. The optional 'passwordid' parameter
to the tls-creds-x509 object type, provides the ID of a
secret object instance that holds the decryption password
for the PEM file.

 # printf "123456" > mypasswd.txt
 # $QEMU \
    -object secret,id=sec0,filename=mypasswd.txt \
    -object tls-creds-x509,passwordid=sec0,id=creds0,\
            dir=/home/berrange/.pki/qemu,endpoint=server \
    -vnc :1,tls-creds=creds0

This requires QEMU to be linked to GNUTLS >= 3.1.11. If
GNUTLS is too old an error will be reported if an attempt
is made to pass a decryption password.

Reviewed-by: default avatarEric Blake <eblake@redhat.com>
Signed-off-by: default avatarDaniel P. Berrange <berrange@redhat.com>
parent ac1d8878
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@

#include "crypto/tlscredsx509.h"
#include "crypto/tlscredspriv.h"
#include "crypto/secret.h"
#include "qom/object_interfaces.h"
#include "trace.h"

@@ -607,9 +608,30 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
    }

    if (cert != NULL && key != NULL) {
#if GNUTLS_VERSION_NUMBER >= 0x030111
        char *password = NULL;
        if (creds->passwordid) {
            password = qcrypto_secret_lookup_as_utf8(creds->passwordid,
                                                     errp);
            if (!password) {
                goto cleanup;
            }
        }
        ret = gnutls_certificate_set_x509_key_file2(creds->data,
                                                    cert, key,
                                                    GNUTLS_X509_FMT_PEM,
                                                    password,
                                                    0);
        g_free(password);
#else /* GNUTLS_VERSION_NUMBER < 0x030111 */
        if (creds->passwordid) {
            error_setg(errp, "PKCS8 decryption requires GNUTLS >= 3.1.11");
            goto cleanup;
        }
        ret = gnutls_certificate_set_x509_key_file(creds->data,
                                                   cert, key,
                                                   GNUTLS_X509_FMT_PEM);
#endif /* GNUTLS_VERSION_NUMBER < 0x030111 */
        if (ret < 0) {
            error_setg(errp, "Cannot load certificate '%s' & key '%s': %s",
                       cert, key, gnutls_strerror(ret));
@@ -737,6 +759,27 @@ qcrypto_tls_creds_x509_prop_set_sanity(Object *obj,
}


static void
qcrypto_tls_creds_x509_prop_set_passwordid(Object *obj,
                                           const char *value,
                                           Error **errp G_GNUC_UNUSED)
{
    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);

    creds->passwordid = g_strdup(value);
}


static char *
qcrypto_tls_creds_x509_prop_get_passwordid(Object *obj,
                                           Error **errp G_GNUC_UNUSED)
{
    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);

    return g_strdup(creds->passwordid);
}


static bool
qcrypto_tls_creds_x509_prop_get_sanity(Object *obj,
                                       Error **errp G_GNUC_UNUSED)
@@ -769,6 +812,10 @@ qcrypto_tls_creds_x509_init(Object *obj)
                             qcrypto_tls_creds_x509_prop_get_sanity,
                             qcrypto_tls_creds_x509_prop_set_sanity,
                             NULL);
    object_property_add_str(obj, "passwordid",
                            qcrypto_tls_creds_x509_prop_get_passwordid,
                            qcrypto_tls_creds_x509_prop_set_passwordid,
                            NULL);
}


@@ -777,6 +824,7 @@ qcrypto_tls_creds_x509_finalize(Object *obj)
{
    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);

    g_free(creds->passwordid);
    qcrypto_tls_creds_x509_unload(creds);
}

+1 −0
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ struct QCryptoTLSCredsX509 {
    gnutls_certificate_credentials_t data;
#endif
    bool sanityCheck;
    char *passwordid;
};


+7 −1
Original line number Diff line number Diff line
@@ -3627,7 +3627,7 @@ expensive operation that consumes random pool entropy, so it is
recommended that a persistent set of parameters be generated
upfront and saved.

@item -object tls-creds-x509,id=@var{id},endpoint=@var{endpoint},dir=@var{/path/to/cred/dir},verify-peer=@var{on|off}
@item -object tls-creds-x509,id=@var{id},endpoint=@var{endpoint},dir=@var{/path/to/cred/dir},verify-peer=@var{on|off},passwordid=@var{id}

Creates a TLS anonymous credentials object, which can be used to provide
TLS support on network backends. The @option{id} parameter is a unique
@@ -3654,6 +3654,12 @@ in PEM format, in filenames @var{ca-cert.pem}, @var{ca-crl.pem} (optional),
@var{server-cert.pem} (only servers), @var{server-key.pem} (only servers),
@var{client-cert.pem} (only clients), and @var{client-key.pem} (only clients).

For the @var{server-key.pem} and @var{client-key.pem} files which
contain sensitive private keys, it is possible to use an encrypted
version by providing the @var{passwordid} parameter. This provides
the ID of a previously created @code{secret} object containing the
password for decryption.

@item -object filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@var{all|rx|tx}]

Interval @var{t} can't be 0, this filter batches the packet delivery: all