|  | /* | 
|  | * QEMU crypto TLS credential support | 
|  | * | 
|  | * Copyright (c) 2015 Red Hat, Inc. | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include "qemu/osdep.h" | 
|  | #include "qapi/error.h" | 
|  | #include "qapi-types-crypto.h" | 
|  | #include "qemu/module.h" | 
|  | #include "tlscredspriv.h" | 
|  | #include "trace.h" | 
|  |  | 
|  | #define DH_BITS 2048 | 
|  |  | 
|  | #ifdef CONFIG_GNUTLS | 
|  | int | 
|  | qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds, | 
|  | const char *filename, | 
|  | gnutls_dh_params_t *dh_params, | 
|  | Error **errp) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | trace_qcrypto_tls_creds_load_dh(creds, filename ? filename : "<generated>"); | 
|  |  | 
|  | if (filename == NULL) { | 
|  | ret = gnutls_dh_params_init(dh_params); | 
|  | if (ret < 0) { | 
|  | error_setg(errp, "Unable to initialize DH parameters: %s", | 
|  | gnutls_strerror(ret)); | 
|  | return -1; | 
|  | } | 
|  | ret = gnutls_dh_params_generate2(*dh_params, DH_BITS); | 
|  | if (ret < 0) { | 
|  | gnutls_dh_params_deinit(*dh_params); | 
|  | *dh_params = NULL; | 
|  | error_setg(errp, "Unable to generate DH parameters: %s", | 
|  | gnutls_strerror(ret)); | 
|  | return -1; | 
|  | } | 
|  | } else { | 
|  | GError *gerr = NULL; | 
|  | gchar *contents; | 
|  | gsize len; | 
|  | gnutls_datum_t data; | 
|  | if (!g_file_get_contents(filename, | 
|  | &contents, | 
|  | &len, | 
|  | &gerr)) { | 
|  |  | 
|  | error_setg(errp, "%s", gerr->message); | 
|  | g_error_free(gerr); | 
|  | return -1; | 
|  | } | 
|  | data.data = (unsigned char *)contents; | 
|  | data.size = len; | 
|  | ret = gnutls_dh_params_init(dh_params); | 
|  | if (ret < 0) { | 
|  | g_free(contents); | 
|  | error_setg(errp, "Unable to initialize DH parameters: %s", | 
|  | gnutls_strerror(ret)); | 
|  | return -1; | 
|  | } | 
|  | ret = gnutls_dh_params_import_pkcs3(*dh_params, | 
|  | &data, | 
|  | GNUTLS_X509_FMT_PEM); | 
|  | g_free(contents); | 
|  | if (ret < 0) { | 
|  | gnutls_dh_params_deinit(*dh_params); | 
|  | *dh_params = NULL; | 
|  | error_setg(errp, "Unable to load DH parameters from %s: %s", | 
|  | filename, gnutls_strerror(ret)); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | int | 
|  | qcrypto_tls_creds_get_path(QCryptoTLSCreds *creds, | 
|  | const char *filename, | 
|  | bool required, | 
|  | char **cred, | 
|  | Error **errp) | 
|  | { | 
|  | struct stat sb; | 
|  | int ret = -1; | 
|  |  | 
|  | if (!creds->dir) { | 
|  | if (required) { | 
|  | error_setg(errp, "Missing 'dir' property value"); | 
|  | return -1; | 
|  | } else { | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | *cred = g_strdup_printf("%s/%s", creds->dir, filename); | 
|  |  | 
|  | if (stat(*cred, &sb) < 0) { | 
|  | if (errno == ENOENT && !required) { | 
|  | ret = 0; | 
|  | } else { | 
|  | error_setg_errno(errp, errno, | 
|  | "Unable to access credentials %s", | 
|  | *cred); | 
|  | } | 
|  | g_free(*cred); | 
|  | *cred = NULL; | 
|  | goto cleanup; | 
|  | } | 
|  |  | 
|  | ret = 0; | 
|  | cleanup: | 
|  | trace_qcrypto_tls_creds_get_path(creds, filename, | 
|  | *cred ? *cred : "<none>"); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | #endif /* ! CONFIG_GNUTLS */ | 
|  |  | 
|  |  | 
|  | static void | 
|  | qcrypto_tls_creds_prop_set_verify(Object *obj, | 
|  | bool value, | 
|  | Error **errp G_GNUC_UNUSED) | 
|  | { | 
|  | QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); | 
|  |  | 
|  | creds->verifyPeer = value; | 
|  | } | 
|  |  | 
|  |  | 
|  | static bool | 
|  | qcrypto_tls_creds_prop_get_verify(Object *obj, | 
|  | Error **errp G_GNUC_UNUSED) | 
|  | { | 
|  | QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); | 
|  |  | 
|  | return creds->verifyPeer; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | qcrypto_tls_creds_prop_set_dir(Object *obj, | 
|  | const char *value, | 
|  | Error **errp G_GNUC_UNUSED) | 
|  | { | 
|  | QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); | 
|  |  | 
|  | creds->dir = g_strdup(value); | 
|  | } | 
|  |  | 
|  |  | 
|  | static char * | 
|  | qcrypto_tls_creds_prop_get_dir(Object *obj, | 
|  | Error **errp G_GNUC_UNUSED) | 
|  | { | 
|  | QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); | 
|  |  | 
|  | return g_strdup(creds->dir); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | qcrypto_tls_creds_prop_set_priority(Object *obj, | 
|  | const char *value, | 
|  | Error **errp G_GNUC_UNUSED) | 
|  | { | 
|  | QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); | 
|  |  | 
|  | creds->priority = g_strdup(value); | 
|  | } | 
|  |  | 
|  |  | 
|  | static char * | 
|  | qcrypto_tls_creds_prop_get_priority(Object *obj, | 
|  | Error **errp G_GNUC_UNUSED) | 
|  | { | 
|  | QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); | 
|  |  | 
|  | return g_strdup(creds->priority); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | qcrypto_tls_creds_prop_set_endpoint(Object *obj, | 
|  | int value, | 
|  | Error **errp G_GNUC_UNUSED) | 
|  | { | 
|  | QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); | 
|  |  | 
|  | creds->endpoint = value; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int | 
|  | qcrypto_tls_creds_prop_get_endpoint(Object *obj, | 
|  | Error **errp G_GNUC_UNUSED) | 
|  | { | 
|  | QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); | 
|  |  | 
|  | return creds->endpoint; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | qcrypto_tls_creds_class_init(ObjectClass *oc, void *data) | 
|  | { | 
|  | object_class_property_add_bool(oc, "verify-peer", | 
|  | qcrypto_tls_creds_prop_get_verify, | 
|  | qcrypto_tls_creds_prop_set_verify); | 
|  | object_class_property_add_str(oc, "dir", | 
|  | qcrypto_tls_creds_prop_get_dir, | 
|  | qcrypto_tls_creds_prop_set_dir); | 
|  | object_class_property_add_enum(oc, "endpoint", | 
|  | "QCryptoTLSCredsEndpoint", | 
|  | &QCryptoTLSCredsEndpoint_lookup, | 
|  | qcrypto_tls_creds_prop_get_endpoint, | 
|  | qcrypto_tls_creds_prop_set_endpoint); | 
|  | object_class_property_add_str(oc, "priority", | 
|  | qcrypto_tls_creds_prop_get_priority, | 
|  | qcrypto_tls_creds_prop_set_priority); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | qcrypto_tls_creds_init(Object *obj) | 
|  | { | 
|  | QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); | 
|  |  | 
|  | creds->verifyPeer = true; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | qcrypto_tls_creds_finalize(Object *obj) | 
|  | { | 
|  | QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); | 
|  |  | 
|  | g_free(creds->dir); | 
|  | g_free(creds->priority); | 
|  | } | 
|  |  | 
|  | bool qcrypto_tls_creds_check_endpoint(QCryptoTLSCreds *creds, | 
|  | QCryptoTLSCredsEndpoint endpoint, | 
|  | Error **errp) | 
|  | { | 
|  | if (creds->endpoint != endpoint) { | 
|  | error_setg(errp, "Expected TLS credentials for a %s endpoint", | 
|  | QCryptoTLSCredsEndpoint_str(endpoint)); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static const TypeInfo qcrypto_tls_creds_info = { | 
|  | .parent = TYPE_OBJECT, | 
|  | .name = TYPE_QCRYPTO_TLS_CREDS, | 
|  | .instance_size = sizeof(QCryptoTLSCreds), | 
|  | .instance_init = qcrypto_tls_creds_init, | 
|  | .instance_finalize = qcrypto_tls_creds_finalize, | 
|  | .class_init = qcrypto_tls_creds_class_init, | 
|  | .class_size = sizeof(QCryptoTLSCredsClass), | 
|  | .abstract = true, | 
|  | }; | 
|  |  | 
|  |  | 
|  | static void | 
|  | qcrypto_tls_creds_register_types(void) | 
|  | { | 
|  | type_register_static(&qcrypto_tls_creds_info); | 
|  | } | 
|  |  | 
|  |  | 
|  | type_init(qcrypto_tls_creds_register_types); |