qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] PATCH 5/8: x509 certificate for server


From: Daniel P. Berrange
Subject: Re: [Qemu-devel] PATCH 5/8: x509 certificate for server
Date: Mon, 13 Aug 2007 20:47:50 +0100
User-agent: Mutt/1.4.1i

This patch adds support for using x509 certificates on the server
end. The server needs a CA certificate, and its own certificate and
private key. A CA revocation list is optional. This this patch the
file names are hardcoded. The next-but-one patch will make them
configurable.

The use of x509 certificates is controlled by the 'x509' flag to
the VNC arg, eg '-vnc :1,tls,x509'. This only provides encryption
of the session, no authentication. The subsequent patch will allow
certificates to be used for authentication too.

Example using TLS, x509 server certificates and password auth

  qemu [...OPTIONS...] -vnc :1,password,tls,x509 -monitor stdio
  (qemu) change vnc password
  Password: ********
  (qemu)


   Signed-off-by: Daniel P. Berrange <address@hidden>


diff -r 4199204d1b36 vnc.c
--- a/vnc.c     Wed Aug 08 12:53:40 2007 -0400
+++ b/vnc.c     Wed Aug 08 12:53:43 2007 -0400
@@ -105,6 +105,14 @@ enum {
     VNC_AUTH_VENCRYPT_X509VNC = 261,
     VNC_AUTH_VENCRYPT_X509PLAIN = 262,
 };
+
+#if CONFIG_VNC_TLS
+#define X509_CA_CERT_FILE "ca-cert.pem"
+#define X509_CA_CRL_FILE "ca-crl.pem"
+#define X509_SERVER_KEY_FILE "server-key.pem"
+#define X509_SERVER_CERT_FILE "server-cert.pem"
+#endif
+
 #endif /* CONFIG_VNC_TLS */
 
 struct VncState
@@ -1377,16 +1385,60 @@ static gnutls_anon_server_credentials vn
 }
 
 
+static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(void)
+{
+    gnutls_certificate_credentials_t x509_cred;
+    int ret;
+    struct stat st;
+
+    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
+       VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
+       return NULL;
+    }
+    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, 
X509_CA_CERT_FILE, GNUTLS_X509_FMT_PEM)) < 0) {
+       VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
+       gnutls_certificate_free_credentials(x509_cred);
+       return NULL;
+    }
+
+    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, 
X509_SERVER_CERT_FILE,
+                                                    X509_SERVER_KEY_FILE,
+                                                    GNUTLS_X509_FMT_PEM)) < 0) 
{
+       VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
+       gnutls_certificate_free_credentials(x509_cred);
+       return NULL;
+    }
+
+    if (stat(X509_CA_CRL_FILE, &st) < 0) {
+       if (errno != ENOENT) {
+           gnutls_certificate_free_credentials(x509_cred);
+           return NULL;
+       }
+    } else {
+       if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, 
X509_CA_CRL_FILE, GNUTLS_X509_FMT_PEM)) < 0) {
+           VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
+           gnutls_certificate_free_credentials(x509_cred);
+           return NULL;
+       }
+    }
+
+    gnutls_certificate_set_dh_params (x509_cred, dh_params);
+
+    return x509_cred;
+}
+
 static int start_auth_vencrypt_subauth(VncState *vs)
 {
     switch (vs->subauth) {
     case VNC_AUTH_VENCRYPT_TLSNONE:
+    case VNC_AUTH_VENCRYPT_X509NONE:
        VNC_DEBUG("Accept TLS auth none\n");
        vnc_write_u32(vs, 0); /* Accept auth completion */
        vnc_read_when(vs, protocol_client_init, 1);
        break;
 
     case VNC_AUTH_VENCRYPT_TLSVNC:
+    case VNC_AUTH_VENCRYPT_X509VNC:
        VNC_DEBUG("Start TLS auth VNC\n");
        return start_auth_vnc(vs);
 
@@ -1437,11 +1489,17 @@ static void vnc_handshake_io(void *opaqu
     vnc_continue_handshake(vs);
 }
 
+#define NEED_X509_AUTH(vs)                           \
+    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
+
+
 static int vnc_start_tls(struct VncState *vs) {
     static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
     static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, 
GNUTLS_SSL3, 0 };
     static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
-    gnutls_anon_server_credentials anon_cred = NULL;
+    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, 
GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
 
     VNC_DEBUG("Do TLS setup\n");
     if (vnc_tls_initialize() < 0) {
@@ -1462,7 +1520,7 @@ static int vnc_start_tls(struct VncState
            return -1;
        }
 
-       if (gnutls_kx_set_priority(vs->tls_session, kx_anon) < 0) {
+       if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? 
kx_x509 : kx_anon) < 0) {
            gnutls_deinit(vs->tls_session);
            vs->tls_session = NULL;
            vnc_client_error(vs);
@@ -1483,19 +1541,36 @@ static int vnc_start_tls(struct VncState
            return -1;
        }
 
-       anon_cred = vnc_tls_initialize_anon_cred();
-       if (!anon_cred) {
-           gnutls_deinit(vs->tls_session);
-           vs->tls_session = NULL;
-           vnc_client_error(vs);
-           return -1;
-       }
-       if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) 
< 0) {
-           gnutls_deinit(vs->tls_session);
-           vs->tls_session = NULL;
-           gnutls_anon_free_server_credentials(anon_cred);
-           vnc_client_error(vs);
-           return -1;
+       if (NEED_X509_AUTH(vs)) {
+           gnutls_certificate_server_credentials x509_cred = 
vnc_tls_initialize_x509_cred();
+           if (!x509_cred) {
+               gnutls_deinit(vs->tls_session);
+               vs->tls_session = NULL;
+               vnc_client_error(vs);
+               return -1;
+           }
+           if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, 
x509_cred) < 0) {
+               gnutls_deinit(vs->tls_session);
+               vs->tls_session = NULL;
+               gnutls_certificate_free_credentials(x509_cred);
+               vnc_client_error(vs);
+               return -1;
+           }
+       } else {
+           gnutls_anon_server_credentials anon_cred = 
vnc_tls_initialize_anon_cred();
+           if (!anon_cred) {
+               gnutls_deinit(vs->tls_session);
+               vs->tls_session = NULL;
+               vnc_client_error(vs);
+               return -1;
+           }
+           if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, 
anon_cred) < 0) {
+               gnutls_deinit(vs->tls_session);
+               vs->tls_session = NULL;
+               gnutls_anon_free_server_credentials(anon_cred);
+               vnc_client_error(vs);
+               return -1;
+           }
        }
 
        gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs);
@@ -1796,7 +1871,7 @@ int vnc_display_open(DisplayState *ds, c
     const char *options;
     int password = 0;
 #if CONFIG_VNC_TLS
-    int tls = 0;
+    int tls = 0, x509 = 0;
 #endif
 
     vnc_display_close(ds);
@@ -1814,15 +1889,22 @@ int vnc_display_open(DisplayState *ds, c
 #if CONFIG_VNC_TLS
        else if (strncmp(options, "tls", 3) == 0)
            tls = 1; /* Require TLS */
+       else if (strncmp(options, "x509", 4) == 0)
+           x509 = 1; /* Require x509 certificates */
 #endif
     }
 
     if (password) {
 #if CONFIG_VNC_TLS
        if (tls) {
-           VNC_DEBUG("Initializing VNC server with TLS password auth\n");
            vs->auth = VNC_AUTH_VENCRYPT;
-           vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+           if (x509) {
+               VNC_DEBUG("Initializing VNC server with x509 password auth\n");
+               vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
+           } else {
+               VNC_DEBUG("Initializing VNC server with TLS password auth\n");
+               vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+           }
        } else {
 #endif
            VNC_DEBUG("Initializing VNC server with password auth\n");
@@ -1834,9 +1916,14 @@ int vnc_display_open(DisplayState *ds, c
     } else {
 #if CONFIG_VNC_TLS
        if (tls) {
-           VNC_DEBUG("Initializing VNC server with TLS no auth\n");
            vs->auth = VNC_AUTH_VENCRYPT;
-           vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
+           if (x509) {
+               VNC_DEBUG("Initializing VNC server with x509 no auth\n");
+               vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
+           } else {
+               VNC_DEBUG("Initializing VNC server with TLS no auth\n");
+               vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
+           }
        } else {
 #endif
            VNC_DEBUG("Initializing VNC server with no auth\n");

-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]