xref: /openbmc/qemu/crypto/tlscredsx509.c (revision 85bcbc78)
1 /*
2  * QEMU crypto TLS x509 credential support
3  *
4  * Copyright (c) 2015 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "crypto/tlscredsx509.h"
22 #include "crypto/tlscredspriv.h"
23 #include "qom/object_interfaces.h"
24 #include "trace.h"
25 
26 
27 #ifdef CONFIG_GNUTLS
28 
29 
30 static int
31 qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
32                             Error **errp)
33 {
34     char *cacert = NULL, *cacrl = NULL, *cert = NULL,
35         *key = NULL, *dhparams = NULL;
36     int ret;
37     int rv = -1;
38 
39     trace_qcrypto_tls_creds_x509_load(creds,
40             creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
41 
42     if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
43         if (qcrypto_tls_creds_get_path(&creds->parent_obj,
44                                        QCRYPTO_TLS_CREDS_X509_CA_CERT,
45                                        true, &cacert, errp) < 0 ||
46             qcrypto_tls_creds_get_path(&creds->parent_obj,
47                                        QCRYPTO_TLS_CREDS_X509_CA_CRL,
48                                        false, &cacrl, errp) < 0 ||
49             qcrypto_tls_creds_get_path(&creds->parent_obj,
50                                        QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
51                                        true, &cert, errp) < 0 ||
52             qcrypto_tls_creds_get_path(&creds->parent_obj,
53                                        QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
54                                        true, &key, errp) < 0 ||
55             qcrypto_tls_creds_get_path(&creds->parent_obj,
56                                        QCRYPTO_TLS_CREDS_DH_PARAMS,
57                                        false, &dhparams, errp) < 0) {
58             goto cleanup;
59         }
60     } else {
61         if (qcrypto_tls_creds_get_path(&creds->parent_obj,
62                                        QCRYPTO_TLS_CREDS_X509_CA_CERT,
63                                        true, &cacert, errp) < 0 ||
64             qcrypto_tls_creds_get_path(&creds->parent_obj,
65                                        QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
66                                        false, &cert, errp) < 0 ||
67             qcrypto_tls_creds_get_path(&creds->parent_obj,
68                                        QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
69                                        false, &key, errp) < 0) {
70             goto cleanup;
71         }
72     }
73 
74     ret = gnutls_certificate_allocate_credentials(&creds->data);
75     if (ret < 0) {
76         error_setg(errp, "Cannot allocate credentials: '%s'",
77                    gnutls_strerror(ret));
78         goto cleanup;
79     }
80 
81     ret = gnutls_certificate_set_x509_trust_file(creds->data,
82                                                  cacert,
83                                                  GNUTLS_X509_FMT_PEM);
84     if (ret < 0) {
85         error_setg(errp, "Cannot load CA certificate '%s': %s",
86                    cacert, gnutls_strerror(ret));
87         goto cleanup;
88     }
89 
90     if (cert != NULL && key != NULL) {
91         ret = gnutls_certificate_set_x509_key_file(creds->data,
92                                                    cert, key,
93                                                    GNUTLS_X509_FMT_PEM);
94         if (ret < 0) {
95             error_setg(errp, "Cannot load certificate '%s' & key '%s': %s",
96                        cert, key, gnutls_strerror(ret));
97             goto cleanup;
98         }
99     }
100 
101     if (cacrl != NULL) {
102         ret = gnutls_certificate_set_x509_crl_file(creds->data,
103                                                    cacrl,
104                                                    GNUTLS_X509_FMT_PEM);
105         if (ret < 0) {
106             error_setg(errp, "Cannot load CRL '%s': %s",
107                        cacrl, gnutls_strerror(ret));
108             goto cleanup;
109         }
110     }
111 
112     if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
113         if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
114                                                  &creds->parent_obj.dh_params,
115                                                  errp) < 0) {
116             goto cleanup;
117         }
118         gnutls_certificate_set_dh_params(creds->data,
119                                          creds->parent_obj.dh_params);
120     }
121 
122     rv = 0;
123  cleanup:
124     g_free(cacert);
125     g_free(cacrl);
126     g_free(cert);
127     g_free(key);
128     g_free(dhparams);
129     return rv;
130 }
131 
132 
133 static void
134 qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds)
135 {
136     if (creds->data) {
137         gnutls_certificate_free_credentials(creds->data);
138         creds->data = NULL;
139     }
140 }
141 
142 
143 #else /* ! CONFIG_GNUTLS */
144 
145 
146 static void
147 qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED,
148                             Error **errp)
149 {
150     error_setg(errp, "TLS credentials support requires GNUTLS");
151 }
152 
153 
154 static void
155 qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED)
156 {
157     /* nada */
158 }
159 
160 
161 #endif /* ! CONFIG_GNUTLS */
162 
163 
164 static void
165 qcrypto_tls_creds_x509_prop_set_loaded(Object *obj,
166                                        bool value,
167                                        Error **errp)
168 {
169     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
170 
171     if (value) {
172         qcrypto_tls_creds_x509_load(creds, errp);
173     } else {
174         qcrypto_tls_creds_x509_unload(creds);
175     }
176 }
177 
178 
179 #ifdef CONFIG_GNUTLS
180 
181 
182 static bool
183 qcrypto_tls_creds_x509_prop_get_loaded(Object *obj,
184                                        Error **errp G_GNUC_UNUSED)
185 {
186     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
187 
188     return creds->data != NULL;
189 }
190 
191 
192 #else /* ! CONFIG_GNUTLS */
193 
194 
195 static bool
196 qcrypto_tls_creds_x509_prop_get_loaded(Object *obj G_GNUC_UNUSED,
197                                        Error **errp G_GNUC_UNUSED)
198 {
199     return false;
200 }
201 
202 
203 #endif /* ! CONFIG_GNUTLS */
204 
205 
206 static void
207 qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp)
208 {
209     object_property_set_bool(OBJECT(uc), true, "loaded", errp);
210 }
211 
212 
213 static void
214 qcrypto_tls_creds_x509_init(Object *obj)
215 {
216     object_property_add_bool(obj, "loaded",
217                              qcrypto_tls_creds_x509_prop_get_loaded,
218                              qcrypto_tls_creds_x509_prop_set_loaded,
219                              NULL);
220 }
221 
222 
223 static void
224 qcrypto_tls_creds_x509_finalize(Object *obj)
225 {
226     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
227 
228     qcrypto_tls_creds_x509_unload(creds);
229 }
230 
231 
232 static void
233 qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data)
234 {
235     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
236 
237     ucc->complete = qcrypto_tls_creds_x509_complete;
238 }
239 
240 
241 static const TypeInfo qcrypto_tls_creds_x509_info = {
242     .parent = TYPE_QCRYPTO_TLS_CREDS,
243     .name = TYPE_QCRYPTO_TLS_CREDS_X509,
244     .instance_size = sizeof(QCryptoTLSCredsX509),
245     .instance_init = qcrypto_tls_creds_x509_init,
246     .instance_finalize = qcrypto_tls_creds_x509_finalize,
247     .class_size = sizeof(QCryptoTLSCredsX509Class),
248     .class_init = qcrypto_tls_creds_x509_class_init,
249     .interfaces = (InterfaceInfo[]) {
250         { TYPE_USER_CREATABLE },
251         { }
252     }
253 };
254 
255 
256 static void
257 qcrypto_tls_creds_x509_register_types(void)
258 {
259     type_register_static(&qcrypto_tls_creds_x509_info);
260 }
261 
262 
263 type_init(qcrypto_tls_creds_x509_register_types);
264