/* * 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 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 "crypto/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_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, NULL); object_class_property_add_str(oc, "dir", qcrypto_tls_creds_prop_get_dir, qcrypto_tls_creds_prop_set_dir, NULL); object_class_property_add_enum(oc, "endpoint", "QCryptoTLSCredsEndpoint", QCryptoTLSCredsEndpoint_lookup, qcrypto_tls_creds_prop_get_endpoint, qcrypto_tls_creds_prop_set_endpoint, NULL); } 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); } 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);