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