Commit 6f43024c90ec6de51e31193ebf6e6ea3b776652a
1 parent
469b15c6
Custom location for x509 cert paths, by Daniel P. Berrange.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3139 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
115 additions
and
16 deletions
vnc.c
... | ... | @@ -143,6 +143,11 @@ struct VncState |
143 | 143 | #if CONFIG_VNC_TLS |
144 | 144 | int subauth; |
145 | 145 | int x509verify; |
146 | + | |
147 | + char *x509cacert; | |
148 | + char *x509cacrl; | |
149 | + char *x509cert; | |
150 | + char *x509key; | |
146 | 151 | #endif |
147 | 152 | char challenge[VNC_AUTH_CHALLENGE_SIZE]; |
148 | 153 | |
... | ... | @@ -1386,37 +1391,49 @@ static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void) |
1386 | 1391 | } |
1387 | 1392 | |
1388 | 1393 | |
1389 | -static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(void) | |
1394 | +static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs) | |
1390 | 1395 | { |
1391 | 1396 | gnutls_certificate_credentials_t x509_cred; |
1392 | 1397 | int ret; |
1393 | - struct stat st; | |
1398 | + | |
1399 | + if (!vs->x509cacert) { | |
1400 | + VNC_DEBUG("No CA x509 certificate specified\n"); | |
1401 | + return NULL; | |
1402 | + } | |
1403 | + if (!vs->x509cert) { | |
1404 | + VNC_DEBUG("No server x509 certificate specified\n"); | |
1405 | + return NULL; | |
1406 | + } | |
1407 | + if (!vs->x509key) { | |
1408 | + VNC_DEBUG("No server private key specified\n"); | |
1409 | + return NULL; | |
1410 | + } | |
1394 | 1411 | |
1395 | 1412 | if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { |
1396 | 1413 | VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); |
1397 | 1414 | return NULL; |
1398 | 1415 | } |
1399 | - if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, X509_CA_CERT_FILE, GNUTLS_X509_FMT_PEM)) < 0) { | |
1416 | + if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, | |
1417 | + vs->x509cacert, | |
1418 | + GNUTLS_X509_FMT_PEM)) < 0) { | |
1400 | 1419 | VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); |
1401 | 1420 | gnutls_certificate_free_credentials(x509_cred); |
1402 | 1421 | return NULL; |
1403 | 1422 | } |
1404 | 1423 | |
1405 | - if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, X509_SERVER_CERT_FILE, | |
1406 | - X509_SERVER_KEY_FILE, | |
1424 | + if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, | |
1425 | + vs->x509cert, | |
1426 | + vs->x509key, | |
1407 | 1427 | GNUTLS_X509_FMT_PEM)) < 0) { |
1408 | 1428 | VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); |
1409 | 1429 | gnutls_certificate_free_credentials(x509_cred); |
1410 | 1430 | return NULL; |
1411 | 1431 | } |
1412 | 1432 | |
1413 | - if (stat(X509_CA_CRL_FILE, &st) < 0) { | |
1414 | - if (errno != ENOENT) { | |
1415 | - gnutls_certificate_free_credentials(x509_cred); | |
1416 | - return NULL; | |
1417 | - } | |
1418 | - } else { | |
1419 | - if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, X509_CA_CRL_FILE, GNUTLS_X509_FMT_PEM)) < 0) { | |
1433 | + if (vs->x509cacrl) { | |
1434 | + if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, | |
1435 | + vs->x509cacrl, | |
1436 | + GNUTLS_X509_FMT_PEM)) < 0) { | |
1420 | 1437 | VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); |
1421 | 1438 | gnutls_certificate_free_credentials(x509_cred); |
1422 | 1439 | return NULL; |
... | ... | @@ -1632,7 +1649,7 @@ static int vnc_start_tls(struct VncState *vs) { |
1632 | 1649 | } |
1633 | 1650 | |
1634 | 1651 | if (NEED_X509_AUTH(vs)) { |
1635 | - gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(); | |
1652 | + gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs); | |
1636 | 1653 | if (!x509_cred) { |
1637 | 1654 | gnutls_deinit(vs->tls_session); |
1638 | 1655 | vs->tls_session = NULL; |
... | ... | @@ -1903,6 +1920,63 @@ void vnc_display_init(DisplayState *ds) |
1903 | 1920 | vnc_dpy_resize(vs->ds, 640, 400); |
1904 | 1921 | } |
1905 | 1922 | |
1923 | +#if CONFIG_VNC_TLS | |
1924 | +static int vnc_set_x509_credential(VncState *vs, | |
1925 | + const char *certdir, | |
1926 | + const char *filename, | |
1927 | + char **cred, | |
1928 | + int ignoreMissing) | |
1929 | +{ | |
1930 | + struct stat sb; | |
1931 | + | |
1932 | + if (*cred) { | |
1933 | + qemu_free(*cred); | |
1934 | + *cred = NULL; | |
1935 | + } | |
1936 | + | |
1937 | + if (!(*cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2))) | |
1938 | + return -1; | |
1939 | + | |
1940 | + strcpy(*cred, certdir); | |
1941 | + strcat(*cred, "/"); | |
1942 | + strcat(*cred, filename); | |
1943 | + | |
1944 | + VNC_DEBUG("Check %s\n", *cred); | |
1945 | + if (stat(*cred, &sb) < 0) { | |
1946 | + qemu_free(*cred); | |
1947 | + *cred = NULL; | |
1948 | + if (ignoreMissing && errno == ENOENT) | |
1949 | + return 0; | |
1950 | + return -1; | |
1951 | + } | |
1952 | + | |
1953 | + return 0; | |
1954 | +} | |
1955 | + | |
1956 | +static int vnc_set_x509_credential_dir(VncState *vs, | |
1957 | + const char *certdir) | |
1958 | +{ | |
1959 | + if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0) | |
1960 | + goto cleanup; | |
1961 | + if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0) | |
1962 | + goto cleanup; | |
1963 | + if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0) | |
1964 | + goto cleanup; | |
1965 | + if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0) | |
1966 | + goto cleanup; | |
1967 | + | |
1968 | + return 0; | |
1969 | + | |
1970 | + cleanup: | |
1971 | + qemu_free(vs->x509cacert); | |
1972 | + qemu_free(vs->x509cacrl); | |
1973 | + qemu_free(vs->x509cert); | |
1974 | + qemu_free(vs->x509key); | |
1975 | + vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL; | |
1976 | + return -1; | |
1977 | +} | |
1978 | +#endif /* CONFIG_VNC_TLS */ | |
1979 | + | |
1906 | 1980 | void vnc_display_close(DisplayState *ds) |
1907 | 1981 | { |
1908 | 1982 | VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; |
... | ... | @@ -1986,11 +2060,36 @@ int vnc_display_open(DisplayState *ds, const char *display) |
1986 | 2060 | #if CONFIG_VNC_TLS |
1987 | 2061 | } else if (strncmp(options, "tls", 3) == 0) { |
1988 | 2062 | tls = 1; /* Require TLS */ |
1989 | - } else if (strncmp(options, "x509verify", 10) == 0) { | |
1990 | - x509 = 1; /* Require x509 certificates... */ | |
1991 | - vs->x509verify = 1;/* ...and verify client certs */ | |
1992 | 2063 | } else if (strncmp(options, "x509", 4) == 0) { |
2064 | + char *start, *end; | |
1993 | 2065 | x509 = 1; /* Require x509 certificates */ |
2066 | + if (strncmp(options, "x509verify", 10) == 0) | |
2067 | + vs->x509verify = 1; /* ...and verify client certs */ | |
2068 | + | |
2069 | + /* Now check for 'x509=/some/path' postfix | |
2070 | + * and use that to setup x509 certificate/key paths */ | |
2071 | + start = strchr(options, '='); | |
2072 | + end = strchr(options, ','); | |
2073 | + if (start && (!end || (start < end))) { | |
2074 | + int len = end ? end-(start+1) : strlen(start+1); | |
2075 | + char *path = qemu_malloc(len+1); | |
2076 | + strncpy(path, start+1, len); | |
2077 | + path[len] = '\0'; | |
2078 | + VNC_DEBUG("Trying certificate path '%s'\n", path); | |
2079 | + if (vnc_set_x509_credential_dir(vs, path) < 0) { | |
2080 | + fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path); | |
2081 | + qemu_free(path); | |
2082 | + qemu_free(vs->display); | |
2083 | + vs->display = NULL; | |
2084 | + return -1; | |
2085 | + } | |
2086 | + qemu_free(path); | |
2087 | + } else { | |
2088 | + fprintf(stderr, "No certificate path provided\n"); | |
2089 | + qemu_free(vs->display); | |
2090 | + vs->display = NULL; | |
2091 | + return -1; | |
2092 | + } | |
1994 | 2093 | #endif |
1995 | 2094 | } |
1996 | 2095 | } | ... | ... |