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