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,6 +143,11 @@ struct VncState | ||
143 | #if CONFIG_VNC_TLS | 143 | #if CONFIG_VNC_TLS |
144 | int subauth; | 144 | int subauth; |
145 | int x509verify; | 145 | int x509verify; |
146 | + | ||
147 | + char *x509cacert; | ||
148 | + char *x509cacrl; | ||
149 | + char *x509cert; | ||
150 | + char *x509key; | ||
146 | #endif | 151 | #endif |
147 | char challenge[VNC_AUTH_CHALLENGE_SIZE]; | 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,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 | gnutls_certificate_credentials_t x509_cred; | 1396 | gnutls_certificate_credentials_t x509_cred; |
1392 | int ret; | 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 | if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { | 1412 | if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { |
1396 | VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); | 1413 | VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); |
1397 | return NULL; | 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 | VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); | 1419 | VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); |
1401 | gnutls_certificate_free_credentials(x509_cred); | 1420 | gnutls_certificate_free_credentials(x509_cred); |
1402 | return NULL; | 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 | GNUTLS_X509_FMT_PEM)) < 0) { | 1427 | GNUTLS_X509_FMT_PEM)) < 0) { |
1408 | VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); | 1428 | VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); |
1409 | gnutls_certificate_free_credentials(x509_cred); | 1429 | gnutls_certificate_free_credentials(x509_cred); |
1410 | return NULL; | 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 | VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); | 1437 | VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); |
1421 | gnutls_certificate_free_credentials(x509_cred); | 1438 | gnutls_certificate_free_credentials(x509_cred); |
1422 | return NULL; | 1439 | return NULL; |
@@ -1632,7 +1649,7 @@ static int vnc_start_tls(struct VncState *vs) { | @@ -1632,7 +1649,7 @@ static int vnc_start_tls(struct VncState *vs) { | ||
1632 | } | 1649 | } |
1633 | 1650 | ||
1634 | if (NEED_X509_AUTH(vs)) { | 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 | if (!x509_cred) { | 1653 | if (!x509_cred) { |
1637 | gnutls_deinit(vs->tls_session); | 1654 | gnutls_deinit(vs->tls_session); |
1638 | vs->tls_session = NULL; | 1655 | vs->tls_session = NULL; |
@@ -1903,6 +1920,63 @@ void vnc_display_init(DisplayState *ds) | @@ -1903,6 +1920,63 @@ void vnc_display_init(DisplayState *ds) | ||
1903 | vnc_dpy_resize(vs->ds, 640, 400); | 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 | void vnc_display_close(DisplayState *ds) | 1980 | void vnc_display_close(DisplayState *ds) |
1907 | { | 1981 | { |
1908 | VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; | 1982 | VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; |
@@ -1986,11 +2060,36 @@ int vnc_display_open(DisplayState *ds, const char *display) | @@ -1986,11 +2060,36 @@ int vnc_display_open(DisplayState *ds, const char *display) | ||
1986 | #if CONFIG_VNC_TLS | 2060 | #if CONFIG_VNC_TLS |
1987 | } else if (strncmp(options, "tls", 3) == 0) { | 2061 | } else if (strncmp(options, "tls", 3) == 0) { |
1988 | tls = 1; /* Require TLS */ | 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 | } else if (strncmp(options, "x509", 4) == 0) { | 2063 | } else if (strncmp(options, "x509", 4) == 0) { |
2064 | + char *start, *end; | ||
1993 | x509 = 1; /* Require x509 certificates */ | 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 | #endif | 2093 | #endif |
1995 | } | 2094 | } |
1996 | } | 2095 | } |