Commit 3a702699b26ba5116c153457d552c577383a9fa1
1 parent
8d5d2d4c
x509 certificate for server, by Daniel P. Berrange.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3137 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
107 additions
and
20 deletions
vnc.c
... | ... | @@ -105,6 +105,14 @@ enum { |
105 | 105 | VNC_AUTH_VENCRYPT_X509VNC = 261, |
106 | 106 | VNC_AUTH_VENCRYPT_X509PLAIN = 262, |
107 | 107 | }; |
108 | + | |
109 | +#if CONFIG_VNC_TLS | |
110 | +#define X509_CA_CERT_FILE "ca-cert.pem" | |
111 | +#define X509_CA_CRL_FILE "ca-crl.pem" | |
112 | +#define X509_SERVER_KEY_FILE "server-key.pem" | |
113 | +#define X509_SERVER_CERT_FILE "server-cert.pem" | |
114 | +#endif | |
115 | + | |
108 | 116 | #endif /* CONFIG_VNC_TLS */ |
109 | 117 | |
110 | 118 | struct VncState |
... | ... | @@ -1377,16 +1385,60 @@ static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void) |
1377 | 1385 | } |
1378 | 1386 | |
1379 | 1387 | |
1388 | +static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(void) | |
1389 | +{ | |
1390 | + gnutls_certificate_credentials_t x509_cred; | |
1391 | + int ret; | |
1392 | + struct stat st; | |
1393 | + | |
1394 | + if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { | |
1395 | + VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); | |
1396 | + return NULL; | |
1397 | + } | |
1398 | + if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, X509_CA_CERT_FILE, GNUTLS_X509_FMT_PEM)) < 0) { | |
1399 | + VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); | |
1400 | + gnutls_certificate_free_credentials(x509_cred); | |
1401 | + return NULL; | |
1402 | + } | |
1403 | + | |
1404 | + if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, X509_SERVER_CERT_FILE, | |
1405 | + X509_SERVER_KEY_FILE, | |
1406 | + GNUTLS_X509_FMT_PEM)) < 0) { | |
1407 | + VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); | |
1408 | + gnutls_certificate_free_credentials(x509_cred); | |
1409 | + return NULL; | |
1410 | + } | |
1411 | + | |
1412 | + if (stat(X509_CA_CRL_FILE, &st) < 0) { | |
1413 | + if (errno != ENOENT) { | |
1414 | + gnutls_certificate_free_credentials(x509_cred); | |
1415 | + return NULL; | |
1416 | + } | |
1417 | + } else { | |
1418 | + if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, X509_CA_CRL_FILE, GNUTLS_X509_FMT_PEM)) < 0) { | |
1419 | + VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); | |
1420 | + gnutls_certificate_free_credentials(x509_cred); | |
1421 | + return NULL; | |
1422 | + } | |
1423 | + } | |
1424 | + | |
1425 | + gnutls_certificate_set_dh_params (x509_cred, dh_params); | |
1426 | + | |
1427 | + return x509_cred; | |
1428 | +} | |
1429 | + | |
1380 | 1430 | static int start_auth_vencrypt_subauth(VncState *vs) |
1381 | 1431 | { |
1382 | 1432 | switch (vs->subauth) { |
1383 | 1433 | case VNC_AUTH_VENCRYPT_TLSNONE: |
1434 | + case VNC_AUTH_VENCRYPT_X509NONE: | |
1384 | 1435 | VNC_DEBUG("Accept TLS auth none\n"); |
1385 | 1436 | vnc_write_u32(vs, 0); /* Accept auth completion */ |
1386 | 1437 | vnc_read_when(vs, protocol_client_init, 1); |
1387 | 1438 | break; |
1388 | 1439 | |
1389 | 1440 | case VNC_AUTH_VENCRYPT_TLSVNC: |
1441 | + case VNC_AUTH_VENCRYPT_X509VNC: | |
1390 | 1442 | VNC_DEBUG("Start TLS auth VNC\n"); |
1391 | 1443 | return start_auth_vnc(vs); |
1392 | 1444 | |
... | ... | @@ -1437,11 +1489,17 @@ static void vnc_handshake_io(void *opaque) { |
1437 | 1489 | vnc_continue_handshake(vs); |
1438 | 1490 | } |
1439 | 1491 | |
1492 | +#define NEED_X509_AUTH(vs) \ | |
1493 | + ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ | |
1494 | + (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ | |
1495 | + (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN) | |
1496 | + | |
1497 | + | |
1440 | 1498 | static int vnc_start_tls(struct VncState *vs) { |
1441 | 1499 | static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; |
1442 | 1500 | static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 }; |
1443 | 1501 | static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0}; |
1444 | - gnutls_anon_server_credentials anon_cred = NULL; | |
1502 | + static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0}; | |
1445 | 1503 | |
1446 | 1504 | VNC_DEBUG("Do TLS setup\n"); |
1447 | 1505 | if (vnc_tls_initialize() < 0) { |
... | ... | @@ -1462,7 +1520,7 @@ static int vnc_start_tls(struct VncState *vs) { |
1462 | 1520 | return -1; |
1463 | 1521 | } |
1464 | 1522 | |
1465 | - if (gnutls_kx_set_priority(vs->tls_session, kx_anon) < 0) { | |
1523 | + if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) { | |
1466 | 1524 | gnutls_deinit(vs->tls_session); |
1467 | 1525 | vs->tls_session = NULL; |
1468 | 1526 | vnc_client_error(vs); |
... | ... | @@ -1483,19 +1541,36 @@ static int vnc_start_tls(struct VncState *vs) { |
1483 | 1541 | return -1; |
1484 | 1542 | } |
1485 | 1543 | |
1486 | - anon_cred = vnc_tls_initialize_anon_cred(); | |
1487 | - if (!anon_cred) { | |
1488 | - gnutls_deinit(vs->tls_session); | |
1489 | - vs->tls_session = NULL; | |
1490 | - vnc_client_error(vs); | |
1491 | - return -1; | |
1492 | - } | |
1493 | - if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) { | |
1494 | - gnutls_deinit(vs->tls_session); | |
1495 | - vs->tls_session = NULL; | |
1496 | - gnutls_anon_free_server_credentials(anon_cred); | |
1497 | - vnc_client_error(vs); | |
1498 | - return -1; | |
1544 | + if (NEED_X509_AUTH(vs)) { | |
1545 | + gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(); | |
1546 | + if (!x509_cred) { | |
1547 | + gnutls_deinit(vs->tls_session); | |
1548 | + vs->tls_session = NULL; | |
1549 | + vnc_client_error(vs); | |
1550 | + return -1; | |
1551 | + } | |
1552 | + if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) { | |
1553 | + gnutls_deinit(vs->tls_session); | |
1554 | + vs->tls_session = NULL; | |
1555 | + gnutls_certificate_free_credentials(x509_cred); | |
1556 | + vnc_client_error(vs); | |
1557 | + return -1; | |
1558 | + } | |
1559 | + } else { | |
1560 | + gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred(); | |
1561 | + if (!anon_cred) { | |
1562 | + gnutls_deinit(vs->tls_session); | |
1563 | + vs->tls_session = NULL; | |
1564 | + vnc_client_error(vs); | |
1565 | + return -1; | |
1566 | + } | |
1567 | + if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) { | |
1568 | + gnutls_deinit(vs->tls_session); | |
1569 | + vs->tls_session = NULL; | |
1570 | + gnutls_anon_free_server_credentials(anon_cred); | |
1571 | + vnc_client_error(vs); | |
1572 | + return -1; | |
1573 | + } | |
1499 | 1574 | } |
1500 | 1575 | |
1501 | 1576 | gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs); |
... | ... | @@ -1797,7 +1872,7 @@ int vnc_display_open(DisplayState *ds, const char *display) |
1797 | 1872 | const char *options; |
1798 | 1873 | int password = 0; |
1799 | 1874 | #if CONFIG_VNC_TLS |
1800 | - int tls = 0; | |
1875 | + int tls = 0, x509 = 0; | |
1801 | 1876 | #endif |
1802 | 1877 | |
1803 | 1878 | vnc_display_close(ds); |
... | ... | @@ -1815,15 +1890,22 @@ int vnc_display_open(DisplayState *ds, const char *display) |
1815 | 1890 | #if CONFIG_VNC_TLS |
1816 | 1891 | else if (strncmp(options, "tls", 3) == 0) |
1817 | 1892 | tls = 1; /* Require TLS */ |
1893 | + else if (strncmp(options, "x509", 4) == 0) | |
1894 | + x509 = 1; /* Require x509 certificates */ | |
1818 | 1895 | #endif |
1819 | 1896 | } |
1820 | 1897 | |
1821 | 1898 | if (password) { |
1822 | 1899 | #if CONFIG_VNC_TLS |
1823 | 1900 | if (tls) { |
1824 | - VNC_DEBUG("Initializing VNC server with TLS password auth\n"); | |
1825 | 1901 | vs->auth = VNC_AUTH_VENCRYPT; |
1826 | - vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; | |
1902 | + if (x509) { | |
1903 | + VNC_DEBUG("Initializing VNC server with x509 password auth\n"); | |
1904 | + vs->subauth = VNC_AUTH_VENCRYPT_X509VNC; | |
1905 | + } else { | |
1906 | + VNC_DEBUG("Initializing VNC server with TLS password auth\n"); | |
1907 | + vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; | |
1908 | + } | |
1827 | 1909 | } else { |
1828 | 1910 | #endif |
1829 | 1911 | VNC_DEBUG("Initializing VNC server with password auth\n"); |
... | ... | @@ -1835,9 +1917,14 @@ int vnc_display_open(DisplayState *ds, const char *display) |
1835 | 1917 | } else { |
1836 | 1918 | #if CONFIG_VNC_TLS |
1837 | 1919 | if (tls) { |
1838 | - VNC_DEBUG("Initializing VNC server with TLS no auth\n"); | |
1839 | 1920 | vs->auth = VNC_AUTH_VENCRYPT; |
1840 | - vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; | |
1921 | + if (x509) { | |
1922 | + VNC_DEBUG("Initializing VNC server with x509 no auth\n"); | |
1923 | + vs->subauth = VNC_AUTH_VENCRYPT_X509NONE; | |
1924 | + } else { | |
1925 | + VNC_DEBUG("Initializing VNC server with TLS no auth\n"); | |
1926 | + vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; | |
1927 | + } | |
1841 | 1928 | } else { |
1842 | 1929 | #endif |
1843 | 1930 | VNC_DEBUG("Initializing VNC server with no auth\n"); | ... | ... |