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,6 +105,14 @@ enum { | ||
105 | VNC_AUTH_VENCRYPT_X509VNC = 261, | 105 | VNC_AUTH_VENCRYPT_X509VNC = 261, |
106 | VNC_AUTH_VENCRYPT_X509PLAIN = 262, | 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 | #endif /* CONFIG_VNC_TLS */ | 116 | #endif /* CONFIG_VNC_TLS */ |
109 | 117 | ||
110 | struct VncState | 118 | struct VncState |
@@ -1377,16 +1385,60 @@ static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void) | @@ -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 | static int start_auth_vencrypt_subauth(VncState *vs) | 1430 | static int start_auth_vencrypt_subauth(VncState *vs) |
1381 | { | 1431 | { |
1382 | switch (vs->subauth) { | 1432 | switch (vs->subauth) { |
1383 | case VNC_AUTH_VENCRYPT_TLSNONE: | 1433 | case VNC_AUTH_VENCRYPT_TLSNONE: |
1434 | + case VNC_AUTH_VENCRYPT_X509NONE: | ||
1384 | VNC_DEBUG("Accept TLS auth none\n"); | 1435 | VNC_DEBUG("Accept TLS auth none\n"); |
1385 | vnc_write_u32(vs, 0); /* Accept auth completion */ | 1436 | vnc_write_u32(vs, 0); /* Accept auth completion */ |
1386 | vnc_read_when(vs, protocol_client_init, 1); | 1437 | vnc_read_when(vs, protocol_client_init, 1); |
1387 | break; | 1438 | break; |
1388 | 1439 | ||
1389 | case VNC_AUTH_VENCRYPT_TLSVNC: | 1440 | case VNC_AUTH_VENCRYPT_TLSVNC: |
1441 | + case VNC_AUTH_VENCRYPT_X509VNC: | ||
1390 | VNC_DEBUG("Start TLS auth VNC\n"); | 1442 | VNC_DEBUG("Start TLS auth VNC\n"); |
1391 | return start_auth_vnc(vs); | 1443 | return start_auth_vnc(vs); |
1392 | 1444 | ||
@@ -1437,11 +1489,17 @@ static void vnc_handshake_io(void *opaque) { | @@ -1437,11 +1489,17 @@ static void vnc_handshake_io(void *opaque) { | ||
1437 | vnc_continue_handshake(vs); | 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 | static int vnc_start_tls(struct VncState *vs) { | 1498 | static int vnc_start_tls(struct VncState *vs) { |
1441 | static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; | 1499 | static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; |
1442 | static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 }; | 1500 | static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 }; |
1443 | static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0}; | 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 | VNC_DEBUG("Do TLS setup\n"); | 1504 | VNC_DEBUG("Do TLS setup\n"); |
1447 | if (vnc_tls_initialize() < 0) { | 1505 | if (vnc_tls_initialize() < 0) { |
@@ -1462,7 +1520,7 @@ static int vnc_start_tls(struct VncState *vs) { | @@ -1462,7 +1520,7 @@ static int vnc_start_tls(struct VncState *vs) { | ||
1462 | return -1; | 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 | gnutls_deinit(vs->tls_session); | 1524 | gnutls_deinit(vs->tls_session); |
1467 | vs->tls_session = NULL; | 1525 | vs->tls_session = NULL; |
1468 | vnc_client_error(vs); | 1526 | vnc_client_error(vs); |
@@ -1483,19 +1541,36 @@ static int vnc_start_tls(struct VncState *vs) { | @@ -1483,19 +1541,36 @@ static int vnc_start_tls(struct VncState *vs) { | ||
1483 | return -1; | 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 | gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs); | 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,7 +1872,7 @@ int vnc_display_open(DisplayState *ds, const char *display) | ||
1797 | const char *options; | 1872 | const char *options; |
1798 | int password = 0; | 1873 | int password = 0; |
1799 | #if CONFIG_VNC_TLS | 1874 | #if CONFIG_VNC_TLS |
1800 | - int tls = 0; | 1875 | + int tls = 0, x509 = 0; |
1801 | #endif | 1876 | #endif |
1802 | 1877 | ||
1803 | vnc_display_close(ds); | 1878 | vnc_display_close(ds); |
@@ -1815,15 +1890,22 @@ int vnc_display_open(DisplayState *ds, const char *display) | @@ -1815,15 +1890,22 @@ int vnc_display_open(DisplayState *ds, const char *display) | ||
1815 | #if CONFIG_VNC_TLS | 1890 | #if CONFIG_VNC_TLS |
1816 | else if (strncmp(options, "tls", 3) == 0) | 1891 | else if (strncmp(options, "tls", 3) == 0) |
1817 | tls = 1; /* Require TLS */ | 1892 | tls = 1; /* Require TLS */ |
1893 | + else if (strncmp(options, "x509", 4) == 0) | ||
1894 | + x509 = 1; /* Require x509 certificates */ | ||
1818 | #endif | 1895 | #endif |
1819 | } | 1896 | } |
1820 | 1897 | ||
1821 | if (password) { | 1898 | if (password) { |
1822 | #if CONFIG_VNC_TLS | 1899 | #if CONFIG_VNC_TLS |
1823 | if (tls) { | 1900 | if (tls) { |
1824 | - VNC_DEBUG("Initializing VNC server with TLS password auth\n"); | ||
1825 | vs->auth = VNC_AUTH_VENCRYPT; | 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 | } else { | 1909 | } else { |
1828 | #endif | 1910 | #endif |
1829 | VNC_DEBUG("Initializing VNC server with password auth\n"); | 1911 | VNC_DEBUG("Initializing VNC server with password auth\n"); |
@@ -1835,9 +1917,14 @@ int vnc_display_open(DisplayState *ds, const char *display) | @@ -1835,9 +1917,14 @@ int vnc_display_open(DisplayState *ds, const char *display) | ||
1835 | } else { | 1917 | } else { |
1836 | #if CONFIG_VNC_TLS | 1918 | #if CONFIG_VNC_TLS |
1837 | if (tls) { | 1919 | if (tls) { |
1838 | - VNC_DEBUG("Initializing VNC server with TLS no auth\n"); | ||
1839 | vs->auth = VNC_AUTH_VENCRYPT; | 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 | } else { | 1928 | } else { |
1842 | #endif | 1929 | #endif |
1843 | VNC_DEBUG("Initializing VNC server with no auth\n"); | 1930 | VNC_DEBUG("Initializing VNC server with no auth\n"); |