xref: /qemu/crypto/tls-cipher-suites.c (revision f9734d5d4078f17daf328b9e113aaffe3d00ecaf)
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 "hw/nvram/fw_cfg.h"
17  #include "tlscredspriv.h"
18  #include "trace.h"
19  
20  struct QCryptoTLSCipherSuites {
21      /* <private> */
22      QCryptoTLSCreds parent_obj;
23      /* <public> */
24  };
25  
26  /*
27   * IANA registered TLS ciphers:
28   * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
29   */
30  typedef struct {
31      uint8_t data[2];
32  } QEMU_PACKED IANA_TLS_CIPHER;
33  
34  GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj,
35                                                 Error **errp)
36  {
37      QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
38      gnutls_priority_t pcache;
39      GByteArray *byte_array;
40      const char *err;
41      size_t i;
42      int ret;
43  
44      trace_qcrypto_tls_cipher_suite_priority(creds->priority);
45      ret = gnutls_priority_init(&pcache, creds->priority, &err);
46      if (ret < 0) {
47          error_setg(errp, "Syntax error using priority '%s': %s",
48                     creds->priority, gnutls_strerror(ret));
49          return NULL;
50      }
51  
52      byte_array = g_byte_array_new();
53  
54      for (i = 0;; i++) {
55          int ret;
56          unsigned idx;
57          const char *name;
58          IANA_TLS_CIPHER cipher;
59          gnutls_protocol_t protocol;
60          const char *version;
61  
62          ret = gnutls_priority_get_cipher_suite_index(pcache, i, &idx);
63          if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
64              break;
65          }
66          if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE) {
67              continue;
68          }
69  
70          name = gnutls_cipher_suite_info(idx, (unsigned char *)&cipher,
71                                          NULL, NULL, NULL, &protocol);
72          if (name == NULL) {
73              continue;
74          }
75  
76          version = gnutls_protocol_get_name(protocol);
77          g_byte_array_append(byte_array, cipher.data, 2);
78          trace_qcrypto_tls_cipher_suite_info(cipher.data[0],
79                                              cipher.data[1],
80                                              version, name);
81      }
82      trace_qcrypto_tls_cipher_suite_count(byte_array->len);
83      gnutls_priority_deinit(pcache);
84  
85      return byte_array;
86  }
87  
88  static void qcrypto_tls_cipher_suites_complete(UserCreatable *uc,
89                                                 Error **errp)
90  {
91      QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(uc);
92  
93      if (!creds->priority) {
94          error_setg(errp, "'priority' property is not set");
95          return;
96      }
97  }
98  
99  static GByteArray *qcrypto_tls_cipher_suites_fw_cfg_gen_data(Object *obj,
100                                                               Error **errp)
101  {
102      return qcrypto_tls_cipher_suites_get_data(QCRYPTO_TLS_CIPHER_SUITES(obj),
103                                                errp);
104  }
105  
106  static void qcrypto_tls_cipher_suites_class_init(ObjectClass *oc, void *data)
107  {
108      UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
109      FWCfgDataGeneratorClass *fwgc = FW_CFG_DATA_GENERATOR_CLASS(oc);
110  
111      ucc->complete = qcrypto_tls_cipher_suites_complete;
112      fwgc->get_data = qcrypto_tls_cipher_suites_fw_cfg_gen_data;
113  }
114  
115  static const TypeInfo qcrypto_tls_cipher_suites_info = {
116      .parent = TYPE_QCRYPTO_TLS_CREDS,
117      .name = TYPE_QCRYPTO_TLS_CIPHER_SUITES,
118      .instance_size = sizeof(QCryptoTLSCipherSuites),
119      .class_size = sizeof(QCryptoTLSCredsClass),
120      .class_init = qcrypto_tls_cipher_suites_class_init,
121      .interfaces = (InterfaceInfo[]) {
122          { TYPE_USER_CREATABLE },
123          { TYPE_FW_CFG_DATA_GENERATOR_INTERFACE },
124          { }
125      }
126  };
127  
128  static void qcrypto_tls_cipher_suites_register_types(void)
129  {
130      type_register_static(&qcrypto_tls_cipher_suites_info);
131  }
132  
133  type_init(qcrypto_tls_cipher_suites_register_types);
134