summaryrefslogtreecommitdiffstats
path: root/qemu/crypto/tlssession.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/crypto/tlssession.c')
-rw-r--r--qemu/crypto/tlssession.c576
1 files changed, 0 insertions, 576 deletions
diff --git a/qemu/crypto/tlssession.c b/qemu/crypto/tlssession.c
deleted file mode 100644
index a543e5a57..000000000
--- a/qemu/crypto/tlssession.c
+++ /dev/null
@@ -1,576 +0,0 @@
-/*
- * QEMU crypto TLS session 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/tlssession.h"
-#include "crypto/tlscredsanon.h"
-#include "crypto/tlscredsx509.h"
-#include "qapi/error.h"
-#include "qemu/acl.h"
-#include "trace.h"
-
-#ifdef CONFIG_GNUTLS
-
-
-#include <gnutls/x509.h>
-
-
-struct QCryptoTLSSession {
- QCryptoTLSCreds *creds;
- gnutls_session_t handle;
- char *hostname;
- char *aclname;
- bool handshakeComplete;
- QCryptoTLSSessionWriteFunc writeFunc;
- QCryptoTLSSessionReadFunc readFunc;
- void *opaque;
- char *peername;
-};
-
-
-void
-qcrypto_tls_session_free(QCryptoTLSSession *session)
-{
- if (!session) {
- return;
- }
-
- gnutls_deinit(session->handle);
- g_free(session->hostname);
- g_free(session->peername);
- g_free(session->aclname);
- object_unref(OBJECT(session->creds));
- g_free(session);
-}
-
-
-static ssize_t
-qcrypto_tls_session_push(void *opaque, const void *buf, size_t len)
-{
- QCryptoTLSSession *session = opaque;
-
- if (!session->writeFunc) {
- errno = EIO;
- return -1;
- };
-
- return session->writeFunc(buf, len, session->opaque);
-}
-
-
-static ssize_t
-qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
-{
- QCryptoTLSSession *session = opaque;
-
- if (!session->readFunc) {
- errno = EIO;
- return -1;
- };
-
- return session->readFunc(buf, len, session->opaque);
-}
-
-
-QCryptoTLSSession *
-qcrypto_tls_session_new(QCryptoTLSCreds *creds,
- const char *hostname,
- const char *aclname,
- QCryptoTLSCredsEndpoint endpoint,
- Error **errp)
-{
- QCryptoTLSSession *session;
- int ret;
-
- session = g_new0(QCryptoTLSSession, 1);
- trace_qcrypto_tls_session_new(
- session, creds, hostname ? hostname : "<none>",
- aclname ? aclname : "<none>", endpoint);
-
- if (hostname) {
- session->hostname = g_strdup(hostname);
- }
- if (aclname) {
- session->aclname = g_strdup(aclname);
- }
- session->creds = creds;
- object_ref(OBJECT(creds));
-
- if (creds->endpoint != endpoint) {
- error_setg(errp, "Credentials endpoint doesn't match session");
- goto error;
- }
-
- if (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
- ret = gnutls_init(&session->handle, GNUTLS_SERVER);
- } else {
- ret = gnutls_init(&session->handle, GNUTLS_CLIENT);
- }
- if (ret < 0) {
- error_setg(errp, "Cannot initialize TLS session: %s",
- gnutls_strerror(ret));
- goto error;
- }
-
- if (object_dynamic_cast(OBJECT(creds),
- TYPE_QCRYPTO_TLS_CREDS_ANON)) {
- QCryptoTLSCredsAnon *acreds = QCRYPTO_TLS_CREDS_ANON(creds);
-
- ret = gnutls_priority_set_direct(session->handle,
- "NORMAL:+ANON-DH", NULL);
- if (ret < 0) {
- error_setg(errp, "Unable to set TLS session priority: %s",
- gnutls_strerror(ret));
- goto error;
- }
- if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
- ret = gnutls_credentials_set(session->handle,
- GNUTLS_CRD_ANON,
- acreds->data.server);
- } else {
- ret = gnutls_credentials_set(session->handle,
- GNUTLS_CRD_ANON,
- acreds->data.client);
- }
- if (ret < 0) {
- error_setg(errp, "Cannot set session credentials: %s",
- gnutls_strerror(ret));
- goto error;
- }
- } else if (object_dynamic_cast(OBJECT(creds),
- TYPE_QCRYPTO_TLS_CREDS_X509)) {
- QCryptoTLSCredsX509 *tcreds = QCRYPTO_TLS_CREDS_X509(creds);
-
- ret = gnutls_set_default_priority(session->handle);
- if (ret < 0) {
- error_setg(errp, "Cannot set default TLS session priority: %s",
- gnutls_strerror(ret));
- goto error;
- }
- ret = gnutls_credentials_set(session->handle,
- GNUTLS_CRD_CERTIFICATE,
- tcreds->data);
- if (ret < 0) {
- error_setg(errp, "Cannot set session credentials: %s",
- gnutls_strerror(ret));
- goto error;
- }
-
- if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
- /* This requests, but does not enforce a client cert.
- * The cert checking code later does enforcement */
- gnutls_certificate_server_set_request(session->handle,
- GNUTLS_CERT_REQUEST);
- }
- } else {
- error_setg(errp, "Unsupported TLS credentials type %s",
- object_get_typename(OBJECT(creds)));
- goto error;
- }
-
- gnutls_transport_set_ptr(session->handle, session);
- gnutls_transport_set_push_function(session->handle,
- qcrypto_tls_session_push);
- gnutls_transport_set_pull_function(session->handle,
- qcrypto_tls_session_pull);
-
- return session;
-
- error:
- qcrypto_tls_session_free(session);
- return NULL;
-}
-
-static int
-qcrypto_tls_session_check_certificate(QCryptoTLSSession *session,
- Error **errp)
-{
- int ret;
- unsigned int status;
- const gnutls_datum_t *certs;
- unsigned int nCerts, i;
- time_t now;
- gnutls_x509_crt_t cert = NULL;
-
- now = time(NULL);
- if (now == ((time_t)-1)) {
- error_setg_errno(errp, errno, "Cannot get current time");
- return -1;
- }
-
- ret = gnutls_certificate_verify_peers2(session->handle, &status);
- if (ret < 0) {
- error_setg(errp, "Verify failed: %s", gnutls_strerror(ret));
- return -1;
- }
-
- if (status != 0) {
- const char *reason = "Invalid certificate";
-
- if (status & GNUTLS_CERT_INVALID) {
- reason = "The certificate is not trusted";
- }
-
- if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
- reason = "The certificate hasn't got a known issuer";
- }
-
- if (status & GNUTLS_CERT_REVOKED) {
- reason = "The certificate has been revoked";
- }
-
- if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
- reason = "The certificate uses an insecure algorithm";
- }
-
- error_setg(errp, "%s", reason);
- return -1;
- }
-
- certs = gnutls_certificate_get_peers(session->handle, &nCerts);
- if (!certs) {
- error_setg(errp, "No certificate peers");
- return -1;
- }
-
- for (i = 0; i < nCerts; i++) {
- ret = gnutls_x509_crt_init(&cert);
- if (ret < 0) {
- error_setg(errp, "Cannot initialize certificate: %s",
- gnutls_strerror(ret));
- return -1;
- }
-
- ret = gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER);
- if (ret < 0) {
- error_setg(errp, "Cannot import certificate: %s",
- gnutls_strerror(ret));
- goto error;
- }
-
- if (gnutls_x509_crt_get_expiration_time(cert) < now) {
- error_setg(errp, "The certificate has expired");
- goto error;
- }
-
- if (gnutls_x509_crt_get_activation_time(cert) > now) {
- error_setg(errp, "The certificate is not yet activated");
- goto error;
- }
-
- if (gnutls_x509_crt_get_activation_time(cert) > now) {
- error_setg(errp, "The certificate is not yet activated");
- goto error;
- }
-
- if (i == 0) {
- size_t dnameSize = 1024;
- session->peername = g_malloc(dnameSize);
- requery:
- ret = gnutls_x509_crt_get_dn(cert, session->peername, &dnameSize);
- if (ret < 0) {
- if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
- session->peername = g_realloc(session->peername,
- dnameSize);
- goto requery;
- }
- error_setg(errp, "Cannot get client distinguished name: %s",
- gnutls_strerror(ret));
- goto error;
- }
- if (session->aclname) {
- qemu_acl *acl = qemu_acl_find(session->aclname);
- int allow;
- if (!acl) {
- error_setg(errp, "Cannot find ACL %s",
- session->aclname);
- goto error;
- }
-
- allow = qemu_acl_party_is_allowed(acl, session->peername);
-
- if (!allow) {
- error_setg(errp, "TLS x509 ACL check for %s is denied",
- session->peername);
- goto error;
- }
- }
- if (session->hostname) {
- if (!gnutls_x509_crt_check_hostname(cert, session->hostname)) {
- error_setg(errp,
- "Certificate does not match the hostname %s",
- session->hostname);
- goto error;
- }
- }
- }
-
- gnutls_x509_crt_deinit(cert);
- }
-
- return 0;
-
- error:
- gnutls_x509_crt_deinit(cert);
- return -1;
-}
-
-
-int
-qcrypto_tls_session_check_credentials(QCryptoTLSSession *session,
- Error **errp)
-{
- if (object_dynamic_cast(OBJECT(session->creds),
- TYPE_QCRYPTO_TLS_CREDS_ANON)) {
- return 0;
- } else if (object_dynamic_cast(OBJECT(session->creds),
- TYPE_QCRYPTO_TLS_CREDS_X509)) {
- if (session->creds->verifyPeer) {
- return qcrypto_tls_session_check_certificate(session,
- errp);
- } else {
- return 0;
- }
- } else {
- error_setg(errp, "Unexpected credential type %s",
- object_get_typename(OBJECT(session->creds)));
- return -1;
- }
-}
-
-
-void
-qcrypto_tls_session_set_callbacks(QCryptoTLSSession *session,
- QCryptoTLSSessionWriteFunc writeFunc,
- QCryptoTLSSessionReadFunc readFunc,
- void *opaque)
-{
- session->writeFunc = writeFunc;
- session->readFunc = readFunc;
- session->opaque = opaque;
-}
-
-
-ssize_t
-qcrypto_tls_session_write(QCryptoTLSSession *session,
- const char *buf,
- size_t len)
-{
- ssize_t ret = gnutls_record_send(session->handle, buf, len);
-
- if (ret < 0) {
- switch (ret) {
- case GNUTLS_E_AGAIN:
- errno = EAGAIN;
- break;
- case GNUTLS_E_INTERRUPTED:
- errno = EINTR;
- break;
- default:
- errno = EIO;
- break;
- }
- ret = -1;
- }
-
- return ret;
-}
-
-
-ssize_t
-qcrypto_tls_session_read(QCryptoTLSSession *session,
- char *buf,
- size_t len)
-{
- ssize_t ret = gnutls_record_recv(session->handle, buf, len);
-
- if (ret < 0) {
- switch (ret) {
- case GNUTLS_E_AGAIN:
- errno = EAGAIN;
- break;
- case GNUTLS_E_INTERRUPTED:
- errno = EINTR;
- break;
- default:
- errno = EIO;
- break;
- }
- ret = -1;
- }
-
- return ret;
-}
-
-
-int
-qcrypto_tls_session_handshake(QCryptoTLSSession *session,
- Error **errp)
-{
- int ret = gnutls_handshake(session->handle);
- if (ret == 0) {
- session->handshakeComplete = true;
- } else {
- if (ret == GNUTLS_E_INTERRUPTED ||
- ret == GNUTLS_E_AGAIN) {
- ret = 1;
- } else {
- error_setg(errp, "TLS handshake failed: %s",
- gnutls_strerror(ret));
- ret = -1;
- }
- }
-
- return ret;
-}
-
-
-QCryptoTLSSessionHandshakeStatus
-qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *session)
-{
- if (session->handshakeComplete) {
- return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
- } else if (gnutls_record_get_direction(session->handle) == 0) {
- return QCRYPTO_TLS_HANDSHAKE_RECVING;
- } else {
- return QCRYPTO_TLS_HANDSHAKE_SENDING;
- }
-}
-
-
-int
-qcrypto_tls_session_get_key_size(QCryptoTLSSession *session,
- Error **errp)
-{
- gnutls_cipher_algorithm_t cipher;
- int ssf;
-
- cipher = gnutls_cipher_get(session->handle);
- ssf = gnutls_cipher_get_key_size(cipher);
- if (!ssf) {
- error_setg(errp, "Cannot get TLS cipher key size");
- return -1;
- }
- return ssf;
-}
-
-
-char *
-qcrypto_tls_session_get_peer_name(QCryptoTLSSession *session)
-{
- if (session->peername) {
- return g_strdup(session->peername);
- }
- return NULL;
-}
-
-
-#else /* ! CONFIG_GNUTLS */
-
-
-QCryptoTLSSession *
-qcrypto_tls_session_new(QCryptoTLSCreds *creds G_GNUC_UNUSED,
- const char *hostname G_GNUC_UNUSED,
- const char *aclname G_GNUC_UNUSED,
- QCryptoTLSCredsEndpoint endpoint G_GNUC_UNUSED,
- Error **errp)
-{
- error_setg(errp, "TLS requires GNUTLS support");
- return NULL;
-}
-
-
-void
-qcrypto_tls_session_free(QCryptoTLSSession *sess G_GNUC_UNUSED)
-{
-}
-
-
-int
-qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess G_GNUC_UNUSED,
- Error **errp)
-{
- error_setg(errp, "TLS requires GNUTLS support");
- return -1;
-}
-
-
-void
-qcrypto_tls_session_set_callbacks(
- QCryptoTLSSession *sess G_GNUC_UNUSED,
- QCryptoTLSSessionWriteFunc writeFunc G_GNUC_UNUSED,
- QCryptoTLSSessionReadFunc readFunc G_GNUC_UNUSED,
- void *opaque G_GNUC_UNUSED)
-{
-}
-
-
-ssize_t
-qcrypto_tls_session_write(QCryptoTLSSession *sess,
- const char *buf,
- size_t len)
-{
- errno = -EIO;
- return -1;
-}
-
-
-ssize_t
-qcrypto_tls_session_read(QCryptoTLSSession *sess,
- char *buf,
- size_t len)
-{
- errno = -EIO;
- return -1;
-}
-
-
-int
-qcrypto_tls_session_handshake(QCryptoTLSSession *sess,
- Error **errp)
-{
- error_setg(errp, "TLS requires GNUTLS support");
- return -1;
-}
-
-
-QCryptoTLSSessionHandshakeStatus
-qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess)
-{
- return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
-}
-
-
-int
-qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess,
- Error **errp)
-{
- error_setg(errp, "TLS requires GNUTLS support");
- return -1;
-}
-
-
-char *
-qcrypto_tls_session_get_peer_name(QCryptoTLSSession *sess)
-{
- return NULL;
-}
-
-#endif