|  | /* | 
|  | * 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 "tlscredspriv.h" | 
|  | #include "trace.h" | 
|  |  | 
|  | struct QCryptoTLSCipherSuites { | 
|  | /* <private> */ | 
|  | QCryptoTLSCreds parent_obj; | 
|  | /* <public> */ | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * 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++) { | 
|  | 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(QCryptoTLSCipherSuites), | 
|  | .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); |