Commit 3a702699b26ba5116c153457d552c577383a9fa1

Authored by ths
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
... ... @@ -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");
... ...