| /* | 
 |  * 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); |