static void qio_channel_tls_finalize(Object *obj) { QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj); object_unref(OBJECT(ioc->master)); qcrypto_tls_session_free(ioc->session); }
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); char *prio; if (creds->priority != NULL) { prio = g_strdup_printf("%s:%s", creds->priority, TLS_PRIORITY_ADDITIONAL_ANON); } else { prio = g_strdup(CONFIG_TLS_PRIORITY ":" TLS_PRIORITY_ADDITIONAL_ANON); } ret = gnutls_priority_set_direct(session->handle, prio, NULL); if (ret < 0) { error_setg(errp, "Unable to set TLS session priority %s: %s", prio, gnutls_strerror(ret)); g_free(prio); goto error; } g_free(prio); 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_PSK)) { QCryptoTLSCredsPSK *pcreds = QCRYPTO_TLS_CREDS_PSK(creds); char *prio; if (creds->priority != NULL) { prio = g_strdup_printf("%s:%s", creds->priority, TLS_PRIORITY_ADDITIONAL_PSK); } else { prio = g_strdup(CONFIG_TLS_PRIORITY ":" TLS_PRIORITY_ADDITIONAL_PSK); } ret = gnutls_priority_set_direct(session->handle, prio, NULL); if (ret < 0) { error_setg(errp, "Unable to set TLS session priority %s: %s", prio, gnutls_strerror(ret)); g_free(prio); goto error; } g_free(prio); if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { ret = gnutls_credentials_set(session->handle, GNUTLS_CRD_PSK, pcreds->data.server); } else { ret = gnutls_credentials_set(session->handle, GNUTLS_CRD_PSK, pcreds->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); const char *prio = creds->priority; if (!prio) { prio = CONFIG_TLS_PRIORITY; } ret = gnutls_priority_set_direct(session->handle, prio, NULL); if (ret < 0) { error_setg(errp, "Cannot set default TLS session priority %s: %s", prio, 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; }