static int vnc_auth_sasl_check_access(VncState *vs) { const void *val; int err; int allow; err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val); if (err != SASL_OK) { VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n", err, sasl_errstring(err, NULL, NULL)); return -1; } if (val == NULL) { VNC_DEBUG("no client username was found, denying access\n"); return -1; } VNC_DEBUG("SASL client username %s\n", (const char *)val); vs->sasl.username = g_strdup((const char*)val); if (vs->vd->sasl.acl == NULL) { VNC_DEBUG("no ACL activated, allowing access\n"); return 0; } allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username); VNC_DEBUG("SASL client %s %s by ACL\n", vs->sasl.username, allow ? "allowed" : "denied"); return allow ? 0 : -1; }
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 vnc_tls_validate_certificate(struct VncState *vs) { int ret; unsigned int status; const gnutls_datum_t *certs; unsigned int nCerts, i; time_t now; VNC_DEBUG("Validating client certificate\n"); if ((ret = gnutls_certificate_verify_peers2 (vs->tls.session, &status)) < 0) { VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret)); return -1; } if ((now = time(NULL)) == ((time_t)-1)) { return -1; } if (status != 0) { if (status & GNUTLS_CERT_INVALID) VNC_DEBUG("The certificate is not trusted.\n"); if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) VNC_DEBUG("The certificate hasn't got a known issuer.\n"); if (status & GNUTLS_CERT_REVOKED) VNC_DEBUG("The certificate has been revoked.\n"); if (status & GNUTLS_CERT_INSECURE_ALGORITHM) VNC_DEBUG("The certificate uses an insecure algorithm\n"); return -1; } else { VNC_DEBUG("Certificate is valid!\n"); } /* Only support x509 for now */ if (gnutls_certificate_type_get(vs->tls.session) != GNUTLS_CRT_X509) return -1; if (!(certs = gnutls_certificate_get_peers(vs->tls.session, &nCerts))) return -1; for (i = 0 ; i < nCerts ; i++) { gnutls_x509_crt_t cert; VNC_DEBUG ("Checking certificate chain %d\n", i); if (gnutls_x509_crt_init (&cert) < 0) return -1; if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) { gnutls_x509_crt_deinit (cert); return -1; } if (gnutls_x509_crt_get_expiration_time (cert) < now) { VNC_DEBUG("The certificate has expired\n"); gnutls_x509_crt_deinit (cert); return -1; } if (gnutls_x509_crt_get_activation_time (cert) > now) { VNC_DEBUG("The certificate is not yet activated\n"); gnutls_x509_crt_deinit (cert); return -1; } if (gnutls_x509_crt_get_activation_time (cert) > now) { VNC_DEBUG("The certificate is not yet activated\n"); gnutls_x509_crt_deinit (cert); return -1; } if (i == 0) { size_t dnameSize = 1024; vs->tls.dname = g_malloc(dnameSize); requery: if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) { if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { vs->tls.dname = g_realloc(vs->tls.dname, dnameSize); goto requery; } gnutls_x509_crt_deinit (cert); VNC_DEBUG("Cannot get client distinguished name: %s", gnutls_strerror (ret)); return -1; } if (vs->vd->tls.x509verify) { int allow; if (!vs->vd->tls.acl) { VNC_DEBUG("no ACL activated, allowing access"); gnutls_x509_crt_deinit (cert); continue; } allow = qemu_acl_party_is_allowed(vs->vd->tls.acl, vs->tls.dname); VNC_DEBUG("TLS x509 ACL check for %s is %s\n", vs->tls.dname, allow ? "allowed" : "denied"); if (!allow) { gnutls_x509_crt_deinit (cert); return -1; } } } gnutls_x509_crt_deinit (cert); } return 0; }