Message ID | 1429280557-8887-35-git-send-email-berrange@redhat.com |
---|---|
State | New |
Headers | show |
On 04/17/2015 08:22 AM, Daniel P. Berrange wrote: > This integrates support for QIOChannelTLS object in the TCP > chardev backend. If the 'tls-cred=NAME' option is passed with > the '-chardev tcp' argument, then it will setup the chardev > such that the client is required to establish a TLS handshake > when connecting. The 'acl' option will further enable the > creation of a 'char.$ID.tlspeername' ACL which will be used > to validate the client x509 certificate, if provided. > > A complete invokation to run QEMU as the server for a TLS s/invokation/invocation/ > encrypted serial dev might be > > $ qemu-system-x86_64 \ > -nodefconfig -nodefaults -device sga -display none \ > -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0,server \ > -device isa-serial,chardev=s0 \ > -object qcrypto-tls-cred,id=tls0,credtype=x509,\ > endpoint=server,dir=/home/berrange/security/qemutls,verify-peer=off > > To test with the gnutls-cli tool as the client: > > $ gnutls-cli --priority=NORMAL -p 9000 \ > --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ > 127.0.0.1 > > If QEMU was told to use 'anon' credential type, then use the > priority string 'NOMAL:+ANON-DH' with gnutls-cli s/NOMAL/NORMAL/ > > Alternatively, if setting up a chardev to operate as a client, > then the TLS credentials registered must be for the client > endpoint. First a TLS server must be setup, which can be done > with the gnutls-serv tool > > $ gnutls-serv --priority=NORMAL -p 9000 \ > --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ > --x509certfile=/home/berrange/security/qemutls/server-cert.pem \ > --x509keyfile=/home/berrange/security/qemutls/server-key.pem > > Then QEMU can connect with > > $ qemu-system-x86_64 \ > -nodefconfig -nodefaults -device sga -display none \ > -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0 \ > -device isa-serial,chardev=s0 \ > -object qcrypto-tls-cred,id=tls0,credtype=x509,\ > endpoint=client,dir=/home/berrange/security/qemutls > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > --- > qapi-schema.json | 2 + > qemu-char.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++--------- > qemu-options.hx | 9 ++- > 3 files changed, 161 insertions(+), 32 deletions(-) > > diff --git a/qapi-schema.json b/qapi-schema.json > index ac9594d..062a455 100644 > --- a/qapi-schema.json > +++ b/qapi-schema.json > @@ -2782,6 +2782,8 @@ > # Since: 1.4 > ## > { 'type': 'ChardevSocket', 'data': { 'addr' : 'SocketAddress', > + '*tls-cred' : 'str', > + '*acl' : 'str', Need to document these two fields, along with '(since 2.4)' designators. > +++ b/qemu-options.hx > @@ -2009,7 +2009,7 @@ ETEXI > DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, > "-chardev null,id=id[,mux=on|off]\n" > "-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4][,ipv6][,nodelay][,reconnect=seconds]\n" > - " [,server][,nowait][,telnet][,reconnect=seconds][,mux=on|off] (tcp)\n" > + " [,server][,nowait][,telnet][,reconnect=seconds][,mux=on|off][,tls-cred=ID][,acl] (tcp)\n" > "-chardev socket,id=id,path=path[,server][,nowait][,telnet][,reconnect=seconds][,mux=on|off] (unix)\n" > "-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n" > " [,localport=localport][,ipv4][,ipv6][,mux=on|off]\n" > @@ -2082,7 +2082,7 @@ Options to each backend are described below. > A void device. This device will not emit any data, and will drop any data it > receives. The null backend does not take any options. > > -@item -chardev socket ,id=@var{id} [@var{TCP options} or @var{unix options}] [,server] [,nowait] [,telnet] [,reconnect=@var{seconds}] > +@item -chardev socket ,id=@var{id} [@var{TCP options} or @var{unix options}] [,server] [,nowait] [,telnet] [,reconnect=@var{seconds}][,tls-cred=@var{id}] Everyone else in this line had space before [
On Fri, Apr 17, 2015 at 12:27:06PM -0600, Eric Blake wrote: > On 04/17/2015 08:22 AM, Daniel P. Berrange wrote: > > This integrates support for QIOChannelTLS object in the TCP > > chardev backend. If the 'tls-cred=NAME' option is passed with > > the '-chardev tcp' argument, then it will setup the chardev > > such that the client is required to establish a TLS handshake > > when connecting. The 'acl' option will further enable the > > creation of a 'char.$ID.tlspeername' ACL which will be used > > to validate the client x509 certificate, if provided. > > > > A complete invokation to run QEMU as the server for a TLS > > s/invokation/invocation/ > > > encrypted serial dev might be > > > > $ qemu-system-x86_64 \ > > -nodefconfig -nodefaults -device sga -display none \ > > -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0,server \ > > -device isa-serial,chardev=s0 \ > > -object qcrypto-tls-cred,id=tls0,credtype=x509,\ > > endpoint=server,dir=/home/berrange/security/qemutls,verify-peer=off > > > > To test with the gnutls-cli tool as the client: > > > > $ gnutls-cli --priority=NORMAL -p 9000 \ > > --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ > > 127.0.0.1 > > > > If QEMU was told to use 'anon' credential type, then use the > > priority string 'NOMAL:+ANON-DH' with gnutls-cli > > s/NOMAL/NORMAL/ > > > > > Alternatively, if setting up a chardev to operate as a client, > > then the TLS credentials registered must be for the client > > endpoint. First a TLS server must be setup, which can be done > > with the gnutls-serv tool > > > > $ gnutls-serv --priority=NORMAL -p 9000 \ > > --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ > > --x509certfile=/home/berrange/security/qemutls/server-cert.pem \ > > --x509keyfile=/home/berrange/security/qemutls/server-key.pem > > > > Then QEMU can connect with > > > > $ qemu-system-x86_64 \ > > -nodefconfig -nodefaults -device sga -display none \ > > -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0 \ > > -device isa-serial,chardev=s0 \ > > -object qcrypto-tls-cred,id=tls0,credtype=x509,\ > > endpoint=client,dir=/home/berrange/security/qemutls > > > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > > --- > > qapi-schema.json | 2 + > > qemu-char.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++--------- > > qemu-options.hx | 9 ++- > > 3 files changed, 161 insertions(+), 32 deletions(-) > > > > diff --git a/qapi-schema.json b/qapi-schema.json > > index ac9594d..062a455 100644 > > --- a/qapi-schema.json > > +++ b/qapi-schema.json > > @@ -2782,6 +2782,8 @@ > > # Since: 1.4 > > ## > > { 'type': 'ChardevSocket', 'data': { 'addr' : 'SocketAddress', > > + '*tls-cred' : 'str', > > + '*acl' : 'str', > > Need to document these two fields, along with '(since 2.4)' designators. Ah, ok forgot about that. Regards, Daniel
On Fri, Apr 17, 2015 at 03:22:37PM +0100, Daniel P. Berrange wrote: > This integrates support for QIOChannelTLS object in the TCP > chardev backend. If the 'tls-cred=NAME' option is passed with > the '-chardev tcp' argument, then it will setup the chardev > such that the client is required to establish a TLS handshake > when connecting. The 'acl' option will further enable the > creation of a 'char.$ID.tlspeername' ACL which will be used > to validate the client x509 certificate, if provided. > > A complete invokation to run QEMU as the server for a TLS > encrypted serial dev might be > > $ qemu-system-x86_64 \ > -nodefconfig -nodefaults -device sga -display none \ > -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0,server \ > -device isa-serial,chardev=s0 \ > -object qcrypto-tls-cred,id=tls0,credtype=x509,\ > endpoint=server,dir=/home/berrange/security/qemutls,verify-peer=off > > To test with the gnutls-cli tool as the client: > > $ gnutls-cli --priority=NORMAL -p 9000 \ > --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ > 127.0.0.1 > > If QEMU was told to use 'anon' credential type, then use the > priority string 'NOMAL:+ANON-DH' with gnutls-cli > > Alternatively, if setting up a chardev to operate as a client, > then the TLS credentials registered must be for the client > endpoint. First a TLS server must be setup, which can be done > with the gnutls-serv tool > > $ gnutls-serv --priority=NORMAL -p 9000 \ > --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ > --x509certfile=/home/berrange/security/qemutls/server-cert.pem \ > --x509keyfile=/home/berrange/security/qemutls/server-key.pem > > Then QEMU can connect with > > $ qemu-system-x86_64 \ > -nodefconfig -nodefaults -device sga -display none \ > -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0 \ > -device isa-serial,chardev=s0 \ > -object qcrypto-tls-cred,id=tls0,credtype=x509,\ > endpoint=client,dir=/home/berrange/security/qemutls I've applied your 'qemu-io-channel-7' branch locally, compiled QEMU and began to play around. $ git describe v2.3.0-rc3-42-g5878696 When running QEMU either as server or as client, I notice this error (further below are the details of how I tested): [. . .] qemu-system-x86_64: -object qcrypto-tls-cred,id=tls0,credtype=x509,: invalid object type: qcrypto-tls-cred Test with QEMU as client ------------------------ Setup PKI environment[1] , and run a GnuTLS server: $ gnutls-serv --priority=NORMAL -p 9000 \ --x509cafile=/export/security/gnutls/ca-cert.pem \ --x509certfile=/export/security/gnutls/server-cert.pem \ --x509keyfile=/export/security/gnutls/server-key.pem Set static Diffie-Hellman parameters, consider --dhparams. Processed 1 CA certificate(s). HTTP Server listening on IPv4 0.0.0.0 port 9000...done HTTP Server listening on IPv6 :: port 9000...done And, connect with QEMU: $ /home/kashyapc/build/tls-qemu/x86_64-softmmu/qemu-system-x86_64 \ -nodefconfig -nodefaults -device sga -display none \ -chardev socket,id=s0,host=localhost,port=9000,tls-cred=tls0 \ -device isa-serial,chardev=s0 \ -object qcrypto-tls-cred,id=tls0,credtype=x509,\ endpoint=client,dir=/export/security/gnutls qemu-system-x86_64: -object qcrypto-tls-cred,id=tls0,credtype=x509,: invalid object type: qcrypto-tls-cred Test with QEMU as server ------------------------ $ /home/kashyapc/build/tls-qemu/x86_64-softmmu/qemu-system-x86_64 \ -nodefconfig -nodefaults -device sga -display none \ -chardev socket,id=s0,host=localhost,port=9000,tls-cred=tls0,server \ -device isa-serial,chardev=s0 \ -object qcrypto-tls-cred,id=tls0,credtype=x509,\ endpoint=server,dir=/export/security/gnutls,verify-peer=off qemu-system-x86_64: -object qcrypto-tls-cred,id=tls0,credtype=x509,: invalid object type: qcrypto-tls-cred Am I missing something simple? Additional notes ---------------- (a) I verified the QEMU CLI for -object is correct by looking at local the 'qemu-options.hx' file: @item -object qcrypto-tls-cred,id=@var{id},credtype=@var{type},endpoint=@var{endpoint}, dir=@var{/path/to/cred/dir},verify-peer=@var{on|off} (b) Just to ensure that TLS server is setup correctly, I validated it via `gnutls-cli`: $ gnutls-cli --priority=NORMAL -p 9000 \ --x509cafile=/export/security/gnutls/ca-cert.pem localhost [. . .] - Status: The certificate is trusted. - Successfully sent 0 certificate(s) to server. - Compression: NULL - Options: safe renegotiation, - Handshake was completed [. . .] (c) Exact CLI invocatoins of how I created the self-signed CA, server certificate including their outputs are noted here[1]. (d) When creating the server certificate request, I used the 'dnsName' attribute, and gave its value as "localhost". [1] https://kashyapc.fedorapeople.org/gnutls-pki-setup.txt
On Mon, May 04, 2015 at 10:07:15PM +0200, Kashyap Chamarthy wrote: > On Fri, Apr 17, 2015 at 03:22:37PM +0100, Daniel P. Berrange wrote: > > This integrates support for QIOChannelTLS object in the TCP > > chardev backend. If the 'tls-cred=NAME' option is passed with > > the '-chardev tcp' argument, then it will setup the chardev > > such that the client is required to establish a TLS handshake > > when connecting. The 'acl' option will further enable the > > creation of a 'char.$ID.tlspeername' ACL which will be used > > to validate the client x509 certificate, if provided. > > > > A complete invokation to run QEMU as the server for a TLS > > encrypted serial dev might be > > > > $ qemu-system-x86_64 \ > > -nodefconfig -nodefaults -device sga -display none \ > > -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0,server \ > > -device isa-serial,chardev=s0 \ > > -object qcrypto-tls-cred,id=tls0,credtype=x509,\ > > endpoint=server,dir=/home/berrange/security/qemutls,verify-peer=off > > > > To test with the gnutls-cli tool as the client: > > > > $ gnutls-cli --priority=NORMAL -p 9000 \ > > --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ > > 127.0.0.1 > > > > If QEMU was told to use 'anon' credential type, then use the > > priority string 'NOMAL:+ANON-DH' with gnutls-cli > > > > Alternatively, if setting up a chardev to operate as a client, > > then the TLS credentials registered must be for the client > > endpoint. First a TLS server must be setup, which can be done > > with the gnutls-serv tool > > > > $ gnutls-serv --priority=NORMAL -p 9000 \ > > --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ > > --x509certfile=/home/berrange/security/qemutls/server-cert.pem \ > > --x509keyfile=/home/berrange/security/qemutls/server-key.pem > > > > Then QEMU can connect with > > > > $ qemu-system-x86_64 \ > > -nodefconfig -nodefaults -device sga -display none \ > > -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0 \ > > -device isa-serial,chardev=s0 \ > > -object qcrypto-tls-cred,id=tls0,credtype=x509,\ > > endpoint=client,dir=/home/berrange/security/qemutls > > I've applied your 'qemu-io-channel-7' branch locally, compiled QEMU and > began to play around. > > $ git describe > v2.3.0-rc3-42-g5878696 > > When running QEMU either as server or as client, I notice this error > (further below are the details of how I tested): > > [. . .] > qemu-system-x86_64: -object qcrypto-tls-cred,id=tls0,credtype=x509,: > invalid object type: qcrypto-tls-cred Typo in my commit message - it should end in '-creds' not '-cred' for the object type. Regards, Daniel
On 05/05/2015 15:49, Daniel P. Berrange wrote: >> > qemu-system-x86_64: -object qcrypto-tls-cred,id=tls0,credtype=x509,: >> > invalid object type: qcrypto-tls-cred > Typo in my commit message - it should end in '-creds' not '-cred' for > the object type. FWIW, I think just "tls-creds" is probably a better name for the -object option. "qcrypto" is more of an internal detail. Paolo
On Tue, May 05, 2015 at 03:53:41PM +0200, Paolo Bonzini wrote: > > > On 05/05/2015 15:49, Daniel P. Berrange wrote: > >> > qemu-system-x86_64: -object qcrypto-tls-cred,id=tls0,credtype=x509,: > >> > invalid object type: qcrypto-tls-cred > > Typo in my commit message - it should end in '-creds' not '-cred' for > > the object type. > > FWIW, I think just "tls-creds" is probably a better name for the -object > option. "qcrypto" is more of an internal detail. Ok, I'll drop the prefix from the name - I guess chance of a namespace clash is pretty low anyway. Regards, Daniel
On Tue, May 05, 2015 at 02:49:51PM +0100, Daniel P. Berrange wrote: > On Mon, May 04, 2015 at 10:07:15PM +0200, Kashyap Chamarthy wrote: > > On Fri, Apr 17, 2015 at 03:22:37PM +0100, Daniel P. Berrange wrote: > > > This integrates support for QIOChannelTLS object in the TCP > > > chardev backend. If the 'tls-cred=NAME' option is passed with > > > the '-chardev tcp' argument, then it will setup the chardev > > > such that the client is required to establish a TLS handshake > > > when connecting. The 'acl' option will further enable the > > > creation of a 'char.$ID.tlspeername' ACL which will be used > > > to validate the client x509 certificate, if provided. > > > > > > A complete invokation to run QEMU as the server for a TLS > > > encrypted serial dev might be > > > > > > $ qemu-system-x86_64 \ > > > -nodefconfig -nodefaults -device sga -display none \ > > > -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0,server \ > > > -device isa-serial,chardev=s0 \ > > > -object qcrypto-tls-cred,id=tls0,credtype=x509,\ > > > endpoint=server,dir=/home/berrange/security/qemutls,verify-peer=off > > > > > > To test with the gnutls-cli tool as the client: > > > > > > $ gnutls-cli --priority=NORMAL -p 9000 \ > > > --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ > > > 127.0.0.1 > > > > > > If QEMU was told to use 'anon' credential type, then use the > > > priority string 'NOMAL:+ANON-DH' with gnutls-cli > > > > > > Alternatively, if setting up a chardev to operate as a client, > > > then the TLS credentials registered must be for the client > > > endpoint. First a TLS server must be setup, which can be done > > > with the gnutls-serv tool > > > > > > $ gnutls-serv --priority=NORMAL -p 9000 \ > > > --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ > > > --x509certfile=/home/berrange/security/qemutls/server-cert.pem \ > > > --x509keyfile=/home/berrange/security/qemutls/server-key.pem > > > > > > Then QEMU can connect with > > > > > > $ qemu-system-x86_64 \ > > > -nodefconfig -nodefaults -device sga -display none \ > > > -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0 \ > > > -device isa-serial,chardev=s0 \ > > > -object qcrypto-tls-cred,id=tls0,credtype=x509,\ > > > endpoint=client,dir=/home/berrange/security/qemutls > > > > I've applied your 'qemu-io-channel-7' branch locally, compiled QEMU and > > began to play around. > > > > $ git describe > > v2.3.0-rc3-42-g5878696 > > > > When running QEMU either as server or as client, I notice this error > > (further below are the details of how I tested): > > > > [. . .] > > qemu-system-x86_64: -object qcrypto-tls-cred,id=tls0,credtype=x509,: > > invalid object type: qcrypto-tls-cred > > Typo in my commit message - it should end in '-creds' not '-cred' for > the object type. Yep, that fixed it. I should have looked deeper -- your example in include/crypto/tlscreds.h has the correct syntax and also includes a QMP variant. Just to note, there seems to be three instances of this typo in qemu-options.hx (found via `git grep qcrypto-tls-cred`). While running QEMU as TLS server, the TLS handshake completes successfully when connected via `gnutls-cli`. However, when using QEMU as client to connect to an existing GnuTLS server, I notice a segmentation fault: $ /home/kashyapc/build/tls-qemu/x86_64-softmmu/qemu-system-x86_64 \ -nodefconfig -nodefaults -device sga -display none \ -chardev socket,id=s0,host=localhost,port=9000,tls-cred=tls0 \ -device isa-serial,chardev=s0 \ -object qcrypto-tls-creds,id=tls0,credtype=x509,endpoint=client,dir=/export/security/gnutls Segmentation fault (core dumped)
On Tue, May 05, 2015 at 04:54:44PM +0200, Kashyap Chamarthy wrote: [. . .] > While running QEMU as TLS server, the TLS handshake completes > successfully when connected via `gnutls-cli`. > > However, when using QEMU as client to connect to an existing GnuTLS > server, I notice a segmentation fault: > > $ /home/kashyapc/build/tls-qemu/x86_64-softmmu/qemu-system-x86_64 \ > -nodefconfig -nodefaults -device sga -display none \ > -chardev socket,id=s0,host=localhost,port=9000,tls-cred=tls0 \ > -device isa-serial,chardev=s0 \ > -object qcrypto-tls-creds,id=tls0,credtype=x509,endpoint=client,dir=/export/security/gnutls > Segmentation fault (core dumped) Some debugging with `gdb` below. QEMU was built with: ./configure --target-list=x86_64-softmmu --enable-debug make -j4 Stack traces: $ gdb /home/kashyapc/build/tls-qemu/x86_64-softmmu/qemu-system-x86_64 [. . .] (gdb) run -nodefconfig -nodefaults -device sga -display none -chardev socket,id=s0,host=localhost,port=9000,tls-cred=tls0 -device isa-serial,chardev=s0 -object qcrypto-tls-creds,id=tls0,credtype=x509,endpoint=client,dir=/export/security/gnutls Starting program: /home/kashyapc/build/tls-qemu/x86_64-softmmu/qemu-system-x86_64 -nodefconfig -nodefaults -device sga -display none -chardev socket,id=s0,host=localhost,port=9000,tls-cred=tls0 -device isa-serial,chardev=s0 -object qcrypto-tls-creds,id=tls0,credtype=x509,endpoint=client,dir=/export/security/gnutls [. . .] Program received signal SIGSEGV, Segmentation fault. __strstr_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strstr-sse2-unaligned.S:40 40 movdqu (%rdi), %xmm3 (gdb) thread apply all bt full Thread 2 (Thread 0x7fffe4fcc700 (LWP 5393)): #0 0x00007ffff6bce8fd in nanosleep () at ../sysdeps/unix/syscall-template.S:81 #1 0x00007ffff64f1de8 in g_usleep () at /lib64/libglib-2.0.so.0 #2 0x00005555559d32d7 in call_rcu_thread (opaque=0x0) at /home/kashyapc/tinker-space/qemu/util/rcu.c:228 tries = 0 n = 0 node = 0x7ffff7fd19a0 #3 0x00007ffff6bc652a in start_thread (arg=0x7fffe4fcc700) at pthread_create.c:310 __res = <optimized out> pd = 0x7fffe4fcc700 now = <optimized out> unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737035159296, 3180389637749088242, 140737488345857, 4096, 140737035159296, 140737035160000, -3180444589616128014, -3180404459381186574}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} not_first_call = <optimized out> pagesize_m1 = <optimized out> sp = <optimized out> freesize = <optimized out> #4 0x00007fffeea0979d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109 ---Type <return> to continue, or q <return> to quit--- Thread 1 (Thread 0x7ffff7f89bc0 (LWP 5389)): #0 0x00007fffee9ae6dd in __strstr_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strstr-sse2-unaligned.S:40 #1 0x00007ffff1c6b370 in _gnutls_url_is_known () at /lib64/libgnutls.so.28 #2 0x00007ffff1c6b3d9 in gnutls_certificate_set_x509_key_file2 () at /lib64/libgnutls.so.28 #3 0x00005555559aba85 in qcrypto_tls_creds_load_x509 (creds=0x55555639ac60, errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/crypto/tlscreds.c:728 cacert = 0x55555639a8c0 "/export/security/gnutls/ca-cert.pem" cacrl = 0x0 cert = 0x0 key = 0x0 dhparams = 0x0 ret = 1 rv = -1 #4 0x00005555559abdb2 in qcrypto_tls_creds_load (creds=0x55555639ac60, errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/crypto/tlscreds.c:820 #5 0x00005555559abf30 in qcrypto_tls_creds_prop_set_loaded (obj=0x55555639ac60, value=true, errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/crypto/tlscreds.c:888 creds = 0x55555639ac60 __func__ = "qcrypto_tls_creds_prop_set_loaded" #6 0x00005555558cec1c in property_set_bool (obj=0x55555639ac60, v=0x55555639b4d0, opaque=0x55555639ad40, name=0x555555a59695 "loaded", errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/qom/object.c:1600 prop = 0x55555639ad40 value = true local_err = 0x0 ---Type <return> to continue, or q <return> to quit--- #7 0x00005555558cd485 in object_property_set (obj=0x55555639ac60, v=0x55555639b4d0, name=0x555555a59695 "loaded", errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/qom/object.c:901 prop = 0x55555639ad60 #8 0x00005555558cfa47 in object_property_set_qobject (obj=0x55555639ac60, value=0x55555639b200, name=0x555555a59695 "loaded", errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/qom/qom-qobject.c:24 mi = 0x55555639b4d0 #9 0x00005555558cd6f4 in object_property_set_bool (obj=0x55555639ac60, value=true, name=0x555555a59695 "loaded", errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/qom/object.c:969 qbool = 0x55555639b200 #10 0x00005555559ac2e5 in qcrypto_tls_creds_complete (uc=0x55555639ac60, errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/crypto/tlscreds.c:1018 #11 0x00005555558d0899 in user_creatable_complete (obj=0x55555639ac60, errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/qom/object_interfaces.c:17 ucc = 0x5555563702f0 uc = 0x55555639ac60 __func__ = "user_creatable_complete" #12 0x0000555555750201 in object_add (type=0x55555639a8f0 "qcrypto-tls-creds", id=0x55555639a850 "tls0", qdict=0x5555563997b0, v=0x5555563996a0, errp=0x7fffffffd920) at /home/kashyapc/tinker-space/qemu/qmp.c:659 obj = 0x55555639ac60 klass = 0x555556370050 e = 0x0 local_err = 0x0 #13 0x0000555555736a2d in object_create (opts=0x55555638a7e0, opaque=0x55555573684e <object_create_phase1>) at /home/kashyapc/tinker-space/qemu/vl.c:2644 err = 0x0 type = 0x55555639a8f0 "qcrypto-tls-creds" ---Type <return> to continue, or q <return> to quit--- id = 0x55555639a850 "tls0" dummy = 0x55555639aaf0 ov = 0x5555563996a0 pdict = 0x5555563997b0 type_predicate = 0x55555573684e <object_create_phase1> #14 0x00005555559d08e0 in qemu_opts_foreach (list=0x555555e12ee0 <qemu_object_opts>, func=0x5555557368aa <object_create>, opaque=0x55555573684e <object_create_phase1>, abort_on_failure=0) at /home/kashyapc/tinker-space/qemu/util/qemu-option.c:1059 loc = {kind = LOC_CMDLINE, num = 2, ptr = 0x7fffffffde10, prev = 0x555556315300 <std_loc>} opts = 0x55555638a7e0 rc = 0 #15 0x000055555573a273 in main (argc=13, argv=0x7fffffffddb8, envp=0x7fffffffde28) at /home/kashyapc/tinker-space/qemu/vl.c:4039 i = 21845 snapshot = 0 linux_boot = 3 initrd_filename = 0xffff800000002441 <error: Cannot access memory at address 0xffff800000002441> kernel_filename = 0xffffffffffffffff <error: Cannot access memory at address 0xffffffffffffffff> kernel_cmdline = 0x555556345060 "\241x\244UUU" boot_order = 0x0 boot_once = 0x0 ds = 0x7fffffffdbbf cyls = 0 ---Type <return> to continue, or q <return> to quit--- heads = 0 secs = 0 translation = 0 hda_opts = 0x0 opts = 0x55555638aa50 machine_opts = 0xffffffffffffffff icount_opts = 0x0 olist = 0x0 optind = 13 optarg = 0x0 loadvm = 0x0 machine_class = 0x55555637ac70 cpu_model = 0x0 vga_model = 0x0 qtest_chrdev = 0x0 qtest_log = 0x0 pid_file = 0x0 incoming = 0x0 show_vnc_port = 0 defconfig = false userconfig = true ---Type <return> to continue, or q <return> to quit--- log_mask = 0x0 log_file = 0x0 mem_trace = {malloc = 0x5555557366c1 <malloc_and_trace>, realloc = 0x5555557366f6 <realloc_and_trace>, free = 0x55555573673a <free_and_trace>, calloc = 0x0, try_malloc = 0x0, try_realloc = 0x0} trace_events = 0x0 trace_file = 0x0 maxram_size = 134217728 ram_slots = 0 vmstate_dump_file = 0x0 main_loop_err = 0x0 err = 0x0 __func__ = "main"
On Wed, May 06, 2015 at 10:34:06AM +0200, Kashyap Chamarthy wrote: > On Tue, May 05, 2015 at 04:54:44PM +0200, Kashyap Chamarthy wrote: > > [. . .] > > > While running QEMU as TLS server, the TLS handshake completes > > successfully when connected via `gnutls-cli`. > > > > However, when using QEMU as client to connect to an existing GnuTLS > > server, I notice a segmentation fault: > > > > $ /home/kashyapc/build/tls-qemu/x86_64-softmmu/qemu-system-x86_64 \ > > -nodefconfig -nodefaults -device sga -display none \ > > -chardev socket,id=s0,host=localhost,port=9000,tls-cred=tls0 \ > > -device isa-serial,chardev=s0 \ > > -object qcrypto-tls-creds,id=tls0,credtype=x509,endpoint=client,dir=/export/security/gnutls > > Segmentation fault (core dumped) > > Some debugging with `gdb` below. > > QEMU was built with: > > ./configure --target-list=x86_64-softmmu --enable-debug > make -j4 > > Stack traces: > > $ gdb /home/kashyapc/build/tls-qemu/x86_64-softmmu/qemu-system-x86_64 > #2 0x00007ffff1c6b3d9 in gnutls_certificate_set_x509_key_file2 () at /lib64/libgnutls.so.28 > #3 0x00005555559aba85 in qcrypto_tls_creds_load_x509 (creds=0x55555639ac60, errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/crypto/tlscreds.c:728 > cacert = 0x55555639a8c0 "/export/security/gnutls/ca-cert.pem" > cacrl = 0x0 > cert = 0x0 > key = 0x0 > dhparams = 0x0 > ret = 1 > rv = -1 Ah, with QEMU running in client mode, the client cert + key are optional. In this case you've not provided them (cert & key are 0x0 ie NULL). We are then mistakenly calling gnutls_certificate_set_x509_key_file2 - if I simply skip that I'll avoid the crash. Thanks for testing this - I'll add a test case to validate this scenario too Regards, Daniel
On Wed, May 06, 2015 at 11:18:23AM +0100, Daniel P. Berrange wrote: > On Wed, May 06, 2015 at 10:34:06AM +0200, Kashyap Chamarthy wrote: > > On Tue, May 05, 2015 at 04:54:44PM +0200, Kashyap Chamarthy wrote: > > > > [. . .] > > > > > While running QEMU as TLS server, the TLS handshake completes > > > successfully when connected via `gnutls-cli`. > > > > > > However, when using QEMU as client to connect to an existing GnuTLS > > > server, I notice a segmentation fault: > > > > > > $ /home/kashyapc/build/tls-qemu/x86_64-softmmu/qemu-system-x86_64 \ > > > -nodefconfig -nodefaults -device sga -display none \ > > > -chardev socket,id=s0,host=localhost,port=9000,tls-cred=tls0 \ > > > -device isa-serial,chardev=s0 \ > > > -object qcrypto-tls-creds,id=tls0,credtype=x509,endpoint=client,dir=/export/security/gnutls > > > Segmentation fault (core dumped) > > > > Some debugging with `gdb` below. > > > > QEMU was built with: > > > > ./configure --target-list=x86_64-softmmu --enable-debug > > make -j4 > > > > Stack traces: > > > > $ gdb /home/kashyapc/build/tls-qemu/x86_64-softmmu/qemu-system-x86_64 > > > #2 0x00007ffff1c6b3d9 in gnutls_certificate_set_x509_key_file2 () at /lib64/libgnutls.so.28 > > #3 0x00005555559aba85 in qcrypto_tls_creds_load_x509 (creds=0x55555639ac60, errp=0x7fffffffd8d8) at /home/kashyapc/tinker-space/qemu/crypto/tlscreds.c:728 > > cacert = 0x55555639a8c0 "/export/security/gnutls/ca-cert.pem" > > cacrl = 0x0 > > cert = 0x0 > > key = 0x0 > > dhparams = 0x0 > > ret = 1 > > rv = -1 > > Ah, with QEMU running in client mode, the client cert + key are > optional. In this case you've not provided them (cert & key are 0x0 ie > NULL). Yep, I generated a client-key.pem, client-cert.pem and placed them in the same gnutls directory where the ca* and server* files are located. Indeed the TLS handshake completes succesfully (tested with the same QEMU CLI as above placed in a script): $ ./chardev-backend-qemu-as-tls-client.sh Handshake still running 2 Handshake still running 2 Handshake compelte session=0x7f8bdda6f4c0 On the GnuTLS server: [. . .] * Accepted connection from IPv4 127.0.0.1 port 51353 on Wed May 6 13:19:10 2015 - Description: (TLS1.2)-(ECDHE-RSA-SECP256R1)-(AES-128-CBC)-(SHA1) [. . .] - Server has requested a certificate. - Certificate type: X.509 - Got a certificate list of 1 certificates. [. . .] - Version: TLS1.2 - Key Exchange: ECDHE-RSA - Server Signature: RSA-SHA256 - Client Signature: RSA-SHA256 - Compression: NULL - Options: safe renegotiation, - Channel binding 'tls-unique': 7f4ae1e0dc02dbad602a9c27 > We are then mistakenly calling gnutls_certificate_set_x509_key_file2 - > if I simply skip that I'll avoid the crash. Thanks for testing this - > I'll add a test case to validate this scenario too
diff --git a/qapi-schema.json b/qapi-schema.json index ac9594d..062a455 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2782,6 +2782,8 @@ # Since: 1.4 ## { 'type': 'ChardevSocket', 'data': { 'addr' : 'SocketAddress', + '*tls-cred' : 'str', + '*acl' : 'str', '*server' : 'bool', '*wait' : 'bool', '*nodelay' : 'bool', diff --git a/qemu-char.c b/qemu-char.c index 85fbbaf..da6f188 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -33,6 +33,8 @@ #include "qapi-visit.h" #include "io/channel-socket.h" #include "io/channel-file.h" +#include "io/channel-tls.h" +#include "qemu/acl.h" #include <unistd.h> #include <fcntl.h> @@ -2466,9 +2468,12 @@ static CharDriverState *qemu_chr_open_udp_fd(int fd) /* TCP Net console */ typedef struct { - QIOChannel *ioc; + QIOChannel *ioc; /* Client I/O channel */ + QIOChannelSocket *sioc; /* Client master channel */ QIOChannelSocket *listen_ioc; guint listen_tag; + QCryptoTLSCreds *tls_creds; + char *acl; int connected; int max_size; int do_telnetopt; @@ -2699,6 +2704,8 @@ static void tcp_chr_disconnect(CharDriverState *chr) QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr); } remove_fd_in_watch(chr); + object_unref(OBJECT(s->sioc)); + s->sioc = NULL; object_unref(OBJECT(s->ioc)); s->ioc = NULL; SocketAddress_to_str(chr->filename, CHR_MAX_FILENAME_SIZE, @@ -2777,11 +2784,10 @@ static void tcp_chr_connect(void *opaque) { CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; - QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(s->ioc); sockaddr_to_str(chr->filename, CHR_MAX_FILENAME_SIZE, - &sioc->localAddr, sioc->localAddrLen, - &sioc->remoteAddr, sioc->remoteAddrLen, + &s->sioc->localAddr, s->sioc->localAddrLen, + &s->sioc->remoteAddr, s->sioc->remoteAddrLen, s->is_listen, s->is_telnet); s->connected = 1; @@ -2869,29 +2875,85 @@ static void tcp_chr_telnet_init(CharDriverState *chr) init); } -static int tcp_chr_new_client(CharDriverState *chr, QIOChannel *ioc) + +static void tcp_chr_tls_handshake(QIOTask *task, + gpointer user_data) +{ + CharDriverState *chr = user_data; + TCPCharDriver *s = chr->opaque; + + if (task->err) { + tcp_chr_disconnect(chr); + } else { + if (s->do_telnetopt) { + tcp_chr_telnet_init(chr); + } else { + tcp_chr_connect(chr); + } + } +} + + +static void tcp_chr_tls_init(CharDriverState *chr) +{ + TCPCharDriver *s = chr->opaque; + QIOChannelTLS *tioc; + Error *err = NULL; + + if (s->is_listen) { + tioc = qio_channel_tls_new_server( + s->ioc, s->tls_creds, + s->acl, + &err); + } else { + tioc = qio_channel_tls_new_client( + s->ioc, s->tls_creds, + s->addr->inet->host, + &err); + } + if (tioc == NULL) { + error_free(err); + tcp_chr_disconnect(chr); + } + object_unref(OBJECT(s->ioc)); + s->ioc = QIO_CHANNEL(tioc); + + qio_channel_tls_handshake(tioc, + tcp_chr_tls_handshake, + chr, + NULL); +} + + +static int tcp_chr_new_client(CharDriverState *chr, QIOChannelSocket *sioc) { TCPCharDriver *s = chr->opaque; if (s->ioc != NULL) { return -1; } - s->ioc = ioc; - object_ref(OBJECT(ioc)); + s->ioc = QIO_CHANNEL(sioc); + object_ref(OBJECT(s->ioc)); + s->sioc = sioc; + object_ref(OBJECT(s->sioc)); qio_channel_set_blocking(s->ioc, false); if (s->do_nodelay) { - qio_channel_socket_set_nodelay(QIO_CHANNEL_SOCKET(s->ioc), true); + qio_channel_socket_set_nodelay(s->sioc, true); } if (s->listen_tag) { g_source_remove(s->listen_tag); s->listen_tag = 0; } - if (s->do_telnetopt) { - tcp_chr_telnet_init(chr); + if (s->tls_creds) { + tcp_chr_tls_init(chr); } else { - tcp_chr_connect(chr); + if (s->do_telnetopt) { + tcp_chr_telnet_init(chr); + } else { + tcp_chr_connect(chr); + } } return 0; @@ -2901,14 +2963,14 @@ static int tcp_chr_new_client(CharDriverState *chr, QIOChannel *ioc) static int tcp_chr_add_client(CharDriverState *chr, int fd) { int ret; - QIOChannel *ioc; + QIOChannelSocket *sioc; - ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, NULL)); - if (!ioc) { + sioc = qio_channel_socket_new_fd(fd, NULL); + if (!sioc) { return -1; } - ret = tcp_chr_new_client(chr, ioc); - object_unref(OBJECT(ioc)); + ret = tcp_chr_new_client(chr, sioc); + object_unref(OBJECT(sioc)); return ret; } @@ -2917,17 +2979,16 @@ static gboolean tcp_chr_accept(QIOChannel *channel, void *opaque) { CharDriverState *chr = opaque; - QIOChannel *ioc; + QIOChannelSocket *sioc; - ioc = QIO_CHANNEL( - qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel), NULL)); - if (!ioc) { + sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel), NULL); + if (!sioc) { return TRUE; } - tcp_chr_new_client(chr, ioc); + tcp_chr_new_client(chr, sioc); - object_unref(OBJECT(ioc)); + object_unref(OBJECT(sioc)); return TRUE; } @@ -2959,6 +3020,9 @@ static void tcp_chr_close(CharDriverState *chr) } g_free(s->read_msgfds); } + if (s->tls_creds) { + object_unref(OBJECT(s->tls_creds)); + } if (s->write_msgfds_num) { g_free(s->write_msgfds); } @@ -2979,13 +3043,13 @@ static void qemu_chr_finish_socket_connection(CharDriverState *chr, int fd) s->listen_tag = qio_channel_add_watch( QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr); } else { - QIOChannel *ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, NULL)); - if (!ioc) { + QIOChannelSocket *sioc = qio_channel_socket_new_fd(fd, NULL); + if (!sioc) { close(fd); return; } - tcp_chr_new_client(chr, ioc); - object_unref(OBJECT(ioc)); + tcp_chr_new_client(chr, sioc); + object_unref(OBJECT(sioc)); } } @@ -3450,6 +3514,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, const char *path = qemu_opt_get(opts, "path"); const char *host = qemu_opt_get(opts, "host"); const char *port = qemu_opt_get(opts, "port"); + const char *tls_cred = qemu_opt_get(opts, "tls-cred"); + bool acl = qemu_opt_get_bool(opts, "acl", false); SocketAddress *addr; if (!path) { @@ -3461,6 +3527,11 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, error_setg(errp, "chardev: socket: no port given"); return; } + } else { + if (tls_cred) { + error_setg(errp, "TLS can only be used over TCP socket"); + return; + } } backend->socket = g_new0(ChardevSocket, 1); @@ -3475,6 +3546,11 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, backend->socket->wait = is_waitconnect; backend->socket->has_reconnect = true; backend->socket->reconnect = reconnect; + backend->socket->tls_cred = g_strdup(tls_cred); + if (acl) { + backend->socket->acl = g_strdup_printf("chr.%s.tlspeername", + qemu_opts_id(opts)); + } addr = g_new0(SocketAddress, 1); if (path) { @@ -3494,6 +3570,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, addr->inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0); } backend->socket->addr = addr; + return; } static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, @@ -3877,6 +3954,9 @@ QemuOptsList qemu_chardev_opts = { .name = "telnet", .type = QEMU_OPT_BOOL, },{ + .name = "tls-cred", + .type = QEMU_OPT_STRING, + },{ .name = "width", .type = QEMU_OPT_NUMBER, },{ @@ -4061,6 +4141,41 @@ static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, s->is_listen = is_listen; s->is_telnet = is_telnet; s->do_nodelay = do_nodelay; + if (sock->tls_cred) { + Object *container; + container = container_get(object_get_root(), "/objects"); + /* XXX this type cast causes an abort if the type is wrong. + * This is bad. We should check and set an error */ + s->tls_creds = QCRYPTO_TLS_CREDS( + object_resolve_path_component(container, + sock->tls_cred)); + if (!s->tls_creds) { + error_setg(errp, "No TLS credentials with id '%s'", + sock->tls_cred); + goto error; + } + object_ref(OBJECT(s->tls_creds)); + if (is_listen) { + if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { + error_setg(errp, "%s", + "Expected TLS credentials for server endpoint"); + goto error; + } + } else { + if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) { + error_setg(errp, "%s", + "Expected TLS credentials for client endpoint"); + goto error; + } + } + + if (sock->acl) { + s->acl = g_strdup(sock->acl); + + qemu_acl_init(s->acl); + } + } + qapi_copy_SocketAddress(&s->addr, sock->addr); chr->opaque = s; @@ -4090,10 +4205,7 @@ static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, if (s->reconnect_time) { socket_try_connect(chr); } else if (!qemu_chr_open_socket_fd(chr, errp)) { - g_free(s); - g_free(chr->filename); - g_free(chr); - return NULL; + goto error; } if (is_listen && is_waitconnect) { @@ -4104,6 +4216,16 @@ static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, } return chr; + + error: + if (s->tls_creds) { + object_unref(OBJECT(s->tls_creds)); + } + g_free(s->acl); + g_free(s); + g_free(chr->filename); + g_free(chr); + return NULL; } static CharDriverState *qmp_chardev_open_udp(ChardevUdp *udp, diff --git a/qemu-options.hx b/qemu-options.hx index 44d9be2..0c764fc 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2009,7 +2009,7 @@ ETEXI DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev null,id=id[,mux=on|off]\n" "-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4][,ipv6][,nodelay][,reconnect=seconds]\n" - " [,server][,nowait][,telnet][,reconnect=seconds][,mux=on|off] (tcp)\n" + " [,server][,nowait][,telnet][,reconnect=seconds][,mux=on|off][,tls-cred=ID][,acl] (tcp)\n" "-chardev socket,id=id,path=path[,server][,nowait][,telnet][,reconnect=seconds][,mux=on|off] (unix)\n" "-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n" " [,localport=localport][,ipv4][,ipv6][,mux=on|off]\n" @@ -2082,7 +2082,7 @@ Options to each backend are described below. A void device. This device will not emit any data, and will drop any data it receives. The null backend does not take any options. -@item -chardev socket ,id=@var{id} [@var{TCP options} or @var{unix options}] [,server] [,nowait] [,telnet] [,reconnect=@var{seconds}] +@item -chardev socket ,id=@var{id} [@var{TCP options} or @var{unix options}] [,server] [,nowait] [,telnet] [,reconnect=@var{seconds}][,tls-cred=@var{id}] Create a two-way stream socket, which can be either a TCP or a unix socket. A unix socket will be created if @option{path} is specified. Behaviour is @@ -2100,6 +2100,11 @@ escape sequences. the remote end goes away. qemu will delay this many seconds and then attempt to reconnect. Zero disables reconnecting, and is the default. +@option{tls-cred} requests enablement of the TLS protocol for encryption, +and specifies the id of the TLS credentials to use for the handshake. The +credentials must be previously created with the @option{-object qcrypto-tls-cred} +argument. + TCP and unix socket options are given below: @table @option
This integrates support for QIOChannelTLS object in the TCP chardev backend. If the 'tls-cred=NAME' option is passed with the '-chardev tcp' argument, then it will setup the chardev such that the client is required to establish a TLS handshake when connecting. The 'acl' option will further enable the creation of a 'char.$ID.tlspeername' ACL which will be used to validate the client x509 certificate, if provided. A complete invokation to run QEMU as the server for a TLS encrypted serial dev might be $ qemu-system-x86_64 \ -nodefconfig -nodefaults -device sga -display none \ -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0,server \ -device isa-serial,chardev=s0 \ -object qcrypto-tls-cred,id=tls0,credtype=x509,\ endpoint=server,dir=/home/berrange/security/qemutls,verify-peer=off To test with the gnutls-cli tool as the client: $ gnutls-cli --priority=NORMAL -p 9000 \ --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ 127.0.0.1 If QEMU was told to use 'anon' credential type, then use the priority string 'NOMAL:+ANON-DH' with gnutls-cli Alternatively, if setting up a chardev to operate as a client, then the TLS credentials registered must be for the client endpoint. First a TLS server must be setup, which can be done with the gnutls-serv tool $ gnutls-serv --priority=NORMAL -p 9000 \ --x509cafile=/home/berrange/security/qemutls/ca-cert.pem \ --x509certfile=/home/berrange/security/qemutls/server-cert.pem \ --x509keyfile=/home/berrange/security/qemutls/server-key.pem Then QEMU can connect with $ qemu-system-x86_64 \ -nodefconfig -nodefaults -device sga -display none \ -chardev socket,id=s0,host=127.0.0.1,port=9000,tls-cred=tls0 \ -device isa-serial,chardev=s0 \ -object qcrypto-tls-cred,id=tls0,credtype=x509,\ endpoint=client,dir=/home/berrange/security/qemutls Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- qapi-schema.json | 2 + qemu-char.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++--------- qemu-options.hx | 9 ++- 3 files changed, 161 insertions(+), 32 deletions(-)