firmware (and crypto) patches
- add the tls-cipher-suites object, - add the ability to QOM objects to produce data consumable by the fw_cfg device, - let the tls-cipher-suites object implement the FW_CFG_DATA_GENERATOR interface. This is required by EDK2 'HTTPS Boot' feature of OVMF to tell the guest which TLS ciphers it can use. CI jobs results: https://travis-ci.org/github/philmd/qemu/builds/704724619 https://gitlab.com/philmd/qemu/-/pipelines/162938106 https://cirrus-ci.com/build/4682977303068672 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAl8AsDQACgkQ4+MsLN6t wN4HLA//Sxi7iYWp3OygX1F7A9XpWxuWNVjThBJzao00y0qxWQ7G6l/YTDeNYOoD dE/HsyUd3QtvC6/c79zoqyOb5m+WtQNsQmHAO4LZdR16TPNvTdCZ2lNgWYRIjuHJ obvYy2ingKpnlzd5V1bioTlUw0AOchk86pMnTVAsoKPXWqsOrPB+PYmE9tFRxqVY 5WVW7rnhtcJ05ajeIWhgndhW7fM4lvoWdZyctTIhWttQ9WkhyKAYKHQrmgOcsbUp soOfK9oHRH1XuUsC0SHpPmUQbp/c5cyCS1D7nDuIe/lPNNfWCVeUKkny495Vgj4d nK6MI1PQ4Bw2VBfMMxO4dXl2rnzlVjSnXXUP56IdfZHlOr+5gPh7uZvfZXN3AmHC km9MBt2IWrDYAriMwHhqumzHMIFmNVdqdXaYZYzagwwFzy8VNLgzQEFQYHsIXtl3 7pfvZVtIbSfXFGfktY3vu4sBZNAAk3mAOc04faF3CuTvXp5m0Duc0boO38eLDCbp 5mV2uEUJ9zQzcSoLqfLGiYCBFX9C8XdjdX+u9gMHhNb04y5c6r/zZZKpH7ZfwEc1 WdwXzEor+h3yW06dV1WdOGlMUqVt3Xx9GaJBW57XbdMQQ2O2m+TfMcYLeVLsXtvf aHUKOZdBxRKFcbA7zARhZ4xyzNQVddz3+aTGpzpP/xIL4TXrzHQ= =QArU -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/philmd-gitlab/tags/fw_cfg-20200704' into staging firmware (and crypto) patches - add the tls-cipher-suites object, - add the ability to QOM objects to produce data consumable by the fw_cfg device, - let the tls-cipher-suites object implement the FW_CFG_DATA_GENERATOR interface. This is required by EDK2 'HTTPS Boot' feature of OVMF to tell the guest which TLS ciphers it can use. CI jobs results: https://travis-ci.org/github/philmd/qemu/builds/704724619 https://gitlab.com/philmd/qemu/-/pipelines/162938106 https://cirrus-ci.com/build/4682977303068672 # gpg: Signature made Sat 04 Jul 2020 17:37:08 BST # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] # Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE * remotes/philmd-gitlab/tags/fw_cfg-20200704: crypto/tls-cipher-suites: Produce fw_cfg consumable blob softmmu/vl: Allow -fw_cfg 'gen_id' option to use the 'etc/' namespace softmmu/vl: Let -fw_cfg option take a 'gen_id' argument hw/nvram/fw_cfg: Add the FW_CFG_DATA_GENERATOR interface crypto: Add tls-cipher-suites object Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
aecdfcc3f8
@ -13,6 +13,7 @@ crypto-obj-y += cipher.o
|
|||||||
crypto-obj-$(CONFIG_AF_ALG) += afalg.o
|
crypto-obj-$(CONFIG_AF_ALG) += afalg.o
|
||||||
crypto-obj-$(CONFIG_AF_ALG) += cipher-afalg.o
|
crypto-obj-$(CONFIG_AF_ALG) += cipher-afalg.o
|
||||||
crypto-obj-$(CONFIG_AF_ALG) += hash-afalg.o
|
crypto-obj-$(CONFIG_AF_ALG) += hash-afalg.o
|
||||||
|
crypto-obj-$(CONFIG_GNUTLS) += tls-cipher-suites.o
|
||||||
crypto-obj-y += tlscreds.o
|
crypto-obj-y += tlscreds.o
|
||||||
crypto-obj-y += tlscredsanon.o
|
crypto-obj-y += tlscredsanon.o
|
||||||
crypto-obj-y += tlscredspsk.o
|
crypto-obj-y += tlscredspsk.o
|
||||||
|
126
crypto/tls-cipher-suites.c
Normal file
126
crypto/tls-cipher-suites.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* QEMU TLS Cipher Suites
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018-2020 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Author: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qom/object_interfaces.h"
|
||||||
|
#include "crypto/tlscreds.h"
|
||||||
|
#include "crypto/tls-cipher-suites.h"
|
||||||
|
#include "hw/nvram/fw_cfg.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IANA registered TLS ciphers:
|
||||||
|
* https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t data[2];
|
||||||
|
} QEMU_PACKED IANA_TLS_CIPHER;
|
||||||
|
|
||||||
|
GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
|
||||||
|
gnutls_priority_t pcache;
|
||||||
|
GByteArray *byte_array;
|
||||||
|
const char *err;
|
||||||
|
size_t i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
trace_qcrypto_tls_cipher_suite_priority(creds->priority);
|
||||||
|
ret = gnutls_priority_init(&pcache, creds->priority, &err);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Syntax error using priority '%s': %s",
|
||||||
|
creds->priority, gnutls_strerror(ret));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte_array = g_byte_array_new();
|
||||||
|
|
||||||
|
for (i = 0;; i++) {
|
||||||
|
int ret;
|
||||||
|
unsigned idx;
|
||||||
|
const char *name;
|
||||||
|
IANA_TLS_CIPHER cipher;
|
||||||
|
gnutls_protocol_t protocol;
|
||||||
|
const char *version;
|
||||||
|
|
||||||
|
ret = gnutls_priority_get_cipher_suite_index(pcache, i, &idx);
|
||||||
|
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = gnutls_cipher_suite_info(idx, (unsigned char *)&cipher,
|
||||||
|
NULL, NULL, NULL, &protocol);
|
||||||
|
if (name == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
version = gnutls_protocol_get_name(protocol);
|
||||||
|
g_byte_array_append(byte_array, cipher.data, 2);
|
||||||
|
trace_qcrypto_tls_cipher_suite_info(cipher.data[0],
|
||||||
|
cipher.data[1],
|
||||||
|
version, name);
|
||||||
|
}
|
||||||
|
trace_qcrypto_tls_cipher_suite_count(byte_array->len);
|
||||||
|
gnutls_priority_deinit(pcache);
|
||||||
|
|
||||||
|
return byte_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcrypto_tls_cipher_suites_complete(UserCreatable *uc,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(uc);
|
||||||
|
|
||||||
|
if (!creds->priority) {
|
||||||
|
error_setg(errp, "'priority' property is not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GByteArray *qcrypto_tls_cipher_suites_fw_cfg_gen_data(Object *obj,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return qcrypto_tls_cipher_suites_get_data(QCRYPTO_TLS_CIPHER_SUITES(obj),
|
||||||
|
errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcrypto_tls_cipher_suites_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||||
|
FWCfgDataGeneratorClass *fwgc = FW_CFG_DATA_GENERATOR_CLASS(oc);
|
||||||
|
|
||||||
|
ucc->complete = qcrypto_tls_cipher_suites_complete;
|
||||||
|
fwgc->get_data = qcrypto_tls_cipher_suites_fw_cfg_gen_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo qcrypto_tls_cipher_suites_info = {
|
||||||
|
.parent = TYPE_QCRYPTO_TLS_CREDS,
|
||||||
|
.name = TYPE_QCRYPTO_TLS_CIPHER_SUITES,
|
||||||
|
.instance_size = sizeof(QCryptoTLSCreds),
|
||||||
|
.class_size = sizeof(QCryptoTLSCredsClass),
|
||||||
|
.class_init = qcrypto_tls_cipher_suites_class_init,
|
||||||
|
.interfaces = (InterfaceInfo[]) {
|
||||||
|
{ TYPE_USER_CREATABLE },
|
||||||
|
{ TYPE_FW_CFG_DATA_GENERATOR_INTERFACE },
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void qcrypto_tls_cipher_suites_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&qcrypto_tls_cipher_suites_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(qcrypto_tls_cipher_suites_register_types);
|
@ -21,3 +21,8 @@ qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds
|
|||||||
# tlssession.c
|
# tlssession.c
|
||||||
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *authzid, int endpoint) "TLS session new session=%p creds=%p hostname=%s authzid=%s endpoint=%d"
|
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *authzid, int endpoint) "TLS session new session=%p creds=%p hostname=%s authzid=%s endpoint=%d"
|
||||||
qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s"
|
qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s"
|
||||||
|
|
||||||
|
# tls-cipher-suites.c
|
||||||
|
qcrypto_tls_cipher_suite_priority(const char *name) "priority: %s"
|
||||||
|
qcrypto_tls_cipher_suite_info(uint8_t data0, uint8_t data1, const char *version, const char *name) "data=[0x%02x,0x%02x] version=%s name=%s"
|
||||||
|
qcrypto_tls_cipher_suite_count(unsigned count) "count: %u"
|
||||||
|
@ -219,7 +219,7 @@ To check the result, read the "control" field:
|
|||||||
|
|
||||||
= Externally Provided Items =
|
= Externally Provided Items =
|
||||||
|
|
||||||
As of v2.4, "file" fw_cfg items (i.e., items with selector keys above
|
Since v2.4, "file" fw_cfg items (i.e., items with selector keys above
|
||||||
FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file
|
FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file
|
||||||
directory structure) may be inserted via the QEMU command line, using
|
directory structure) may be inserted via the QEMU command line, using
|
||||||
the following syntax:
|
the following syntax:
|
||||||
@ -230,6 +230,13 @@ Or
|
|||||||
|
|
||||||
-fw_cfg [name=]<item_name>,string=<string>
|
-fw_cfg [name=]<item_name>,string=<string>
|
||||||
|
|
||||||
|
Since v5.1, QEMU allows some objects to generate fw_cfg-specific content,
|
||||||
|
the content is then associated with a "file" item using the 'gen_id' option
|
||||||
|
in the command line, using the following syntax:
|
||||||
|
|
||||||
|
-object <generator-type>,id=<generated_id>,[generator-specific-options] \
|
||||||
|
-fw_cfg [name=]<item_name>,gen_id=<generated_id>
|
||||||
|
|
||||||
See QEMU man page for more documentation.
|
See QEMU man page for more documentation.
|
||||||
|
|
||||||
Using item_name with plain ASCII characters only is recommended.
|
Using item_name with plain ASCII characters only is recommended.
|
||||||
@ -251,4 +258,8 @@ Prefix "opt/org.qemu/" is reserved for QEMU itself.
|
|||||||
Use of names not beginning with "opt/" is potentially dangerous and
|
Use of names not beginning with "opt/" is potentially dangerous and
|
||||||
entirely unsupported. QEMU will warn if you try.
|
entirely unsupported. QEMU will warn if you try.
|
||||||
|
|
||||||
|
Use of names not beginning with "opt/" is tolerated with 'gen_id' (that
|
||||||
|
is, the warning is suppressed), but you must know exactly what you're
|
||||||
|
doing.
|
||||||
|
|
||||||
All externally provided fw_cfg items are read-only to the guest.
|
All externally provided fw_cfg items are read-only to the guest.
|
||||||
|
@ -1032,6 +1032,35 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fw_cfg_add_from_generator(FWCfgState *s, const char *filename,
|
||||||
|
const char *gen_id, Error **errp)
|
||||||
|
{
|
||||||
|
FWCfgDataGeneratorClass *klass;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
GByteArray *array;
|
||||||
|
Object *obj;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
|
obj = object_resolve_path_component(object_get_objects_root(), gen_id);
|
||||||
|
if (!obj) {
|
||||||
|
error_setg(errp, "Cannot find object ID '%s'", gen_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!object_dynamic_cast(obj, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE)) {
|
||||||
|
error_setg(errp, "Object ID '%s' is not a '%s' subclass",
|
||||||
|
gen_id, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
klass = FW_CFG_DATA_GENERATOR_GET_CLASS(obj);
|
||||||
|
array = klass->get_data(obj, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size = array->len;
|
||||||
|
fw_cfg_add_file(s, filename, g_byte_array_free(array, TRUE), size);
|
||||||
|
}
|
||||||
|
|
||||||
static void fw_cfg_machine_reset(void *opaque)
|
static void fw_cfg_machine_reset(void *opaque)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
||||||
@ -1333,12 +1362,18 @@ static const TypeInfo fw_cfg_mem_info = {
|
|||||||
.class_init = fw_cfg_mem_class_init,
|
.class_init = fw_cfg_mem_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const TypeInfo fw_cfg_data_generator_interface_info = {
|
||||||
|
.parent = TYPE_INTERFACE,
|
||||||
|
.name = TYPE_FW_CFG_DATA_GENERATOR_INTERFACE,
|
||||||
|
.class_size = sizeof(FWCfgDataGeneratorClass),
|
||||||
|
};
|
||||||
|
|
||||||
static void fw_cfg_register_types(void)
|
static void fw_cfg_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&fw_cfg_info);
|
type_register_static(&fw_cfg_info);
|
||||||
type_register_static(&fw_cfg_io_info);
|
type_register_static(&fw_cfg_io_info);
|
||||||
type_register_static(&fw_cfg_mem_info);
|
type_register_static(&fw_cfg_mem_info);
|
||||||
|
type_register_static(&fw_cfg_data_generator_interface_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(fw_cfg_register_types)
|
type_init(fw_cfg_register_types)
|
||||||
|
39
include/crypto/tls-cipher-suites.h
Normal file
39
include/crypto/tls-cipher-suites.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
#define QCRYPTO_TLS_CIPHER_SUITES(obj) \
|
||||||
|
OBJECT_CHECK(QCryptoTLSCipherSuites, (obj), TYPE_QCRYPTO_TLS_CIPHER_SUITES)
|
||||||
|
|
||||||
|
typedef struct QCryptoTLSCipherSuites {
|
||||||
|
/* <private> */
|
||||||
|
QCryptoTLSCreds parent_obj;
|
||||||
|
/* <public> */
|
||||||
|
} QCryptoTLSCipherSuites;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 */
|
@ -9,11 +9,36 @@
|
|||||||
#define TYPE_FW_CFG "fw_cfg"
|
#define TYPE_FW_CFG "fw_cfg"
|
||||||
#define TYPE_FW_CFG_IO "fw_cfg_io"
|
#define TYPE_FW_CFG_IO "fw_cfg_io"
|
||||||
#define TYPE_FW_CFG_MEM "fw_cfg_mem"
|
#define TYPE_FW_CFG_MEM "fw_cfg_mem"
|
||||||
|
#define TYPE_FW_CFG_DATA_GENERATOR_INTERFACE "fw_cfg-data-generator"
|
||||||
|
|
||||||
#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
|
#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
|
||||||
#define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO)
|
#define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO)
|
||||||
#define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM)
|
#define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM)
|
||||||
|
|
||||||
|
#define FW_CFG_DATA_GENERATOR_CLASS(class) \
|
||||||
|
OBJECT_CLASS_CHECK(FWCfgDataGeneratorClass, (class), \
|
||||||
|
TYPE_FW_CFG_DATA_GENERATOR_INTERFACE)
|
||||||
|
#define FW_CFG_DATA_GENERATOR_GET_CLASS(obj) \
|
||||||
|
OBJECT_GET_CLASS(FWCfgDataGeneratorClass, (obj), \
|
||||||
|
TYPE_FW_CFG_DATA_GENERATOR_INTERFACE)
|
||||||
|
|
||||||
|
typedef struct FWCfgDataGeneratorClass {
|
||||||
|
/*< private >*/
|
||||||
|
InterfaceClass parent_class;
|
||||||
|
/*< public >*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get_data:
|
||||||
|
* @obj: the object implementing this interface
|
||||||
|
* @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 *(*get_data)(Object *obj, Error **errp);
|
||||||
|
} FWCfgDataGeneratorClass;
|
||||||
|
|
||||||
typedef struct fw_cfg_file FWCfgFile;
|
typedef struct fw_cfg_file FWCfgFile;
|
||||||
|
|
||||||
#define FW_CFG_ORDER_OVERRIDE_VGA 70
|
#define FW_CFG_ORDER_OVERRIDE_VGA 70
|
||||||
@ -263,6 +288,24 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
|
|||||||
void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
|
void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
|
||||||
size_t len);
|
size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fw_cfg_add_from_generator:
|
||||||
|
* @s: fw_cfg device being modified
|
||||||
|
* @filename: name of new fw_cfg file item
|
||||||
|
* @gen_id: name of object implementing FW_CFG_DATA_GENERATOR interface
|
||||||
|
* @errp: pointer to a NULL initialized error object
|
||||||
|
*
|
||||||
|
* Add a new NAMED fw_cfg item with the content generated from the
|
||||||
|
* @gen_id object. The data generated by the @gen_id object is copied
|
||||||
|
* into the data structure of the fw_cfg device.
|
||||||
|
* The next available (unused) selector key starting at FW_CFG_FILE_FIRST
|
||||||
|
* will be used; also, a new entry will be added to the file directory
|
||||||
|
* structure residing at key value FW_CFG_FILE_DIR, containing the item name,
|
||||||
|
* data size, and assigned selector key value.
|
||||||
|
*/
|
||||||
|
void fw_cfg_add_from_generator(FWCfgState *s, const char *filename,
|
||||||
|
const char *gen_id, Error **errp);
|
||||||
|
|
||||||
FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
|
FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
|
||||||
AddressSpace *dma_as);
|
AddressSpace *dma_as);
|
||||||
FWCfgState *fw_cfg_init_io(uint32_t iobase);
|
FWCfgState *fw_cfg_init_io(uint32_t iobase);
|
||||||
|
@ -4579,6 +4579,43 @@ SRST
|
|||||||
string as described at
|
string as described at
|
||||||
https://gnutls.org/manual/html_node/Priority-Strings.html.
|
https://gnutls.org/manual/html_node/Priority-Strings.html.
|
||||||
|
|
||||||
|
``-object tls-cipher-suites,id=id,priority=priority``
|
||||||
|
Creates a TLS cipher suites object, which can be used to control
|
||||||
|
the TLS cipher/protocol algorithms that applications are permitted
|
||||||
|
to use.
|
||||||
|
|
||||||
|
The ``id`` parameter is a unique ID which frontends will use to
|
||||||
|
access the ordered list of permitted TLS cipher suites from the
|
||||||
|
host.
|
||||||
|
|
||||||
|
The ``priority`` parameter allows to override the global default
|
||||||
|
priority used by gnutls. This can be useful if the system
|
||||||
|
administrator needs to use a weaker set of crypto priorities for
|
||||||
|
QEMU without potentially forcing the weakness onto all
|
||||||
|
applications. Or conversely if one wants wants a stronger
|
||||||
|
default for QEMU than for all other applications, they can do
|
||||||
|
this through this parameter. Its format is a gnutls priority
|
||||||
|
string as described at
|
||||||
|
https://gnutls.org/manual/html_node/Priority-Strings.html.
|
||||||
|
|
||||||
|
An example of use of this object is to control UEFI HTTPS Boot.
|
||||||
|
The tls-cipher-suites object exposes the ordered list of permitted
|
||||||
|
TLS cipher suites from the host side to the guest firmware, via
|
||||||
|
fw_cfg. The list is represented as an array of IANA_TLS_CIPHER
|
||||||
|
objects. The firmware uses the IANA_TLS_CIPHER array for configuring
|
||||||
|
guest-side TLS.
|
||||||
|
|
||||||
|
In the following example, the priority at which the host-side policy
|
||||||
|
is retrieved is given by the ``priority`` property.
|
||||||
|
Given that QEMU uses GNUTLS, ``priority=@SYSTEM`` may be used to
|
||||||
|
refer to /etc/crypto-policies/back-ends/gnutls.config.
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
# |qemu_system| \
|
||||||
|
-object tls-cipher-suites,id=mysuite0,priority=@SYSTEM \
|
||||||
|
-fw_cfg name=etc/edk2/https/ciphers,gen_id=mysuite0
|
||||||
|
|
||||||
``-object filter-buffer,id=id,netdev=netdevid,interval=t[,queue=all|rx|tx][,status=on|off][,position=head|tail|id=<id>][,insert=behind|before]``
|
``-object filter-buffer,id=id,netdev=netdevid,interval=t[,queue=all|rx|tx][,status=on|off][,position=head|tail|id=<id>][,insert=behind|before]``
|
||||||
Interval t can't be 0, this filter batches the packet delivery:
|
Interval t can't be 0, this filter batches the packet delivery:
|
||||||
all packets arriving in a given interval on netdev netdevid are
|
all packets arriving in a given interval on netdev netdevid are
|
||||||
|
37
softmmu/vl.c
37
softmmu/vl.c
@ -489,6 +489,11 @@ static QemuOptsList qemu_fw_cfg_opts = {
|
|||||||
.name = "string",
|
.name = "string",
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "Sets content of the blob to be inserted from a string",
|
.help = "Sets content of the blob to be inserted from a string",
|
||||||
|
}, {
|
||||||
|
.name = "gen_id",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "Sets id of the object generating the fw_cfg blob "
|
||||||
|
"to be inserted",
|
||||||
},
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
@ -2020,7 +2025,7 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp)
|
|||||||
{
|
{
|
||||||
gchar *buf;
|
gchar *buf;
|
||||||
size_t size;
|
size_t size;
|
||||||
const char *name, *file, *str;
|
const char *name, *file, *str, *gen_id;
|
||||||
FWCfgState *fw_cfg = (FWCfgState *) opaque;
|
FWCfgState *fw_cfg = (FWCfgState *) opaque;
|
||||||
|
|
||||||
if (fw_cfg == NULL) {
|
if (fw_cfg == NULL) {
|
||||||
@ -2030,14 +2035,13 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp)
|
|||||||
name = qemu_opt_get(opts, "name");
|
name = qemu_opt_get(opts, "name");
|
||||||
file = qemu_opt_get(opts, "file");
|
file = qemu_opt_get(opts, "file");
|
||||||
str = qemu_opt_get(opts, "string");
|
str = qemu_opt_get(opts, "string");
|
||||||
|
gen_id = qemu_opt_get(opts, "gen_id");
|
||||||
|
|
||||||
/* we need name and either a file or the content string */
|
/* we need the name, and exactly one of: file, content string, gen_id */
|
||||||
if (!(nonempty_str(name) && (nonempty_str(file) || nonempty_str(str)))) {
|
if (!nonempty_str(name) ||
|
||||||
error_setg(errp, "invalid argument(s)");
|
nonempty_str(file) + nonempty_str(str) + nonempty_str(gen_id) != 1) {
|
||||||
return -1;
|
error_setg(errp, "name, plus exactly one of file,"
|
||||||
}
|
" string and gen_id, are needed");
|
||||||
if (nonempty_str(file) && nonempty_str(str)) {
|
|
||||||
error_setg(errp, "file and string are mutually exclusive");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (strlen(name) > FW_CFG_MAX_FILE_PATH - 1) {
|
if (strlen(name) > FW_CFG_MAX_FILE_PATH - 1) {
|
||||||
@ -2045,13 +2049,28 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp)
|
|||||||
FW_CFG_MAX_FILE_PATH - 1);
|
FW_CFG_MAX_FILE_PATH - 1);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (strncmp(name, "opt/", 4) != 0) {
|
if (nonempty_str(gen_id)) {
|
||||||
|
/*
|
||||||
|
* In this particular case where the content is populated
|
||||||
|
* internally, the "etc/" namespace protection is relaxed,
|
||||||
|
* so do not emit a warning.
|
||||||
|
*/
|
||||||
|
} else if (strncmp(name, "opt/", 4) != 0) {
|
||||||
warn_report("externally provided fw_cfg item names "
|
warn_report("externally provided fw_cfg item names "
|
||||||
"should be prefixed with \"opt/\"");
|
"should be prefixed with \"opt/\"");
|
||||||
}
|
}
|
||||||
if (nonempty_str(str)) {
|
if (nonempty_str(str)) {
|
||||||
size = strlen(str); /* NUL terminator NOT included in fw_cfg blob */
|
size = strlen(str); /* NUL terminator NOT included in fw_cfg blob */
|
||||||
buf = g_memdup(str, size);
|
buf = g_memdup(str, size);
|
||||||
|
} else if (nonempty_str(gen_id)) {
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
fw_cfg_add_from_generator(fw_cfg, name, gen_id, errp);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
if (!g_file_get_contents(file, &buf, &size, &err)) {
|
if (!g_file_get_contents(file, &buf, &size, &err)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user