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 | } |