xref: /openbmc/qemu/crypto/tls-cipher-suites.c (revision 3203148917d035b09f71986ac2eaa19a352d6d9d)
1 /*
2  * QEMU TLS Cipher Suites
3  *
4  * Copyright (c) 2018-2020 Red Hat, Inc.
5  *
6  * Author: Philippe Mathieu-Daudé <philmd@redhat.com>
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include "qemu/osdep.h"
12 #include "qapi/error.h"
13 #include "qom/object_interfaces.h"
14 #include "crypto/tlscreds.h"
15 #include "crypto/tls-cipher-suites.h"
16 #include "trace.h"
17 
18 /*
19  * IANA registered TLS ciphers:
20  * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
21  */
22 typedef struct {
23     uint8_t data[2];
24 } QEMU_PACKED IANA_TLS_CIPHER;
25 
26 GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj,
27                                                Error **errp)
28 {
29     QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
30     gnutls_priority_t pcache;
31     GByteArray *byte_array;
32     const char *err;
33     size_t i;
34     int ret;
35 
36     trace_qcrypto_tls_cipher_suite_priority(creds->priority);
37     ret = gnutls_priority_init(&pcache, creds->priority, &err);
38     if (ret < 0) {
39         error_setg(errp, "Syntax error using priority '%s': %s",
40                    creds->priority, gnutls_strerror(ret));
41         return NULL;
42     }
43 
44     byte_array = g_byte_array_new();
45 
46     for (i = 0;; i++) {
47         int ret;
48         unsigned idx;
49         const char *name;
50         IANA_TLS_CIPHER cipher;
51         gnutls_protocol_t protocol;
52         const char *version;
53 
54         ret = gnutls_priority_get_cipher_suite_index(pcache, i, &idx);
55         if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
56             break;
57         }
58         if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE) {
59             continue;
60         }
61 
62         name = gnutls_cipher_suite_info(idx, (unsigned char *)&cipher,
63                                         NULL, NULL, NULL, &protocol);
64         if (name == NULL) {
65             continue;
66         }
67 
68         version = gnutls_protocol_get_name(protocol);
69         g_byte_array_append(byte_array, cipher.data, 2);
70         trace_qcrypto_tls_cipher_suite_info(cipher.data[0],
71                                             cipher.data[1],
72                                             version, name);
73     }
74     trace_qcrypto_tls_cipher_suite_count(byte_array->len);
75     gnutls_priority_deinit(pcache);
76 
77     return byte_array;
78 }
79 
80 static void qcrypto_tls_cipher_suites_complete(UserCreatable *uc,
81                                                Error **errp)
82 {
83     QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(uc);
84 
85     if (!creds->priority) {
86         error_setg(errp, "'priority' property is not set");
87         return;
88     }
89 }
90 
91 static void qcrypto_tls_cipher_suites_class_init(ObjectClass *oc, void *data)
92 {
93     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
94 
95     ucc->complete = qcrypto_tls_cipher_suites_complete;
96 }
97 
98 static const TypeInfo qcrypto_tls_cipher_suites_info = {
99     .parent = TYPE_QCRYPTO_TLS_CREDS,
100     .name = TYPE_QCRYPTO_TLS_CIPHER_SUITES,
101     .instance_size = sizeof(QCryptoTLSCreds),
102     .class_size = sizeof(QCryptoTLSCredsClass),
103     .class_init = qcrypto_tls_cipher_suites_class_init,
104     .interfaces = (InterfaceInfo[]) {
105         { TYPE_USER_CREATABLE },
106         { }
107     }
108 };
109 
110 static void qcrypto_tls_cipher_suites_register_types(void)
111 {
112     type_register_static(&qcrypto_tls_cipher_suites_info);
113 }
114 
115 type_init(qcrypto_tls_cipher_suites_register_types);
116