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