Merge vnc-crypto-v9
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJV+CwGAAoJEL6G67QVEE/fResQAKiHbjRRPjtCNjAvVixd2ewa O39TXlgQol4EiMKgsrIJf33yaEJQIj5ElNfKOUysgcLdGfL69+XWGQ5WgoHZx40d 0Iiy8rGOTmCAQMgQYkRmJyayPTkK96jt8rl9psE0ab7JhS4CA2NbgnPWLLzVFwEx 0BJ0SgHvzIGYy0N+9aQ7lVVUUja/Ksg64/6AAPpBHMkBZkOruk132E9B0D0mL7kL rka3OMgLpKqginKD4t3MKII1CnR5iSS2NNB/fJxVzrWK84Wv1/SbD1QnSlHPFWl6 ffeD9j3F8ihFVdi0nssxK6kHYZW+dAeC8VPxpLcnFffHiNa7yU4XGQxmMuR3F/W/ Su/R6W9JSP1dY6MCvCPjJNa2t9AW5iG0pGm4MckoZp4H6F46OPuxb0/GWoz/9prU S7BPLoB3h7h3otmokIL2MvqlU/5lfqUhlhW7w7ZS6fTNXUT2amFlq2UJZpFuEt0b 3kAsAaGAq4wk5QB04lSbxW+u/F669L0dobu2FtOHiHECe3bihrCxk0OckzdA0fOP kZ14jIsvagXgWG2NAMQFKKXL3OCpfbObEm+mQp6JR6y108TwdXR3XYCudVHAHyK7 GS+rhTdOtUgtQgpJG97RgdBd1nvil2dZ+NizX9DXu5EhT6le3PKijIOkq/6TLw5H 5qAYBZCGQXl1bNrmifcH =6TWk -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/berrange/tags/vnc-crypto-v9-for-upstream' into staging Merge vnc-crypto-v9 # gpg: Signature made Tue 15 Sep 2015 15:32:38 BST using RSA key ID 15104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" * remotes/berrange/tags/vnc-crypto-v9-for-upstream: ui: convert VNC server to use QCryptoTLSSession ui: fix return type for VNC I/O functions to be ssize_t crypto: introduce new module for handling TLS sessions crypto: add sanity checking of TLS x509 credentials crypto: introduce new module for TLS x509 credentials crypto: introduce new module for TLS anonymous credentials crypto: introduce new base module for TLS credentials qom: allow QOM to be linked into tools binaries crypto: move crypto objects out of libqemuutil.la tests: remove repetition in unit test object deps qapi: allow override of default enum prefix naming Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						619622424d
					
				
							
								
								
									
										11
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Makefile
									
									
									
									
									
								
							@ -152,6 +152,9 @@ dummy := $(call unnest-vars,, \
 | 
				
			|||||||
                qga-vss-dll-obj-y \
 | 
					                qga-vss-dll-obj-y \
 | 
				
			||||||
                block-obj-y \
 | 
					                block-obj-y \
 | 
				
			||||||
                block-obj-m \
 | 
					                block-obj-m \
 | 
				
			||||||
 | 
					                crypto-obj-y \
 | 
				
			||||||
 | 
					                crypto-aes-obj-y \
 | 
				
			||||||
 | 
					                qom-obj-y \
 | 
				
			||||||
                common-obj-y \
 | 
					                common-obj-y \
 | 
				
			||||||
                common-obj-m)
 | 
					                common-obj-m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -173,6 +176,8 @@ SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
 | 
				
			|||||||
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
 | 
					SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
 | 
					$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
 | 
				
			||||||
 | 
					$(SOFTMMU_SUBDIR_RULES): $(crypto-obj-y)
 | 
				
			||||||
 | 
					$(SOFTMMU_SUBDIR_RULES): $(qom-obj-y)
 | 
				
			||||||
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
 | 
					$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
subdir-%:
 | 
					subdir-%:
 | 
				
			||||||
@ -227,9 +232,9 @@ util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
qemu-img.o: qemu-img-cmds.h
 | 
					qemu-img.o: qemu-img-cmds.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a
 | 
					qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
 | 
				
			||||||
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a
 | 
					qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
 | 
				
			||||||
qemu-io$(EXESUF): qemu-io.o $(block-obj-y) libqemuutil.a libqemustub.a
 | 
					qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
 | 
					qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,6 @@
 | 
				
			|||||||
# Common libraries for tools and emulators
 | 
					# Common libraries for tools and emulators
 | 
				
			||||||
stub-obj-y = stubs/
 | 
					stub-obj-y = stubs/
 | 
				
			||||||
util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o qapi-event.o
 | 
					util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o qapi-event.o
 | 
				
			||||||
util-obj-y += crypto/
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#######################################################################
 | 
					#######################################################################
 | 
				
			||||||
# block-obj-y is code used by both qemu system emulation and qemu-img
 | 
					# block-obj-y is code used by both qemu system emulation and qemu-img
 | 
				
			||||||
@ -21,6 +20,16 @@ block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
block-obj-m = block/
 | 
					block-obj-m = block/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#######################################################################
 | 
				
			||||||
 | 
					# crypto-obj-y is code used by both qemu system emulation and qemu-img
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					crypto-obj-y = crypto/
 | 
				
			||||||
 | 
					crypto-aes-obj-y = crypto/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#######################################################################
 | 
				
			||||||
 | 
					# qom-obj-y is code used by both qemu system emulation and qemu-img
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qom-obj-y = qom/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
######################################################################
 | 
					######################################################################
 | 
				
			||||||
# smartcard
 | 
					# smartcard
 | 
				
			||||||
 | 
				
			|||||||
@ -170,12 +170,18 @@ target-obj-y-save := $(target-obj-y)
 | 
				
			|||||||
dummy := $(call unnest-vars,.., \
 | 
					dummy := $(call unnest-vars,.., \
 | 
				
			||||||
               block-obj-y \
 | 
					               block-obj-y \
 | 
				
			||||||
               block-obj-m \
 | 
					               block-obj-m \
 | 
				
			||||||
 | 
					               crypto-obj-y \
 | 
				
			||||||
 | 
					               crypto-aes-obj-y \
 | 
				
			||||||
 | 
					               qom-obj-y \
 | 
				
			||||||
               common-obj-y \
 | 
					               common-obj-y \
 | 
				
			||||||
               common-obj-m)
 | 
					               common-obj-m)
 | 
				
			||||||
target-obj-y := $(target-obj-y-save)
 | 
					target-obj-y := $(target-obj-y-save)
 | 
				
			||||||
all-obj-y += $(common-obj-y)
 | 
					all-obj-y += $(common-obj-y)
 | 
				
			||||||
all-obj-y += $(target-obj-y)
 | 
					all-obj-y += $(target-obj-y)
 | 
				
			||||||
 | 
					all-obj-y += $(qom-obj-y)
 | 
				
			||||||
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y)
 | 
					all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y)
 | 
				
			||||||
 | 
					all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y)
 | 
				
			||||||
 | 
					all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(QEMU_PROG_BUILD): config-devices.mak
 | 
					$(QEMU_PROG_BUILD): config-devices.mak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										53
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								configure
									
									
									
									
										vendored
									
									
								
							@ -242,7 +242,6 @@ vnc="yes"
 | 
				
			|||||||
sparse="no"
 | 
					sparse="no"
 | 
				
			||||||
uuid=""
 | 
					uuid=""
 | 
				
			||||||
vde=""
 | 
					vde=""
 | 
				
			||||||
vnc_tls=""
 | 
					 | 
				
			||||||
vnc_sasl=""
 | 
					vnc_sasl=""
 | 
				
			||||||
vnc_jpeg=""
 | 
					vnc_jpeg=""
 | 
				
			||||||
vnc_png=""
 | 
					vnc_png=""
 | 
				
			||||||
@ -416,6 +415,9 @@ if test "$debug_info" = "yes"; then
 | 
				
			|||||||
    LDFLAGS="-g $LDFLAGS"
 | 
					    LDFLAGS="-g $LDFLAGS"
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_cflags=""
 | 
				
			||||||
 | 
					test_libs=""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# make source path absolute
 | 
					# make source path absolute
 | 
				
			||||||
source_path=`cd "$source_path"; pwd`
 | 
					source_path=`cd "$source_path"; pwd`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -880,10 +882,6 @@ for opt do
 | 
				
			|||||||
  ;;
 | 
					  ;;
 | 
				
			||||||
  --disable-strip) strip_opt="no"
 | 
					  --disable-strip) strip_opt="no"
 | 
				
			||||||
  ;;
 | 
					  ;;
 | 
				
			||||||
  --disable-vnc-tls) vnc_tls="no"
 | 
					 | 
				
			||||||
  ;;
 | 
					 | 
				
			||||||
  --enable-vnc-tls) vnc_tls="yes"
 | 
					 | 
				
			||||||
  ;;
 | 
					 | 
				
			||||||
  --disable-vnc-sasl) vnc_sasl="no"
 | 
					  --disable-vnc-sasl) vnc_sasl="no"
 | 
				
			||||||
  ;;
 | 
					  ;;
 | 
				
			||||||
  --enable-vnc-sasl) vnc_sasl="yes"
 | 
					  --enable-vnc-sasl) vnc_sasl="yes"
 | 
				
			||||||
@ -2249,6 +2247,19 @@ if test "$gnutls_nettle" != "no"; then
 | 
				
			|||||||
    fi
 | 
					    fi
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##########################################
 | 
				
			||||||
 | 
					# libtasn1 - only for the TLS creds/session test suite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tasn1=yes
 | 
				
			||||||
 | 
					if $pkg_config --exists "libtasn1"; then
 | 
				
			||||||
 | 
					    tasn1_cflags=`$pkg_config --cflags libtasn1`
 | 
				
			||||||
 | 
					    tasn1_libs=`$pkg_config --libs libtasn1`
 | 
				
			||||||
 | 
					    test_cflags="$test_cflags $tasn1_cflags"
 | 
				
			||||||
 | 
					    test_libs="$test_libs $tasn1_libs"
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    tasn1=no
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##########################################
 | 
					##########################################
 | 
				
			||||||
# VTE probe
 | 
					# VTE probe
 | 
				
			||||||
@ -2393,28 +2404,6 @@ EOF
 | 
				
			|||||||
  fi
 | 
					  fi
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##########################################
 | 
					 | 
				
			||||||
# VNC TLS/WS detection
 | 
					 | 
				
			||||||
if test "$vnc" = "yes" -a "$vnc_tls" != "no" ; then
 | 
					 | 
				
			||||||
  cat > $TMPC <<EOF
 | 
					 | 
				
			||||||
#include <gnutls/gnutls.h>
 | 
					 | 
				
			||||||
int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; }
 | 
					 | 
				
			||||||
EOF
 | 
					 | 
				
			||||||
  vnc_tls_cflags=`$pkg_config --cflags gnutls 2> /dev/null`
 | 
					 | 
				
			||||||
  vnc_tls_libs=`$pkg_config --libs gnutls 2> /dev/null`
 | 
					 | 
				
			||||||
  if compile_prog "$vnc_tls_cflags" "$vnc_tls_libs" ; then
 | 
					 | 
				
			||||||
    if test "$vnc_tls" != "no" ; then
 | 
					 | 
				
			||||||
      vnc_tls=yes
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    libs_softmmu="$vnc_tls_libs $libs_softmmu"
 | 
					 | 
				
			||||||
    QEMU_CFLAGS="$QEMU_CFLAGS $vnc_tls_cflags"
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    if test "$vnc_tls" = "yes" ; then
 | 
					 | 
				
			||||||
      feature_not_found "vnc-tls" "Install gnutls devel"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    vnc_tls=no
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
##########################################
 | 
					##########################################
 | 
				
			||||||
# VNC SASL detection
 | 
					# VNC SASL detection
 | 
				
			||||||
@ -4574,6 +4563,7 @@ echo "GNUTLS support    $gnutls"
 | 
				
			|||||||
echo "GNUTLS hash       $gnutls_hash"
 | 
					echo "GNUTLS hash       $gnutls_hash"
 | 
				
			||||||
echo "GNUTLS gcrypt     $gnutls_gcrypt"
 | 
					echo "GNUTLS gcrypt     $gnutls_gcrypt"
 | 
				
			||||||
echo "GNUTLS nettle     $gnutls_nettle ${gnutls_nettle+($nettle_version)}"
 | 
					echo "GNUTLS nettle     $gnutls_nettle ${gnutls_nettle+($nettle_version)}"
 | 
				
			||||||
 | 
					echo "libtasn1          $tasn1"
 | 
				
			||||||
echo "VTE support       $vte"
 | 
					echo "VTE support       $vte"
 | 
				
			||||||
echo "curses support    $curses"
 | 
					echo "curses support    $curses"
 | 
				
			||||||
echo "curl support      $curl"
 | 
					echo "curl support      $curl"
 | 
				
			||||||
@ -4584,7 +4574,6 @@ echo "Block whitelist (ro) $block_drv_ro_whitelist"
 | 
				
			|||||||
echo "VirtFS support    $virtfs"
 | 
					echo "VirtFS support    $virtfs"
 | 
				
			||||||
echo "VNC support       $vnc"
 | 
					echo "VNC support       $vnc"
 | 
				
			||||||
if test "$vnc" = "yes" ; then
 | 
					if test "$vnc" = "yes" ; then
 | 
				
			||||||
    echo "VNC TLS support   $vnc_tls"
 | 
					 | 
				
			||||||
    echo "VNC SASL support  $vnc_sasl"
 | 
					    echo "VNC SASL support  $vnc_sasl"
 | 
				
			||||||
    echo "VNC JPEG support  $vnc_jpeg"
 | 
					    echo "VNC JPEG support  $vnc_jpeg"
 | 
				
			||||||
    echo "VNC PNG support   $vnc_png"
 | 
					    echo "VNC PNG support   $vnc_png"
 | 
				
			||||||
@ -4793,9 +4782,6 @@ echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak
 | 
				
			|||||||
if test "$vnc" = "yes" ; then
 | 
					if test "$vnc" = "yes" ; then
 | 
				
			||||||
  echo "CONFIG_VNC=y" >> $config_host_mak
 | 
					  echo "CONFIG_VNC=y" >> $config_host_mak
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
if test "$vnc_tls" = "yes" ; then
 | 
					 | 
				
			||||||
  echo "CONFIG_VNC_TLS=y" >> $config_host_mak
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
if test "$vnc_sasl" = "yes" ; then
 | 
					if test "$vnc_sasl" = "yes" ; then
 | 
				
			||||||
  echo "CONFIG_VNC_SASL=y" >> $config_host_mak
 | 
					  echo "CONFIG_VNC_SASL=y" >> $config_host_mak
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
@ -4945,6 +4931,9 @@ if test "$gnutls_nettle" = "yes" ; then
 | 
				
			|||||||
  echo "CONFIG_GNUTLS_NETTLE=y" >> $config_host_mak
 | 
					  echo "CONFIG_GNUTLS_NETTLE=y" >> $config_host_mak
 | 
				
			||||||
  echo "CONFIG_NETTLE_VERSION_MAJOR=${nettle_version%%.*}" >> $config_host_mak
 | 
					  echo "CONFIG_NETTLE_VERSION_MAJOR=${nettle_version%%.*}" >> $config_host_mak
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					if test "$tasn1" = "yes" ; then
 | 
				
			||||||
 | 
					  echo "CONFIG_TASN1=y" >> $config_host_mak
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
if test "$vte" = "yes" ; then
 | 
					if test "$vte" = "yes" ; then
 | 
				
			||||||
  echo "CONFIG_VTE=y" >> $config_host_mak
 | 
					  echo "CONFIG_VTE=y" >> $config_host_mak
 | 
				
			||||||
  echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
 | 
					  echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
 | 
				
			||||||
@ -5268,6 +5257,8 @@ echo "EXESUF=$EXESUF" >> $config_host_mak
 | 
				
			|||||||
echo "DSOSUF=$DSOSUF" >> $config_host_mak
 | 
					echo "DSOSUF=$DSOSUF" >> $config_host_mak
 | 
				
			||||||
echo "LDFLAGS_SHARED=$LDFLAGS_SHARED" >> $config_host_mak
 | 
					echo "LDFLAGS_SHARED=$LDFLAGS_SHARED" >> $config_host_mak
 | 
				
			||||||
echo "LIBS_QGA+=$libs_qga" >> $config_host_mak
 | 
					echo "LIBS_QGA+=$libs_qga" >> $config_host_mak
 | 
				
			||||||
 | 
					echo "TEST_LIBS=$test_libs" >> $config_host_mak
 | 
				
			||||||
 | 
					echo "TEST_CFLAGS=$test_cflags" >> $config_host_mak
 | 
				
			||||||
echo "POD2MAN=$POD2MAN" >> $config_host_mak
 | 
					echo "POD2MAN=$POD2MAN" >> $config_host_mak
 | 
				
			||||||
echo "TRANSLATE_OPT_CFLAGS=$TRANSLATE_OPT_CFLAGS" >> $config_host_mak
 | 
					echo "TRANSLATE_OPT_CFLAGS=$TRANSLATE_OPT_CFLAGS" >> $config_host_mak
 | 
				
			||||||
if test "$gcov" = "yes" ; then
 | 
					if test "$gcov" = "yes" ; then
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,12 @@
 | 
				
			|||||||
util-obj-y += init.o
 | 
					crypto-obj-y = init.o
 | 
				
			||||||
util-obj-y += hash.o
 | 
					crypto-obj-y += hash.o
 | 
				
			||||||
util-obj-y += aes.o
 | 
					crypto-obj-y += aes.o
 | 
				
			||||||
util-obj-y += desrfb.o
 | 
					crypto-obj-y += desrfb.o
 | 
				
			||||||
util-obj-y += cipher.o
 | 
					crypto-obj-y += cipher.o
 | 
				
			||||||
 | 
					crypto-obj-y += tlscreds.o
 | 
				
			||||||
 | 
					crypto-obj-y += tlscredsanon.o
 | 
				
			||||||
 | 
					crypto-obj-y += tlscredsx509.o
 | 
				
			||||||
 | 
					crypto-obj-y += tlssession.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Let the userspace emulators avoid linking gnutls/etc
 | 
				
			||||||
 | 
					crypto-aes-obj-y = aes.o
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										251
									
								
								crypto/tlscreds.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								crypto/tlscreds.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,251 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU crypto TLS credential support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto/tlscredspriv.h"
 | 
				
			||||||
 | 
					#include "trace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DH_BITS 2048
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
 | 
				
			||||||
 | 
					                                     const char *filename,
 | 
				
			||||||
 | 
					                                     gnutls_dh_params_t *dh_params,
 | 
				
			||||||
 | 
					                                     Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_qcrypto_tls_creds_load_dh(creds, filename ? filename : "<generated>");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (filename == NULL) {
 | 
				
			||||||
 | 
					        ret = gnutls_dh_params_init(dh_params);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Unable to initialize DH parameters: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ret = gnutls_dh_params_generate2(*dh_params, DH_BITS);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            gnutls_dh_params_deinit(*dh_params);
 | 
				
			||||||
 | 
					            *dh_params = NULL;
 | 
				
			||||||
 | 
					            error_setg(errp, "Unable to generate DH parameters: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        GError *gerr = NULL;
 | 
				
			||||||
 | 
					        gchar *contents;
 | 
				
			||||||
 | 
					        gsize len;
 | 
				
			||||||
 | 
					        gnutls_datum_t data;
 | 
				
			||||||
 | 
					        if (!g_file_get_contents(filename,
 | 
				
			||||||
 | 
					                                 &contents,
 | 
				
			||||||
 | 
					                                 &len,
 | 
				
			||||||
 | 
					                                 &gerr)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            error_setg(errp, "%s", gerr->message);
 | 
				
			||||||
 | 
					            g_error_free(gerr);
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        data.data = (unsigned char *)contents;
 | 
				
			||||||
 | 
					        data.size = len;
 | 
				
			||||||
 | 
					        ret = gnutls_dh_params_init(dh_params);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            g_free(contents);
 | 
				
			||||||
 | 
					            error_setg(errp, "Unable to initialize DH parameters: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ret = gnutls_dh_params_import_pkcs3(*dh_params,
 | 
				
			||||||
 | 
					                                            &data,
 | 
				
			||||||
 | 
					                                            GNUTLS_X509_FMT_PEM);
 | 
				
			||||||
 | 
					        g_free(contents);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            gnutls_dh_params_deinit(*dh_params);
 | 
				
			||||||
 | 
					            *dh_params = NULL;
 | 
				
			||||||
 | 
					            error_setg(errp, "Unable to load DH parameters from %s: %s",
 | 
				
			||||||
 | 
					                       filename, gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_get_path(QCryptoTLSCreds *creds,
 | 
				
			||||||
 | 
					                           const char *filename,
 | 
				
			||||||
 | 
					                           bool required,
 | 
				
			||||||
 | 
					                           char **cred,
 | 
				
			||||||
 | 
					                           Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct stat sb;
 | 
				
			||||||
 | 
					    int ret = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!creds->dir) {
 | 
				
			||||||
 | 
					        if (required) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Missing 'dir' property value");
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *cred = g_strdup_printf("%s/%s", creds->dir, filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (stat(*cred, &sb) < 0) {
 | 
				
			||||||
 | 
					        if (errno == ENOENT && !required) {
 | 
				
			||||||
 | 
					            ret = 0;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            error_setg_errno(errp, errno,
 | 
				
			||||||
 | 
					                             "Unable to access credentials %s",
 | 
				
			||||||
 | 
					                             *cred);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        g_free(*cred);
 | 
				
			||||||
 | 
					        *cred = NULL;
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_qcrypto_tls_creds_get_path(creds, filename,
 | 
				
			||||||
 | 
					                                     *cred ? *cred : "<none>");
 | 
				
			||||||
 | 
					    ret = 0;
 | 
				
			||||||
 | 
					 cleanup:
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ! CONFIG_GNUTLS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_prop_set_verify(Object *obj,
 | 
				
			||||||
 | 
					                                  bool value,
 | 
				
			||||||
 | 
					                                  Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    creds->verifyPeer = value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					qcrypto_tls_creds_prop_get_verify(Object *obj,
 | 
				
			||||||
 | 
					                                  Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return creds->verifyPeer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_prop_set_dir(Object *obj,
 | 
				
			||||||
 | 
					                               const char *value,
 | 
				
			||||||
 | 
					                               Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    creds->dir = g_strdup(value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *
 | 
				
			||||||
 | 
					qcrypto_tls_creds_prop_get_dir(Object *obj,
 | 
				
			||||||
 | 
					                               Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return g_strdup(creds->dir);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_prop_set_endpoint(Object *obj,
 | 
				
			||||||
 | 
					                                    int value,
 | 
				
			||||||
 | 
					                                    Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    creds->endpoint = value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_prop_get_endpoint(Object *obj,
 | 
				
			||||||
 | 
					                                    Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return creds->endpoint;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_init(Object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    creds->verifyPeer = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    object_property_add_bool(obj, "verify-peer",
 | 
				
			||||||
 | 
					                             qcrypto_tls_creds_prop_get_verify,
 | 
				
			||||||
 | 
					                             qcrypto_tls_creds_prop_set_verify,
 | 
				
			||||||
 | 
					                             NULL);
 | 
				
			||||||
 | 
					    object_property_add_str(obj, "dir",
 | 
				
			||||||
 | 
					                            qcrypto_tls_creds_prop_get_dir,
 | 
				
			||||||
 | 
					                            qcrypto_tls_creds_prop_set_dir,
 | 
				
			||||||
 | 
					                            NULL);
 | 
				
			||||||
 | 
					    object_property_add_enum(obj, "endpoint",
 | 
				
			||||||
 | 
					                             "QCryptoTLSCredsEndpoint",
 | 
				
			||||||
 | 
					                             QCryptoTLSCredsEndpoint_lookup,
 | 
				
			||||||
 | 
					                             qcrypto_tls_creds_prop_get_endpoint,
 | 
				
			||||||
 | 
					                             qcrypto_tls_creds_prop_set_endpoint,
 | 
				
			||||||
 | 
					                             NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_finalize(Object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_free(creds->dir);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const TypeInfo qcrypto_tls_creds_info = {
 | 
				
			||||||
 | 
					    .parent = TYPE_OBJECT,
 | 
				
			||||||
 | 
					    .name = TYPE_QCRYPTO_TLS_CREDS,
 | 
				
			||||||
 | 
					    .instance_size = sizeof(QCryptoTLSCreds),
 | 
				
			||||||
 | 
					    .instance_init = qcrypto_tls_creds_init,
 | 
				
			||||||
 | 
					    .instance_finalize = qcrypto_tls_creds_finalize,
 | 
				
			||||||
 | 
					    .class_size = sizeof(QCryptoTLSCredsClass),
 | 
				
			||||||
 | 
					    .abstract = true,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_register_types(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type_register_static(&qcrypto_tls_creds_info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type_init(qcrypto_tls_creds_register_types);
 | 
				
			||||||
							
								
								
									
										223
									
								
								crypto/tlscredsanon.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								crypto/tlscredsanon.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,223 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU crypto TLS anonymous credential support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto/tlscredsanon.h"
 | 
				
			||||||
 | 
					#include "crypto/tlscredspriv.h"
 | 
				
			||||||
 | 
					#include "qom/object_interfaces.h"
 | 
				
			||||||
 | 
					#include "trace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds,
 | 
				
			||||||
 | 
					                            Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *dhparams = NULL;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    int rv = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_qcrypto_tls_creds_anon_load(creds,
 | 
				
			||||||
 | 
					            creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
 | 
				
			||||||
 | 
					        if (qcrypto_tls_creds_get_path(&creds->parent_obj,
 | 
				
			||||||
 | 
					                                       QCRYPTO_TLS_CREDS_DH_PARAMS,
 | 
				
			||||||
 | 
					                                       false, &dhparams, errp) < 0) {
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ret = gnutls_anon_allocate_server_credentials(&creds->data.server);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Cannot allocate credentials: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
 | 
				
			||||||
 | 
					                                                 &creds->parent_obj.dh_params,
 | 
				
			||||||
 | 
					                                                 errp) < 0) {
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gnutls_anon_set_server_dh_params(creds->data.server,
 | 
				
			||||||
 | 
					                                         creds->parent_obj.dh_params);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        ret = gnutls_anon_allocate_client_credentials(&creds->data.client);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Cannot allocate credentials: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rv = 0;
 | 
				
			||||||
 | 
					 cleanup:
 | 
				
			||||||
 | 
					    g_free(dhparams);
 | 
				
			||||||
 | 
					    return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_unload(QCryptoTLSCredsAnon *creds)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
 | 
				
			||||||
 | 
					        if (creds->data.client) {
 | 
				
			||||||
 | 
					            gnutls_anon_free_client_credentials(creds->data.client);
 | 
				
			||||||
 | 
					            creds->data.client = NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (creds->data.server) {
 | 
				
			||||||
 | 
					            gnutls_anon_free_server_credentials(creds->data.server);
 | 
				
			||||||
 | 
					            creds->data.server = NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (creds->parent_obj.dh_params) {
 | 
				
			||||||
 | 
					        gnutls_dh_params_deinit(creds->parent_obj.dh_params);
 | 
				
			||||||
 | 
					        creds->parent_obj.dh_params = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else /* ! CONFIG_GNUTLS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					                            Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    error_setg(errp, "TLS credentials support requires GNUTLS");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_unload(QCryptoTLSCredsAnon *creds G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* nada */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ! CONFIG_GNUTLS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_prop_set_loaded(Object *obj,
 | 
				
			||||||
 | 
					                                       bool value,
 | 
				
			||||||
 | 
					                                       Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (value) {
 | 
				
			||||||
 | 
					        qcrypto_tls_creds_anon_load(creds, errp);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        qcrypto_tls_creds_anon_unload(creds);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_prop_get_loaded(Object *obj,
 | 
				
			||||||
 | 
					                                       Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
 | 
				
			||||||
 | 
					        return creds->data.server != NULL;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return creds->data.client != NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else /* ! CONFIG_GNUTLS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_prop_get_loaded(Object *obj G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					                                       Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ! CONFIG_GNUTLS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    object_property_set_bool(OBJECT(uc), true, "loaded", errp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_init(Object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    object_property_add_bool(obj, "loaded",
 | 
				
			||||||
 | 
					                             qcrypto_tls_creds_anon_prop_get_loaded,
 | 
				
			||||||
 | 
					                             qcrypto_tls_creds_anon_prop_set_loaded,
 | 
				
			||||||
 | 
					                             NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_finalize(Object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qcrypto_tls_creds_anon_unload(creds);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_class_init(ObjectClass *oc, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ucc->complete = qcrypto_tls_creds_anon_complete;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const TypeInfo qcrypto_tls_creds_anon_info = {
 | 
				
			||||||
 | 
					    .parent = TYPE_QCRYPTO_TLS_CREDS,
 | 
				
			||||||
 | 
					    .name = TYPE_QCRYPTO_TLS_CREDS_ANON,
 | 
				
			||||||
 | 
					    .instance_size = sizeof(QCryptoTLSCredsAnon),
 | 
				
			||||||
 | 
					    .instance_init = qcrypto_tls_creds_anon_init,
 | 
				
			||||||
 | 
					    .instance_finalize = qcrypto_tls_creds_anon_finalize,
 | 
				
			||||||
 | 
					    .class_size = sizeof(QCryptoTLSCredsAnonClass),
 | 
				
			||||||
 | 
					    .class_init = qcrypto_tls_creds_anon_class_init,
 | 
				
			||||||
 | 
					    .interfaces = (InterfaceInfo[]) {
 | 
				
			||||||
 | 
					        { TYPE_USER_CREATABLE },
 | 
				
			||||||
 | 
					        { }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_register_types(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type_register_static(&qcrypto_tls_creds_anon_info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type_init(qcrypto_tls_creds_anon_register_types);
 | 
				
			||||||
							
								
								
									
										42
									
								
								crypto/tlscredspriv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								crypto/tlscredspriv.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU crypto TLS credential support private helpers
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef QCRYPTO_TLSCRED_PRIV_H__
 | 
				
			||||||
 | 
					#define QCRYPTO_TLSCRED_PRIV_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto/tlscreds.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int qcrypto_tls_creds_get_path(QCryptoTLSCreds *creds,
 | 
				
			||||||
 | 
					                               const char *filename,
 | 
				
			||||||
 | 
					                               bool required,
 | 
				
			||||||
 | 
					                               char **cred,
 | 
				
			||||||
 | 
					                               Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
 | 
				
			||||||
 | 
					                                         const char *filename,
 | 
				
			||||||
 | 
					                                         gnutls_dh_params_t *dh_params,
 | 
				
			||||||
 | 
					                                         Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* QCRYPTO_TLSCRED_PRIV_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										809
									
								
								crypto/tlscredsx509.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										809
									
								
								crypto/tlscredsx509.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,809 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU crypto TLS x509 credential support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto/tlscredsx509.h"
 | 
				
			||||||
 | 
					#include "crypto/tlscredspriv.h"
 | 
				
			||||||
 | 
					#include "qom/object_interfaces.h"
 | 
				
			||||||
 | 
					#include "trace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <gnutls/x509.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_check_cert_times(gnutls_x509_crt_t cert,
 | 
				
			||||||
 | 
					                                   const char *certFile,
 | 
				
			||||||
 | 
					                                   bool isServer,
 | 
				
			||||||
 | 
					                                   bool isCA,
 | 
				
			||||||
 | 
					                                   Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    time_t now = time(NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (now == ((time_t)-1)) {
 | 
				
			||||||
 | 
					        error_setg_errno(errp, errno, "cannot get current time");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (gnutls_x509_crt_get_expiration_time(cert) < now) {
 | 
				
			||||||
 | 
					        error_setg(errp,
 | 
				
			||||||
 | 
					                   (isCA ?
 | 
				
			||||||
 | 
					                    "The CA certificate %s has expired" :
 | 
				
			||||||
 | 
					                    (isServer ?
 | 
				
			||||||
 | 
					                     "The server certificate %s has expired" :
 | 
				
			||||||
 | 
					                     "The client certificate %s has expired")),
 | 
				
			||||||
 | 
					                   certFile);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (gnutls_x509_crt_get_activation_time(cert) > now) {
 | 
				
			||||||
 | 
					        error_setg(errp,
 | 
				
			||||||
 | 
					                   (isCA ?
 | 
				
			||||||
 | 
					                    "The CA certificate %s is not yet active" :
 | 
				
			||||||
 | 
					                    (isServer ?
 | 
				
			||||||
 | 
					                     "The server certificate %s is not yet active" :
 | 
				
			||||||
 | 
					                     "The client certificate %s is not yet active")),
 | 
				
			||||||
 | 
					                   certFile);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if LIBGNUTLS_VERSION_NUMBER >= 2
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The gnutls_x509_crt_get_basic_constraints function isn't
 | 
				
			||||||
 | 
					 * available in GNUTLS 1.0.x branches. This isn't critical
 | 
				
			||||||
 | 
					 * though, since gnutls_certificate_verify_peers2 will do
 | 
				
			||||||
 | 
					 * pretty much the same check at runtime, so we can just
 | 
				
			||||||
 | 
					 * disable this code
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_check_cert_basic_constraints(QCryptoTLSCredsX509 *creds,
 | 
				
			||||||
 | 
					                                               gnutls_x509_crt_t cert,
 | 
				
			||||||
 | 
					                                               const char *certFile,
 | 
				
			||||||
 | 
					                                               bool isServer,
 | 
				
			||||||
 | 
					                                               bool isCA,
 | 
				
			||||||
 | 
					                                               Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    status = gnutls_x509_crt_get_basic_constraints(cert, NULL, NULL, NULL);
 | 
				
			||||||
 | 
					    trace_qcrypto_tls_creds_x509_check_basic_constraints(
 | 
				
			||||||
 | 
					        creds, certFile, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (status > 0) { /* It is a CA cert */
 | 
				
			||||||
 | 
					        if (!isCA) {
 | 
				
			||||||
 | 
					            error_setg(errp, isServer ?
 | 
				
			||||||
 | 
					                       "The certificate %s basic constraints show a CA, "
 | 
				
			||||||
 | 
					                       "but we need one for a server" :
 | 
				
			||||||
 | 
					                       "The certificate %s basic constraints show a CA, "
 | 
				
			||||||
 | 
					                       "but we need one for a client",
 | 
				
			||||||
 | 
					                       certFile);
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (status == 0) { /* It is not a CA cert */
 | 
				
			||||||
 | 
					        if (isCA) {
 | 
				
			||||||
 | 
					            error_setg(errp,
 | 
				
			||||||
 | 
					                       "The certificate %s basic constraints do not "
 | 
				
			||||||
 | 
					                       "show a CA",
 | 
				
			||||||
 | 
					                       certFile);
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
 | 
				
			||||||
 | 
					        /* Missing basicConstraints */
 | 
				
			||||||
 | 
					        if (isCA) {
 | 
				
			||||||
 | 
					            error_setg(errp,
 | 
				
			||||||
 | 
					                       "The certificate %s is missing basic constraints "
 | 
				
			||||||
 | 
					                       "for a CA",
 | 
				
			||||||
 | 
					                       certFile);
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else { /* General error */
 | 
				
			||||||
 | 
					        error_setg(errp,
 | 
				
			||||||
 | 
					                   "Unable to query certificate %s basic constraints: %s",
 | 
				
			||||||
 | 
					                   certFile, gnutls_strerror(status));
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 *creds,
 | 
				
			||||||
 | 
					                                       gnutls_x509_crt_t cert,
 | 
				
			||||||
 | 
					                                       const char *certFile,
 | 
				
			||||||
 | 
					                                       bool isCA,
 | 
				
			||||||
 | 
					                                       Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int status;
 | 
				
			||||||
 | 
					    unsigned int usage = 0;
 | 
				
			||||||
 | 
					    unsigned int critical = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    status = gnutls_x509_crt_get_key_usage(cert, &usage, &critical);
 | 
				
			||||||
 | 
					    trace_qcrypto_tls_creds_x509_check_key_usage(
 | 
				
			||||||
 | 
					        creds, certFile, status, usage, critical);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (status < 0) {
 | 
				
			||||||
 | 
					        if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
 | 
				
			||||||
 | 
					            usage = isCA ? GNUTLS_KEY_KEY_CERT_SIGN :
 | 
				
			||||||
 | 
					                GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            error_setg(errp,
 | 
				
			||||||
 | 
					                       "Unable to query certificate %s key usage: %s",
 | 
				
			||||||
 | 
					                       certFile, gnutls_strerror(status));
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (isCA) {
 | 
				
			||||||
 | 
					        if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) {
 | 
				
			||||||
 | 
					            if (critical) {
 | 
				
			||||||
 | 
					                error_setg(errp,
 | 
				
			||||||
 | 
					                           "Certificate %s usage does not permit "
 | 
				
			||||||
 | 
					                           "certificate signing", certFile);
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (!(usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) {
 | 
				
			||||||
 | 
					            if (critical) {
 | 
				
			||||||
 | 
					                error_setg(errp,
 | 
				
			||||||
 | 
					                           "Certificate %s usage does not permit digital "
 | 
				
			||||||
 | 
					                           "signature", certFile);
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) {
 | 
				
			||||||
 | 
					            if (critical) {
 | 
				
			||||||
 | 
					                error_setg(errp,
 | 
				
			||||||
 | 
					                           "Certificate %s usage does not permit key "
 | 
				
			||||||
 | 
					                           "encipherment", certFile);
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_check_cert_key_purpose(QCryptoTLSCredsX509 *creds,
 | 
				
			||||||
 | 
					                                         gnutls_x509_crt_t cert,
 | 
				
			||||||
 | 
					                                         const char *certFile,
 | 
				
			||||||
 | 
					                                         bool isServer,
 | 
				
			||||||
 | 
					                                         Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int status;
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					    unsigned int purposeCritical;
 | 
				
			||||||
 | 
					    unsigned int critical;
 | 
				
			||||||
 | 
					    char *buffer = NULL;
 | 
				
			||||||
 | 
					    size_t size;
 | 
				
			||||||
 | 
					    bool allowClient = false, allowServer = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    critical = 0;
 | 
				
			||||||
 | 
					    for (i = 0; ; i++) {
 | 
				
			||||||
 | 
					        size = 0;
 | 
				
			||||||
 | 
					        status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer,
 | 
				
			||||||
 | 
					                                                     &size, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* If there is no data at all, then we must allow
 | 
				
			||||||
 | 
					               client/server to pass */
 | 
				
			||||||
 | 
					            if (i == 0) {
 | 
				
			||||||
 | 
					                allowServer = allowClient = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (status != GNUTLS_E_SHORT_MEMORY_BUFFER) {
 | 
				
			||||||
 | 
					            error_setg(errp,
 | 
				
			||||||
 | 
					                       "Unable to query certificate %s key purpose: %s",
 | 
				
			||||||
 | 
					                       certFile, gnutls_strerror(status));
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = g_new0(char, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer,
 | 
				
			||||||
 | 
					                                                     &size, &purposeCritical);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (status < 0) {
 | 
				
			||||||
 | 
					            trace_qcrypto_tls_creds_x509_check_key_purpose(
 | 
				
			||||||
 | 
					                creds, certFile, status, "<none>", purposeCritical);
 | 
				
			||||||
 | 
					            g_free(buffer);
 | 
				
			||||||
 | 
					            error_setg(errp,
 | 
				
			||||||
 | 
					                       "Unable to query certificate %s key purpose: %s",
 | 
				
			||||||
 | 
					                       certFile, gnutls_strerror(status));
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        trace_qcrypto_tls_creds_x509_check_key_purpose(
 | 
				
			||||||
 | 
					            creds, certFile, status, buffer, purposeCritical);
 | 
				
			||||||
 | 
					        if (purposeCritical) {
 | 
				
			||||||
 | 
					            critical = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_SERVER)) {
 | 
				
			||||||
 | 
					            allowServer = true;
 | 
				
			||||||
 | 
					        } else if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_CLIENT)) {
 | 
				
			||||||
 | 
					            allowClient = true;
 | 
				
			||||||
 | 
					        } else if (g_str_equal(buffer, GNUTLS_KP_ANY)) {
 | 
				
			||||||
 | 
					            allowServer = allowClient = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g_free(buffer);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (isServer) {
 | 
				
			||||||
 | 
					        if (!allowServer) {
 | 
				
			||||||
 | 
					            if (critical) {
 | 
				
			||||||
 | 
					                error_setg(errp,
 | 
				
			||||||
 | 
					                           "Certificate %s purpose does not allow "
 | 
				
			||||||
 | 
					                           "use with a TLS server", certFile);
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (!allowClient) {
 | 
				
			||||||
 | 
					            if (critical) {
 | 
				
			||||||
 | 
					                error_setg(errp,
 | 
				
			||||||
 | 
					                           "Certificate %s purpose does not allow use "
 | 
				
			||||||
 | 
					                           "with a TLS client", certFile);
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_check_cert(QCryptoTLSCredsX509 *creds,
 | 
				
			||||||
 | 
					                             gnutls_x509_crt_t cert,
 | 
				
			||||||
 | 
					                             const char *certFile,
 | 
				
			||||||
 | 
					                             bool isServer,
 | 
				
			||||||
 | 
					                             bool isCA,
 | 
				
			||||||
 | 
					                             Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (qcrypto_tls_creds_check_cert_times(cert, certFile,
 | 
				
			||||||
 | 
					                                           isServer, isCA,
 | 
				
			||||||
 | 
					                                           errp) < 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if LIBGNUTLS_VERSION_NUMBER >= 2
 | 
				
			||||||
 | 
					    if (qcrypto_tls_creds_check_cert_basic_constraints(creds,
 | 
				
			||||||
 | 
					                                                       cert, certFile,
 | 
				
			||||||
 | 
					                                                       isServer, isCA,
 | 
				
			||||||
 | 
					                                                       errp) < 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (qcrypto_tls_creds_check_cert_key_usage(creds,
 | 
				
			||||||
 | 
					                                               cert, certFile,
 | 
				
			||||||
 | 
					                                               isCA, errp) < 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!isCA &&
 | 
				
			||||||
 | 
					        qcrypto_tls_creds_check_cert_key_purpose(creds,
 | 
				
			||||||
 | 
					                                                 cert, certFile,
 | 
				
			||||||
 | 
					                                                 isServer, errp) < 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t cert,
 | 
				
			||||||
 | 
					                                  const char *certFile,
 | 
				
			||||||
 | 
					                                  gnutls_x509_crt_t *cacerts,
 | 
				
			||||||
 | 
					                                  size_t ncacerts,
 | 
				
			||||||
 | 
					                                  const char *cacertFile,
 | 
				
			||||||
 | 
					                                  bool isServer,
 | 
				
			||||||
 | 
					                                  Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    unsigned int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (gnutls_x509_crt_list_verify(&cert, 1,
 | 
				
			||||||
 | 
					                                    cacerts, ncacerts,
 | 
				
			||||||
 | 
					                                    NULL, 0,
 | 
				
			||||||
 | 
					                                    0, &status) < 0) {
 | 
				
			||||||
 | 
					        error_setg(errp, isServer ?
 | 
				
			||||||
 | 
					                   "Unable to verify server certificate %s against "
 | 
				
			||||||
 | 
					                   "CA certificate %s" :
 | 
				
			||||||
 | 
					                   "Unable to verify client certificate %s against "
 | 
				
			||||||
 | 
					                   "CA certificate %s",
 | 
				
			||||||
 | 
					                   certFile, cacertFile);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (status != 0) {
 | 
				
			||||||
 | 
					        const char *reason = "Invalid certificate";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (status & GNUTLS_CERT_INVALID) {
 | 
				
			||||||
 | 
					            reason = "The certificate is not trusted";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
 | 
				
			||||||
 | 
					            reason = "The certificate hasn't got a known issuer";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (status & GNUTLS_CERT_REVOKED) {
 | 
				
			||||||
 | 
					            reason = "The certificate has been revoked";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef GNUTLS_1_0_COMPAT
 | 
				
			||||||
 | 
					        if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
 | 
				
			||||||
 | 
					            reason = "The certificate uses an insecure algorithm";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        error_setg(errp,
 | 
				
			||||||
 | 
					                   "Our own certificate %s failed validation against %s: %s",
 | 
				
			||||||
 | 
					                   certFile, cacertFile, reason);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static gnutls_x509_crt_t
 | 
				
			||||||
 | 
					qcrypto_tls_creds_load_cert(QCryptoTLSCredsX509 *creds,
 | 
				
			||||||
 | 
					                            const char *certFile,
 | 
				
			||||||
 | 
					                            bool isServer,
 | 
				
			||||||
 | 
					                            Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gnutls_datum_t data;
 | 
				
			||||||
 | 
					    gnutls_x509_crt_t cert = NULL;
 | 
				
			||||||
 | 
					    char *buf = NULL;
 | 
				
			||||||
 | 
					    gsize buflen;
 | 
				
			||||||
 | 
					    GError *gerr;
 | 
				
			||||||
 | 
					    int ret = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_qcrypto_tls_creds_x509_load_cert(creds, isServer, certFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (gnutls_x509_crt_init(&cert) < 0) {
 | 
				
			||||||
 | 
					        error_setg(errp, "Unable to initialize certificate");
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) {
 | 
				
			||||||
 | 
					        error_setg(errp, "Cannot load CA cert list %s: %s",
 | 
				
			||||||
 | 
					                   certFile, gerr->message);
 | 
				
			||||||
 | 
					        g_error_free(gerr);
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data.data = (unsigned char *)buf;
 | 
				
			||||||
 | 
					    data.size = strlen(buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM) < 0) {
 | 
				
			||||||
 | 
					        error_setg(errp, isServer ?
 | 
				
			||||||
 | 
					                   "Unable to import server certificate %s" :
 | 
				
			||||||
 | 
					                   "Unable to import client certificate %s",
 | 
				
			||||||
 | 
					                   certFile);
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 cleanup:
 | 
				
			||||||
 | 
					    if (ret != 0) {
 | 
				
			||||||
 | 
					        gnutls_x509_crt_deinit(cert);
 | 
				
			||||||
 | 
					        cert = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    g_free(buf);
 | 
				
			||||||
 | 
					    return cert;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 *creds,
 | 
				
			||||||
 | 
					                                    const char *certFile,
 | 
				
			||||||
 | 
					                                    gnutls_x509_crt_t *certs,
 | 
				
			||||||
 | 
					                                    unsigned int certMax,
 | 
				
			||||||
 | 
					                                    size_t *ncerts,
 | 
				
			||||||
 | 
					                                    Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gnutls_datum_t data;
 | 
				
			||||||
 | 
					    char *buf = NULL;
 | 
				
			||||||
 | 
					    gsize buflen;
 | 
				
			||||||
 | 
					    int ret = -1;
 | 
				
			||||||
 | 
					    GError *gerr = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *ncerts = 0;
 | 
				
			||||||
 | 
					    trace_qcrypto_tls_creds_x509_load_cert_list(creds, certFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) {
 | 
				
			||||||
 | 
					        error_setg(errp, "Cannot load CA cert list %s: %s",
 | 
				
			||||||
 | 
					                   certFile, gerr->message);
 | 
				
			||||||
 | 
					        g_error_free(gerr);
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data.data = (unsigned char *)buf;
 | 
				
			||||||
 | 
					    data.size = strlen(buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (gnutls_x509_crt_list_import(certs, &certMax, &data,
 | 
				
			||||||
 | 
					                                    GNUTLS_X509_FMT_PEM, 0) < 0) {
 | 
				
			||||||
 | 
					        error_setg(errp,
 | 
				
			||||||
 | 
					                   "Unable to import CA certificate list %s",
 | 
				
			||||||
 | 
					                   certFile);
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    *ncerts = certMax;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 cleanup:
 | 
				
			||||||
 | 
					    g_free(buf);
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_CERTS 16
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
 | 
				
			||||||
 | 
					                                    bool isServer,
 | 
				
			||||||
 | 
					                                    const char *cacertFile,
 | 
				
			||||||
 | 
					                                    const char *certFile,
 | 
				
			||||||
 | 
					                                    Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gnutls_x509_crt_t cert = NULL;
 | 
				
			||||||
 | 
					    gnutls_x509_crt_t cacerts[MAX_CERTS];
 | 
				
			||||||
 | 
					    size_t ncacerts = 0;
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					    int ret = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(cacerts, 0, sizeof(cacerts));
 | 
				
			||||||
 | 
					    if (access(certFile, R_OK) == 0) {
 | 
				
			||||||
 | 
					        cert = qcrypto_tls_creds_load_cert(creds,
 | 
				
			||||||
 | 
					                                           certFile, isServer,
 | 
				
			||||||
 | 
					                                           errp);
 | 
				
			||||||
 | 
					        if (!cert) {
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (access(cacertFile, R_OK) == 0) {
 | 
				
			||||||
 | 
					        if (qcrypto_tls_creds_load_ca_cert_list(creds,
 | 
				
			||||||
 | 
					                                                cacertFile, cacerts,
 | 
				
			||||||
 | 
					                                                MAX_CERTS, &ncacerts,
 | 
				
			||||||
 | 
					                                                errp) < 0) {
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cert &&
 | 
				
			||||||
 | 
					        qcrypto_tls_creds_check_cert(creds,
 | 
				
			||||||
 | 
					                                     cert, certFile, isServer,
 | 
				
			||||||
 | 
					                                     false, errp) < 0) {
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < ncacerts; i++) {
 | 
				
			||||||
 | 
					        if (qcrypto_tls_creds_check_cert(creds,
 | 
				
			||||||
 | 
					                                         cacerts[i], cacertFile,
 | 
				
			||||||
 | 
					                                         isServer, true, errp) < 0) {
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cert && ncacerts &&
 | 
				
			||||||
 | 
					        qcrypto_tls_creds_check_cert_pair(cert, certFile, cacerts,
 | 
				
			||||||
 | 
					                                          ncacerts, cacertFile,
 | 
				
			||||||
 | 
					                                          isServer, errp) < 0) {
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 cleanup:
 | 
				
			||||||
 | 
					    if (cert) {
 | 
				
			||||||
 | 
					        gnutls_x509_crt_deinit(cert);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (i = 0; i < ncacerts; i++) {
 | 
				
			||||||
 | 
					        gnutls_x509_crt_deinit(cacerts[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
 | 
				
			||||||
 | 
					                            Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *cacert = NULL, *cacrl = NULL, *cert = NULL,
 | 
				
			||||||
 | 
					        *key = NULL, *dhparams = NULL;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    int rv = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_qcrypto_tls_creds_x509_load(creds,
 | 
				
			||||||
 | 
					            creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
 | 
				
			||||||
 | 
					        if (qcrypto_tls_creds_get_path(&creds->parent_obj,
 | 
				
			||||||
 | 
					                                       QCRYPTO_TLS_CREDS_X509_CA_CERT,
 | 
				
			||||||
 | 
					                                       true, &cacert, errp) < 0 ||
 | 
				
			||||||
 | 
					            qcrypto_tls_creds_get_path(&creds->parent_obj,
 | 
				
			||||||
 | 
					                                       QCRYPTO_TLS_CREDS_X509_CA_CRL,
 | 
				
			||||||
 | 
					                                       false, &cacrl, errp) < 0 ||
 | 
				
			||||||
 | 
					            qcrypto_tls_creds_get_path(&creds->parent_obj,
 | 
				
			||||||
 | 
					                                       QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
 | 
				
			||||||
 | 
					                                       true, &cert, errp) < 0 ||
 | 
				
			||||||
 | 
					            qcrypto_tls_creds_get_path(&creds->parent_obj,
 | 
				
			||||||
 | 
					                                       QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
 | 
				
			||||||
 | 
					                                       true, &key, errp) < 0 ||
 | 
				
			||||||
 | 
					            qcrypto_tls_creds_get_path(&creds->parent_obj,
 | 
				
			||||||
 | 
					                                       QCRYPTO_TLS_CREDS_DH_PARAMS,
 | 
				
			||||||
 | 
					                                       false, &dhparams, errp) < 0) {
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (qcrypto_tls_creds_get_path(&creds->parent_obj,
 | 
				
			||||||
 | 
					                                       QCRYPTO_TLS_CREDS_X509_CA_CERT,
 | 
				
			||||||
 | 
					                                       true, &cacert, errp) < 0 ||
 | 
				
			||||||
 | 
					            qcrypto_tls_creds_get_path(&creds->parent_obj,
 | 
				
			||||||
 | 
					                                       QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
 | 
				
			||||||
 | 
					                                       false, &cert, errp) < 0 ||
 | 
				
			||||||
 | 
					            qcrypto_tls_creds_get_path(&creds->parent_obj,
 | 
				
			||||||
 | 
					                                       QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
 | 
				
			||||||
 | 
					                                       false, &key, errp) < 0) {
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (creds->sanityCheck &&
 | 
				
			||||||
 | 
					        qcrypto_tls_creds_x509_sanity_check(creds,
 | 
				
			||||||
 | 
					            creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
 | 
				
			||||||
 | 
					            cacert, cert, errp) < 0) {
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = gnutls_certificate_allocate_credentials(&creds->data);
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        error_setg(errp, "Cannot allocate credentials: '%s'",
 | 
				
			||||||
 | 
					                   gnutls_strerror(ret));
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = gnutls_certificate_set_x509_trust_file(creds->data,
 | 
				
			||||||
 | 
					                                                 cacert,
 | 
				
			||||||
 | 
					                                                 GNUTLS_X509_FMT_PEM);
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        error_setg(errp, "Cannot load CA certificate '%s': %s",
 | 
				
			||||||
 | 
					                   cacert, gnutls_strerror(ret));
 | 
				
			||||||
 | 
					        goto cleanup;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cert != NULL && key != NULL) {
 | 
				
			||||||
 | 
					        ret = gnutls_certificate_set_x509_key_file(creds->data,
 | 
				
			||||||
 | 
					                                                   cert, key,
 | 
				
			||||||
 | 
					                                                   GNUTLS_X509_FMT_PEM);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Cannot load certificate '%s' & key '%s': %s",
 | 
				
			||||||
 | 
					                       cert, key, gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cacrl != NULL) {
 | 
				
			||||||
 | 
					        ret = gnutls_certificate_set_x509_crl_file(creds->data,
 | 
				
			||||||
 | 
					                                                   cacrl,
 | 
				
			||||||
 | 
					                                                   GNUTLS_X509_FMT_PEM);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Cannot load CRL '%s': %s",
 | 
				
			||||||
 | 
					                       cacrl, gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
 | 
				
			||||||
 | 
					        if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
 | 
				
			||||||
 | 
					                                                 &creds->parent_obj.dh_params,
 | 
				
			||||||
 | 
					                                                 errp) < 0) {
 | 
				
			||||||
 | 
					            goto cleanup;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        gnutls_certificate_set_dh_params(creds->data,
 | 
				
			||||||
 | 
					                                         creds->parent_obj.dh_params);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rv = 0;
 | 
				
			||||||
 | 
					 cleanup:
 | 
				
			||||||
 | 
					    g_free(cacert);
 | 
				
			||||||
 | 
					    g_free(cacrl);
 | 
				
			||||||
 | 
					    g_free(cert);
 | 
				
			||||||
 | 
					    g_free(key);
 | 
				
			||||||
 | 
					    g_free(dhparams);
 | 
				
			||||||
 | 
					    return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (creds->data) {
 | 
				
			||||||
 | 
					        gnutls_certificate_free_credentials(creds->data);
 | 
				
			||||||
 | 
					        creds->data = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else /* ! CONFIG_GNUTLS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					                            Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    error_setg(errp, "TLS credentials support requires GNUTLS");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* nada */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ! CONFIG_GNUTLS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_prop_set_loaded(Object *obj,
 | 
				
			||||||
 | 
					                                       bool value,
 | 
				
			||||||
 | 
					                                       Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (value) {
 | 
				
			||||||
 | 
					        qcrypto_tls_creds_x509_load(creds, errp);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        qcrypto_tls_creds_x509_unload(creds);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_prop_get_loaded(Object *obj,
 | 
				
			||||||
 | 
					                                       Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return creds->data != NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else /* ! CONFIG_GNUTLS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_prop_get_loaded(Object *obj G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					                                       Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ! CONFIG_GNUTLS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_prop_set_sanity(Object *obj,
 | 
				
			||||||
 | 
					                                       bool value,
 | 
				
			||||||
 | 
					                                       Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    creds->sanityCheck = value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_prop_get_sanity(Object *obj,
 | 
				
			||||||
 | 
					                                       Error **errp G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return creds->sanityCheck;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    object_property_set_bool(OBJECT(uc), true, "loaded", errp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_init(Object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    creds->sanityCheck = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    object_property_add_bool(obj, "loaded",
 | 
				
			||||||
 | 
					                             qcrypto_tls_creds_x509_prop_get_loaded,
 | 
				
			||||||
 | 
					                             qcrypto_tls_creds_x509_prop_set_loaded,
 | 
				
			||||||
 | 
					                             NULL);
 | 
				
			||||||
 | 
					    object_property_add_bool(obj, "sanity-check",
 | 
				
			||||||
 | 
					                             qcrypto_tls_creds_x509_prop_get_sanity,
 | 
				
			||||||
 | 
					                             qcrypto_tls_creds_x509_prop_set_sanity,
 | 
				
			||||||
 | 
					                             NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_finalize(Object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qcrypto_tls_creds_x509_unload(creds);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ucc->complete = qcrypto_tls_creds_x509_complete;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const TypeInfo qcrypto_tls_creds_x509_info = {
 | 
				
			||||||
 | 
					    .parent = TYPE_QCRYPTO_TLS_CREDS,
 | 
				
			||||||
 | 
					    .name = TYPE_QCRYPTO_TLS_CREDS_X509,
 | 
				
			||||||
 | 
					    .instance_size = sizeof(QCryptoTLSCredsX509),
 | 
				
			||||||
 | 
					    .instance_init = qcrypto_tls_creds_x509_init,
 | 
				
			||||||
 | 
					    .instance_finalize = qcrypto_tls_creds_x509_finalize,
 | 
				
			||||||
 | 
					    .class_size = sizeof(QCryptoTLSCredsX509Class),
 | 
				
			||||||
 | 
					    .class_init = qcrypto_tls_creds_x509_class_init,
 | 
				
			||||||
 | 
					    .interfaces = (InterfaceInfo[]) {
 | 
				
			||||||
 | 
					        { TYPE_USER_CREATABLE },
 | 
				
			||||||
 | 
					        { }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_register_types(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type_register_static(&qcrypto_tls_creds_x509_info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type_init(qcrypto_tls_creds_x509_register_types);
 | 
				
			||||||
							
								
								
									
										574
									
								
								crypto/tlssession.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										574
									
								
								crypto/tlssession.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,574 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU crypto TLS session support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto/tlssession.h"
 | 
				
			||||||
 | 
					#include "crypto/tlscredsanon.h"
 | 
				
			||||||
 | 
					#include "crypto/tlscredsx509.h"
 | 
				
			||||||
 | 
					#include "qemu/acl.h"
 | 
				
			||||||
 | 
					#include "trace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <gnutls/x509.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct QCryptoTLSSession {
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *creds;
 | 
				
			||||||
 | 
					    gnutls_session_t handle;
 | 
				
			||||||
 | 
					    char *hostname;
 | 
				
			||||||
 | 
					    char *aclname;
 | 
				
			||||||
 | 
					    bool handshakeComplete;
 | 
				
			||||||
 | 
					    QCryptoTLSSessionWriteFunc writeFunc;
 | 
				
			||||||
 | 
					    QCryptoTLSSessionReadFunc readFunc;
 | 
				
			||||||
 | 
					    void *opaque;
 | 
				
			||||||
 | 
					    char *peername;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					qcrypto_tls_session_free(QCryptoTLSSession *session)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!session) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gnutls_deinit(session->handle);
 | 
				
			||||||
 | 
					    g_free(session->hostname);
 | 
				
			||||||
 | 
					    g_free(session->peername);
 | 
				
			||||||
 | 
					    g_free(session->aclname);
 | 
				
			||||||
 | 
					    object_unref(OBJECT(session->creds));
 | 
				
			||||||
 | 
					    g_free(session);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t
 | 
				
			||||||
 | 
					qcrypto_tls_session_push(void *opaque, const void *buf, size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSSession *session = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!session->writeFunc) {
 | 
				
			||||||
 | 
					        errno = EIO;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return session->writeFunc(buf, len, session->opaque);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t
 | 
				
			||||||
 | 
					qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSSession *session = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!session->readFunc) {
 | 
				
			||||||
 | 
					        errno = EIO;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return session->readFunc(buf, len, session->opaque);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QCryptoTLSSession *
 | 
				
			||||||
 | 
					qcrypto_tls_session_new(QCryptoTLSCreds *creds,
 | 
				
			||||||
 | 
					                        const char *hostname,
 | 
				
			||||||
 | 
					                        const char *aclname,
 | 
				
			||||||
 | 
					                        QCryptoTLSCredsEndpoint endpoint,
 | 
				
			||||||
 | 
					                        Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QCryptoTLSSession *session;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    session = g_new0(QCryptoTLSSession, 1);
 | 
				
			||||||
 | 
					    trace_qcrypto_tls_session_new(
 | 
				
			||||||
 | 
					        session, creds, hostname ? hostname : "<none>",
 | 
				
			||||||
 | 
					        aclname ? aclname : "<none>", endpoint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (hostname) {
 | 
				
			||||||
 | 
					        session->hostname = g_strdup(hostname);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (aclname) {
 | 
				
			||||||
 | 
					        session->aclname = g_strdup(aclname);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    session->creds = creds;
 | 
				
			||||||
 | 
					    object_ref(OBJECT(creds));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (creds->endpoint != endpoint) {
 | 
				
			||||||
 | 
					        error_setg(errp, "Credentials endpoint doesn't match session");
 | 
				
			||||||
 | 
					        goto error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
 | 
				
			||||||
 | 
					        ret = gnutls_init(&session->handle, GNUTLS_SERVER);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        ret = gnutls_init(&session->handle, GNUTLS_CLIENT);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        error_setg(errp, "Cannot initialize TLS session: %s",
 | 
				
			||||||
 | 
					                   gnutls_strerror(ret));
 | 
				
			||||||
 | 
					        goto error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (object_dynamic_cast(OBJECT(creds),
 | 
				
			||||||
 | 
					                            TYPE_QCRYPTO_TLS_CREDS_ANON)) {
 | 
				
			||||||
 | 
					        QCryptoTLSCredsAnon *acreds = QCRYPTO_TLS_CREDS_ANON(creds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ret = gnutls_priority_set_direct(session->handle,
 | 
				
			||||||
 | 
					                                         "NORMAL:+ANON-DH", NULL);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Unable to set TLS session priority: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
 | 
				
			||||||
 | 
					            ret = gnutls_credentials_set(session->handle,
 | 
				
			||||||
 | 
					                                         GNUTLS_CRD_ANON,
 | 
				
			||||||
 | 
					                                         acreds->data.server);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ret = gnutls_credentials_set(session->handle,
 | 
				
			||||||
 | 
					                                         GNUTLS_CRD_ANON,
 | 
				
			||||||
 | 
					                                         acreds->data.client);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Cannot set session credentials: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (object_dynamic_cast(OBJECT(creds),
 | 
				
			||||||
 | 
					                                   TYPE_QCRYPTO_TLS_CREDS_X509)) {
 | 
				
			||||||
 | 
					        QCryptoTLSCredsX509 *tcreds = QCRYPTO_TLS_CREDS_X509(creds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ret = gnutls_set_default_priority(session->handle);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Cannot set default TLS session priority: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ret = gnutls_credentials_set(session->handle,
 | 
				
			||||||
 | 
					                                     GNUTLS_CRD_CERTIFICATE,
 | 
				
			||||||
 | 
					                                     tcreds->data);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Cannot set session credentials: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
 | 
				
			||||||
 | 
					            /* This requests, but does not enforce a client cert.
 | 
				
			||||||
 | 
					             * The cert checking code later does enforcement */
 | 
				
			||||||
 | 
					            gnutls_certificate_server_set_request(session->handle,
 | 
				
			||||||
 | 
					                                                  GNUTLS_CERT_REQUEST);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        error_setg(errp, "Unsupported TLS credentials type %s",
 | 
				
			||||||
 | 
					                   object_get_typename(OBJECT(creds)));
 | 
				
			||||||
 | 
					        goto error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gnutls_transport_set_ptr(session->handle, session);
 | 
				
			||||||
 | 
					    gnutls_transport_set_push_function(session->handle,
 | 
				
			||||||
 | 
					                                       qcrypto_tls_session_push);
 | 
				
			||||||
 | 
					    gnutls_transport_set_pull_function(session->handle,
 | 
				
			||||||
 | 
					                                       qcrypto_tls_session_pull);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return session;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 error:
 | 
				
			||||||
 | 
					    qcrypto_tls_session_free(session);
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					qcrypto_tls_session_check_certificate(QCryptoTLSSession *session,
 | 
				
			||||||
 | 
					                                      Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    unsigned int status;
 | 
				
			||||||
 | 
					    const gnutls_datum_t *certs;
 | 
				
			||||||
 | 
					    unsigned int nCerts, i;
 | 
				
			||||||
 | 
					    time_t now;
 | 
				
			||||||
 | 
					    gnutls_x509_crt_t cert = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    now = time(NULL);
 | 
				
			||||||
 | 
					    if (now == ((time_t)-1)) {
 | 
				
			||||||
 | 
					        error_setg_errno(errp, errno, "Cannot get current time");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = gnutls_certificate_verify_peers2(session->handle, &status);
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        error_setg(errp, "Verify failed: %s", gnutls_strerror(ret));
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (status != 0) {
 | 
				
			||||||
 | 
					        const char *reason = "Invalid certificate";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (status & GNUTLS_CERT_INVALID) {
 | 
				
			||||||
 | 
					            reason = "The certificate is not trusted";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
 | 
				
			||||||
 | 
					            reason = "The certificate hasn't got a known issuer";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (status & GNUTLS_CERT_REVOKED) {
 | 
				
			||||||
 | 
					            reason = "The certificate has been revoked";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
 | 
				
			||||||
 | 
					            reason = "The certificate uses an insecure algorithm";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        error_setg(errp, "%s", reason);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    certs = gnutls_certificate_get_peers(session->handle, &nCerts);
 | 
				
			||||||
 | 
					    if (!certs) {
 | 
				
			||||||
 | 
					        error_setg(errp, "No certificate peers");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < nCerts; i++) {
 | 
				
			||||||
 | 
					        ret = gnutls_x509_crt_init(&cert);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Cannot initialize certificate: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ret = gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Cannot import certificate: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (gnutls_x509_crt_get_expiration_time(cert) < now) {
 | 
				
			||||||
 | 
					            error_setg(errp, "The certificate has expired");
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (gnutls_x509_crt_get_activation_time(cert) > now) {
 | 
				
			||||||
 | 
					            error_setg(errp, "The certificate is not yet activated");
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (gnutls_x509_crt_get_activation_time(cert) > now) {
 | 
				
			||||||
 | 
					            error_setg(errp, "The certificate is not yet activated");
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (i == 0) {
 | 
				
			||||||
 | 
					            size_t dnameSize = 1024;
 | 
				
			||||||
 | 
					            session->peername = g_malloc(dnameSize);
 | 
				
			||||||
 | 
					        requery:
 | 
				
			||||||
 | 
					            ret = gnutls_x509_crt_get_dn(cert, session->peername, &dnameSize);
 | 
				
			||||||
 | 
					            if (ret < 0) {
 | 
				
			||||||
 | 
					                if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
 | 
				
			||||||
 | 
					                    session->peername = g_realloc(session->peername,
 | 
				
			||||||
 | 
					                                                  dnameSize);
 | 
				
			||||||
 | 
					                    goto requery;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                error_setg(errp, "Cannot get client distinguished name: %s",
 | 
				
			||||||
 | 
					                           gnutls_strerror(ret));
 | 
				
			||||||
 | 
					                goto error;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (session->aclname) {
 | 
				
			||||||
 | 
					                qemu_acl *acl = qemu_acl_find(session->aclname);
 | 
				
			||||||
 | 
					                int allow;
 | 
				
			||||||
 | 
					                if (!acl) {
 | 
				
			||||||
 | 
					                    error_setg(errp, "Cannot find ACL %s",
 | 
				
			||||||
 | 
					                               session->aclname);
 | 
				
			||||||
 | 
					                    goto error;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                allow = qemu_acl_party_is_allowed(acl, session->peername);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                error_setg(errp, "TLS x509 ACL check for %s is %s",
 | 
				
			||||||
 | 
					                           session->peername, allow ? "allowed" : "denied");
 | 
				
			||||||
 | 
					                if (!allow) {
 | 
				
			||||||
 | 
					                    goto error;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (session->hostname) {
 | 
				
			||||||
 | 
					                if (!gnutls_x509_crt_check_hostname(cert, session->hostname)) {
 | 
				
			||||||
 | 
					                    error_setg(errp,
 | 
				
			||||||
 | 
					                               "Certificate does not match the hostname %s",
 | 
				
			||||||
 | 
					                               session->hostname);
 | 
				
			||||||
 | 
					                    goto error;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gnutls_x509_crt_deinit(cert);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 error:
 | 
				
			||||||
 | 
					    gnutls_x509_crt_deinit(cert);
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					qcrypto_tls_session_check_credentials(QCryptoTLSSession *session,
 | 
				
			||||||
 | 
					                                      Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (object_dynamic_cast(OBJECT(session->creds),
 | 
				
			||||||
 | 
					                            TYPE_QCRYPTO_TLS_CREDS_ANON)) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    } else if (object_dynamic_cast(OBJECT(session->creds),
 | 
				
			||||||
 | 
					                            TYPE_QCRYPTO_TLS_CREDS_X509)) {
 | 
				
			||||||
 | 
					        if (session->creds->verifyPeer) {
 | 
				
			||||||
 | 
					            return qcrypto_tls_session_check_certificate(session,
 | 
				
			||||||
 | 
					                                                         errp);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        error_setg(errp, "Unexpected credential type %s",
 | 
				
			||||||
 | 
					                   object_get_typename(OBJECT(session->creds)));
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					qcrypto_tls_session_set_callbacks(QCryptoTLSSession *session,
 | 
				
			||||||
 | 
					                                  QCryptoTLSSessionWriteFunc writeFunc,
 | 
				
			||||||
 | 
					                                  QCryptoTLSSessionReadFunc readFunc,
 | 
				
			||||||
 | 
					                                  void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    session->writeFunc = writeFunc;
 | 
				
			||||||
 | 
					    session->readFunc = readFunc;
 | 
				
			||||||
 | 
					    session->opaque = opaque;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ssize_t
 | 
				
			||||||
 | 
					qcrypto_tls_session_write(QCryptoTLSSession *session,
 | 
				
			||||||
 | 
					                          const char *buf,
 | 
				
			||||||
 | 
					                          size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ssize_t ret = gnutls_record_send(session->handle, buf, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        switch (ret) {
 | 
				
			||||||
 | 
					        case GNUTLS_E_AGAIN:
 | 
				
			||||||
 | 
					            errno = EAGAIN;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case GNUTLS_E_INTERRUPTED:
 | 
				
			||||||
 | 
					            errno = EINTR;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            errno = EIO;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ret = -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ssize_t
 | 
				
			||||||
 | 
					qcrypto_tls_session_read(QCryptoTLSSession *session,
 | 
				
			||||||
 | 
					                         char *buf,
 | 
				
			||||||
 | 
					                         size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ssize_t ret = gnutls_record_recv(session->handle, buf, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        switch (ret) {
 | 
				
			||||||
 | 
					        case GNUTLS_E_AGAIN:
 | 
				
			||||||
 | 
					            errno = EAGAIN;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case GNUTLS_E_INTERRUPTED:
 | 
				
			||||||
 | 
					            errno = EINTR;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            errno = EIO;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ret = -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					qcrypto_tls_session_handshake(QCryptoTLSSession *session,
 | 
				
			||||||
 | 
					                              Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret = gnutls_handshake(session->handle);
 | 
				
			||||||
 | 
					    if (ret == 0) {
 | 
				
			||||||
 | 
					        session->handshakeComplete = true;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (ret == GNUTLS_E_INTERRUPTED ||
 | 
				
			||||||
 | 
					            ret == GNUTLS_E_AGAIN) {
 | 
				
			||||||
 | 
					            ret = 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            error_setg(errp, "TLS handshake failed: %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(ret));
 | 
				
			||||||
 | 
					            ret = -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QCryptoTLSSessionHandshakeStatus
 | 
				
			||||||
 | 
					qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *session)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (session->handshakeComplete) {
 | 
				
			||||||
 | 
					        return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
 | 
				
			||||||
 | 
					    } else if (gnutls_record_get_direction(session->handle) == 0) {
 | 
				
			||||||
 | 
					        return QCRYPTO_TLS_HANDSHAKE_RECVING;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return QCRYPTO_TLS_HANDSHAKE_SENDING;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					qcrypto_tls_session_get_key_size(QCryptoTLSSession *session,
 | 
				
			||||||
 | 
					                                 Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gnutls_cipher_algorithm_t cipher;
 | 
				
			||||||
 | 
					    int ssf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cipher = gnutls_cipher_get(session->handle);
 | 
				
			||||||
 | 
					    ssf = gnutls_cipher_get_key_size(cipher);
 | 
				
			||||||
 | 
					    if (!ssf) {
 | 
				
			||||||
 | 
					        error_setg(errp, "Cannot get TLS cipher key size");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ssf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					qcrypto_tls_session_get_peer_name(QCryptoTLSSession *session)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (session->peername) {
 | 
				
			||||||
 | 
					        return g_strdup(session->peername);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else /* ! CONFIG_GNUTLS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QCryptoTLSSession *
 | 
				
			||||||
 | 
					qcrypto_tls_session_new(QCryptoTLSCreds *creds G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					                        const char *hostname G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					                        const char *aclname G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					                        QCryptoTLSCredsEndpoint endpoint G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					                        Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    error_setg(errp, "TLS requires GNUTLS support");
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					qcrypto_tls_session_free(QCryptoTLSSession *sess G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					                                      Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    error_setg(errp, "TLS requires GNUTLS support");
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					qcrypto_tls_session_set_callbacks(
 | 
				
			||||||
 | 
					    QCryptoTLSSession *sess G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					    QCryptoTLSSessionWriteFunc writeFunc G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					    QCryptoTLSSessionReadFunc readFunc G_GNUC_UNUSED,
 | 
				
			||||||
 | 
					    void *opaque G_GNUC_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ssize_t
 | 
				
			||||||
 | 
					qcrypto_tls_session_write(QCryptoTLSSession *sess,
 | 
				
			||||||
 | 
					                          const char *buf,
 | 
				
			||||||
 | 
					                          size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    errno = -EIO;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ssize_t
 | 
				
			||||||
 | 
					qcrypto_tls_session_read(QCryptoTLSSession *sess,
 | 
				
			||||||
 | 
					                         char *buf,
 | 
				
			||||||
 | 
					                         size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    errno = -EIO;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					qcrypto_tls_session_handshake(QCryptoTLSSession *sess,
 | 
				
			||||||
 | 
					                              Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    error_setg(errp, "TLS requires GNUTLS support");
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QCryptoTLSSessionHandshakeStatus
 | 
				
			||||||
 | 
					qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess,
 | 
				
			||||||
 | 
					                                 Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    error_setg(errp, "TLS requires GNUTLS support");
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					qcrypto_tls_session_get_peer_name(QCryptoTLSSession *sess)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@ -236,6 +236,7 @@ both fields like this:
 | 
				
			|||||||
=== Enumeration types ===
 | 
					=== Enumeration types ===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Usage: { 'enum': STRING, 'data': ARRAY-OF-STRING }
 | 
					Usage: { 'enum': STRING, 'data': ARRAY-OF-STRING }
 | 
				
			||||||
 | 
					       { 'enum': STRING, '*prefix': STRING, 'data': ARRAY-OF-STRING }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
An enumeration type is a dictionary containing a single 'data' key
 | 
					An enumeration type is a dictionary containing a single 'data' key
 | 
				
			||||||
whose value is a list of strings.  An example enumeration is:
 | 
					whose value is a list of strings.  An example enumeration is:
 | 
				
			||||||
@ -247,6 +248,13 @@ useful.  The list of strings should be lower case; if an enum name
 | 
				
			|||||||
represents multiple words, use '-' between words.  The string 'max' is
 | 
					represents multiple words, use '-' between words.  The string 'max' is
 | 
				
			||||||
not allowed as an enum value, and values should not be repeated.
 | 
					not allowed as an enum value, and values should not be repeated.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The enum constants will be named by using a heuristic to turn the
 | 
				
			||||||
 | 
					type name into a set of underscore separated words. For the example
 | 
				
			||||||
 | 
					above, 'MyEnum' will turn into 'MY_ENUM' giving a constant name
 | 
				
			||||||
 | 
					of 'MY_ENUM_VALUE1' for the first value. If the default heuristic
 | 
				
			||||||
 | 
					does not result in a desirable name, the optional 'prefix' field
 | 
				
			||||||
 | 
					can be used when defining the enum.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The enumeration values are passed as strings over the Client JSON
 | 
					The enumeration values are passed as strings over the Client JSON
 | 
				
			||||||
Protocol, but are encoded as C enum integral values in generated code.
 | 
					Protocol, but are encoded as C enum integral values in generated code.
 | 
				
			||||||
While the C code starts numbering at 0, it is better to use explicit
 | 
					While the C code starts numbering at 0, it is better to use explicit
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										68
									
								
								include/crypto/tlscreds.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								include/crypto/tlscreds.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU crypto TLS credential support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef QCRYPTO_TLSCRED_H__
 | 
				
			||||||
 | 
					#define QCRYPTO_TLSCRED_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu-common.h"
 | 
				
			||||||
 | 
					#include "qapi/error.h"
 | 
				
			||||||
 | 
					#include "qom/object.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					#include <gnutls/gnutls.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TYPE_QCRYPTO_TLS_CREDS "tls-creds"
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_CREDS(obj)                  \
 | 
				
			||||||
 | 
					    OBJECT_CHECK(QCryptoTLSCreds, (obj), TYPE_QCRYPTO_TLS_CREDS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct QCryptoTLSCreds QCryptoTLSCreds;
 | 
				
			||||||
 | 
					typedef struct QCryptoTLSCredsClass QCryptoTLSCredsClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_CREDS_DH_PARAMS "dh-params.pem"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * QCryptoTLSCreds:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The QCryptoTLSCreds object is an abstract base for different
 | 
				
			||||||
 | 
					 * types of TLS handshake credentials. Most commonly the
 | 
				
			||||||
 | 
					 * QCryptoTLSCredsX509 subclass will be used to provide x509
 | 
				
			||||||
 | 
					 * certificate credentials.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct QCryptoTLSCreds {
 | 
				
			||||||
 | 
					    Object parent_obj;
 | 
				
			||||||
 | 
					    char *dir;
 | 
				
			||||||
 | 
					    QCryptoTLSCredsEndpoint endpoint;
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					    gnutls_dh_params_t dh_params;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    bool verifyPeer;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct QCryptoTLSCredsClass {
 | 
				
			||||||
 | 
					    ObjectClass parent_class;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* QCRYPTO_TLSCRED_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										112
									
								
								include/crypto/tlscredsanon.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								include/crypto/tlscredsanon.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU crypto TLS anonymous credential support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef QCRYPTO_TLSCRED_ANON_H__
 | 
				
			||||||
 | 
					#define QCRYPTO_TLSCRED_ANON_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto/tlscreds.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TYPE_QCRYPTO_TLS_CREDS_ANON "tls-creds-anon"
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_CREDS_ANON(obj)                  \
 | 
				
			||||||
 | 
					    OBJECT_CHECK(QCryptoTLSCredsAnon, (obj), TYPE_QCRYPTO_TLS_CREDS_ANON)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct QCryptoTLSCredsAnon QCryptoTLSCredsAnon;
 | 
				
			||||||
 | 
					typedef struct QCryptoTLSCredsAnonClass QCryptoTLSCredsAnonClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * QCryptoTLSCredsAnon:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The QCryptoTLSCredsAnon object provides a representation
 | 
				
			||||||
 | 
					 * of anonymous credentials used perform a TLS handshake.
 | 
				
			||||||
 | 
					 * This is primarily provided for backwards compatibility and
 | 
				
			||||||
 | 
					 * its use is discouraged as it has poor security characteristics
 | 
				
			||||||
 | 
					 * due to lacking MITM attack protection amongst other problems.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is a user creatable object, which can be instantiated
 | 
				
			||||||
 | 
					 * via object_new_propv():
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <example>
 | 
				
			||||||
 | 
					 *   <title>Creating anonymous TLS credential objects in code</title>
 | 
				
			||||||
 | 
					 *   <programlisting>
 | 
				
			||||||
 | 
					 *   Object *obj;
 | 
				
			||||||
 | 
					 *   Error *err = NULL;
 | 
				
			||||||
 | 
					 *   obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_ANON,
 | 
				
			||||||
 | 
					 *                          "tlscreds0",
 | 
				
			||||||
 | 
					 *                          &err,
 | 
				
			||||||
 | 
					 *                          "endpoint", "server",
 | 
				
			||||||
 | 
					 *                          "dir", "/path/x509/cert/dir",
 | 
				
			||||||
 | 
					 *                          "verify-peer", "yes",
 | 
				
			||||||
 | 
					 *                          NULL);
 | 
				
			||||||
 | 
					 *   </programlisting>
 | 
				
			||||||
 | 
					 * </example>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Or via QMP:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <example>
 | 
				
			||||||
 | 
					 *   <title>Creating anonymous TLS credential objects via QMP</title>
 | 
				
			||||||
 | 
					 *   <programlisting>
 | 
				
			||||||
 | 
					 *    {
 | 
				
			||||||
 | 
					 *       "execute": "object-add", "arguments": {
 | 
				
			||||||
 | 
					 *          "id": "tlscreds0",
 | 
				
			||||||
 | 
					 *          "qom-type": "tls-creds-anon",
 | 
				
			||||||
 | 
					 *          "props": {
 | 
				
			||||||
 | 
					 *             "endpoint": "server",
 | 
				
			||||||
 | 
					 *             "dir": "/path/to/x509/cert/dir",
 | 
				
			||||||
 | 
					 *             "verify-peer": false
 | 
				
			||||||
 | 
					 *          }
 | 
				
			||||||
 | 
					 *       }
 | 
				
			||||||
 | 
					 *    }
 | 
				
			||||||
 | 
					 *   </programlisting>
 | 
				
			||||||
 | 
					 * </example>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Or via the CLI:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <example>
 | 
				
			||||||
 | 
					 *   <title>Creating anonymous TLS credential objects via CLI</title>
 | 
				
			||||||
 | 
					 *   <programlisting>
 | 
				
			||||||
 | 
					 *  qemu-system-x86_64 -object tls-creds-anon,id=tlscreds0,\
 | 
				
			||||||
 | 
					 *          endpoint=server,verify-peer=off,\
 | 
				
			||||||
 | 
					 *          dir=/path/to/x509/certdir/
 | 
				
			||||||
 | 
					 *   </programlisting>
 | 
				
			||||||
 | 
					 * </example>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct QCryptoTLSCredsAnon {
 | 
				
			||||||
 | 
					    QCryptoTLSCreds parent_obj;
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
					        gnutls_anon_server_credentials_t server;
 | 
				
			||||||
 | 
					        gnutls_anon_client_credentials_t client;
 | 
				
			||||||
 | 
					    } data;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct QCryptoTLSCredsAnonClass {
 | 
				
			||||||
 | 
					    QCryptoTLSCredsClass parent_class;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* QCRYPTO_TLSCRED_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										113
									
								
								include/crypto/tlscredsx509.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								include/crypto/tlscredsx509.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU crypto TLS x509 credential support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef QCRYPTO_TLSCRED_X509_H__
 | 
				
			||||||
 | 
					#define QCRYPTO_TLSCRED_X509_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto/tlscreds.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TYPE_QCRYPTO_TLS_CREDS_X509 "tls-creds-x509"
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_CREDS_X509(obj)                  \
 | 
				
			||||||
 | 
					    OBJECT_CHECK(QCryptoTLSCredsX509, (obj), TYPE_QCRYPTO_TLS_CREDS_X509)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct QCryptoTLSCredsX509 QCryptoTLSCredsX509;
 | 
				
			||||||
 | 
					typedef struct QCryptoTLSCredsX509Class QCryptoTLSCredsX509Class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_CREDS_X509_CA_CERT "ca-cert.pem"
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_CREDS_X509_CA_CRL "ca-crl.pem"
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_CREDS_X509_SERVER_KEY "server-key.pem"
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_CREDS_X509_SERVER_CERT "server-cert.pem"
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_CREDS_X509_CLIENT_KEY "client-key.pem"
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_CREDS_X509_CLIENT_CERT "client-cert.pem"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * QCryptoTLSCredsX509:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The QCryptoTLSCredsX509 object provides a representation
 | 
				
			||||||
 | 
					 * of x509 credentials used to perform a TLS handshake.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is a user creatable object, which can be instantiated
 | 
				
			||||||
 | 
					 * via object_new_propv():
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <example>
 | 
				
			||||||
 | 
					 *   <title>Creating x509 TLS credential objects in code</title>
 | 
				
			||||||
 | 
					 *   <programlisting>
 | 
				
			||||||
 | 
					 *   Object *obj;
 | 
				
			||||||
 | 
					 *   Error *err = NULL;
 | 
				
			||||||
 | 
					 *   obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_X509,
 | 
				
			||||||
 | 
					 *                          "tlscreds0",
 | 
				
			||||||
 | 
					 *                          &err,
 | 
				
			||||||
 | 
					 *                          "endpoint", "server",
 | 
				
			||||||
 | 
					 *                          "dir", "/path/x509/cert/dir",
 | 
				
			||||||
 | 
					 *                          "verify-peer", "yes",
 | 
				
			||||||
 | 
					 *                          NULL);
 | 
				
			||||||
 | 
					 *   </programlisting>
 | 
				
			||||||
 | 
					 * </example>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Or via QMP:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <example>
 | 
				
			||||||
 | 
					 *   <title>Creating x509 TLS credential objects via QMP</title>
 | 
				
			||||||
 | 
					 *   <programlisting>
 | 
				
			||||||
 | 
					 *    {
 | 
				
			||||||
 | 
					 *       "execute": "object-add", "arguments": {
 | 
				
			||||||
 | 
					 *          "id": "tlscreds0",
 | 
				
			||||||
 | 
					 *          "qom-type": "tls-creds-x509",
 | 
				
			||||||
 | 
					 *          "props": {
 | 
				
			||||||
 | 
					 *             "endpoint": "server",
 | 
				
			||||||
 | 
					 *             "dir": "/path/to/x509/cert/dir",
 | 
				
			||||||
 | 
					 *             "verify-peer": false
 | 
				
			||||||
 | 
					 *          }
 | 
				
			||||||
 | 
					 *       }
 | 
				
			||||||
 | 
					 *    }
 | 
				
			||||||
 | 
					 *   </programlisting>
 | 
				
			||||||
 | 
					 * </example>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Or via the CLI:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <example>
 | 
				
			||||||
 | 
					 *   <title>Creating x509 TLS credential objects via CLI</title>
 | 
				
			||||||
 | 
					 *   <programlisting>
 | 
				
			||||||
 | 
					 *  qemu-system-x86_64 -object tls-creds-x509,id=tlscreds0,\
 | 
				
			||||||
 | 
					 *          endpoint=server,verify-peer=off,\
 | 
				
			||||||
 | 
					 *          dir=/path/to/x509/certdir/
 | 
				
			||||||
 | 
					 *   </programlisting>
 | 
				
			||||||
 | 
					 * </example>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct QCryptoTLSCredsX509 {
 | 
				
			||||||
 | 
					    QCryptoTLSCreds parent_obj;
 | 
				
			||||||
 | 
					#ifdef CONFIG_GNUTLS
 | 
				
			||||||
 | 
					    gnutls_certificate_credentials_t data;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    bool sanityCheck;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct QCryptoTLSCredsX509Class {
 | 
				
			||||||
 | 
					    QCryptoTLSCredsClass parent_class;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* QCRYPTO_TLSCRED_X509_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										322
									
								
								include/crypto/tlssession.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								include/crypto/tlssession.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,322 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU crypto TLS session support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef QCRYPTO_TLS_SESSION_H__
 | 
				
			||||||
 | 
					#define QCRYPTO_TLS_SESSION_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto/tlscreds.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * QCryptoTLSSession:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The QCryptoTLSSession object encapsulates the
 | 
				
			||||||
 | 
					 * logic to integrate with a TLS providing library such
 | 
				
			||||||
 | 
					 * as GNUTLS, to setup and run TLS sessions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The API is designed such that it has no assumption about
 | 
				
			||||||
 | 
					 * the type of transport it is running over. It may be a
 | 
				
			||||||
 | 
					 * traditional TCP socket, or something else entirely. The
 | 
				
			||||||
 | 
					 * only requirement is a full-duplex stream of some kind.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <example>
 | 
				
			||||||
 | 
					 *   <title>Using TLS session objects</title>
 | 
				
			||||||
 | 
					 *   <programlisting>
 | 
				
			||||||
 | 
					 * static ssize_t mysock_send(const char *buf, size_t len,
 | 
				
			||||||
 | 
					 *                            void *opaque)
 | 
				
			||||||
 | 
					 * {
 | 
				
			||||||
 | 
					 *    int fd = GPOINTER_TO_INT(opaque);
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    return write(*fd, buf, len);
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * static ssize_t mysock_recv(const char *buf, size_t len,
 | 
				
			||||||
 | 
					 *                            void *opaque)
 | 
				
			||||||
 | 
					 * {
 | 
				
			||||||
 | 
					 *    int fd = GPOINTER_TO_INT(opaque);
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    return read(*fd, buf, len);
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * static int mysock_run_tls(int sockfd,
 | 
				
			||||||
 | 
					 *                           QCryptoTLSCreds *creds,
 | 
				
			||||||
 | 
					 *                           Error *erp)
 | 
				
			||||||
 | 
					 * {
 | 
				
			||||||
 | 
					 *    QCryptoTLSSession *sess;
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    sess = qcrypto_tls_session_new(creds,
 | 
				
			||||||
 | 
					 *                                   "vnc.example.com",
 | 
				
			||||||
 | 
					 *                                   NULL,
 | 
				
			||||||
 | 
					 *                                   QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
 | 
				
			||||||
 | 
					 *                                   errp);
 | 
				
			||||||
 | 
					 *    if (sess == NULL) {
 | 
				
			||||||
 | 
					 *       return -1;
 | 
				
			||||||
 | 
					 *    }
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    qcrypto_tls_session_set_callbacks(sess,
 | 
				
			||||||
 | 
					 *                                      mysock_send,
 | 
				
			||||||
 | 
					 *                                      mysock_recv
 | 
				
			||||||
 | 
					 *                                      GINT_TO_POINTER(fd));
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    while (1) {
 | 
				
			||||||
 | 
					 *       if (qcrypto_tls_session_handshake(sess, errp) < 0) {
 | 
				
			||||||
 | 
					 *           qcrypto_tls_session_free(sess);
 | 
				
			||||||
 | 
					 *           return -1;
 | 
				
			||||||
 | 
					 *       }
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *       switch(qcrypto_tls_session_get_handshake_status(sess)) {
 | 
				
			||||||
 | 
					 *       case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
 | 
				
			||||||
 | 
					 *           if (qcrypto_tls_session_check_credentials(sess, errp) < )) {
 | 
				
			||||||
 | 
					 *               qcrypto_tls_session_free(sess);
 | 
				
			||||||
 | 
					 *               return -1;
 | 
				
			||||||
 | 
					 *           }
 | 
				
			||||||
 | 
					 *           goto done;
 | 
				
			||||||
 | 
					 *       case QCRYPTO_TLS_HANDSHAKE_RECVING:
 | 
				
			||||||
 | 
					 *           ...wait for GIO_IN event on fd...
 | 
				
			||||||
 | 
					 *           break;
 | 
				
			||||||
 | 
					 *       case QCRYPTO_TLS_HANDSHAKE_SENDING:
 | 
				
			||||||
 | 
					 *           ...wait for GIO_OUT event on fd...
 | 
				
			||||||
 | 
					 *           break;
 | 
				
			||||||
 | 
					 *       }
 | 
				
			||||||
 | 
					 *    }
 | 
				
			||||||
 | 
					 *   done:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    ....send/recv payload data on sess...
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    qcrypto_tls_session_free(sess):
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 *   </programlisting>
 | 
				
			||||||
 | 
					 * </example>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct QCryptoTLSSession QCryptoTLSSession;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_new:
 | 
				
			||||||
 | 
					 * @creds: pointer to a TLS credentials object
 | 
				
			||||||
 | 
					 * @hostname: optional hostname to validate
 | 
				
			||||||
 | 
					 * @aclname: optional ACL to validate peer credentials against
 | 
				
			||||||
 | 
					 * @endpoint: role of the TLS session, client or server
 | 
				
			||||||
 | 
					 * @errp: pointer to an uninitialized error object
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Create a new TLS session object that will be used to
 | 
				
			||||||
 | 
					 * negotiate a TLS session over an arbitrary data channel.
 | 
				
			||||||
 | 
					 * The session object can operate as either the server or
 | 
				
			||||||
 | 
					 * client, according to the value of the @endpoint argument.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For clients, the @hostname parameter should hold the full
 | 
				
			||||||
 | 
					 * unmodified hostname as requested by the user. This will
 | 
				
			||||||
 | 
					 * be used to verify the against the hostname reported in
 | 
				
			||||||
 | 
					 * the server's credentials (aka x509 certificate).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The @aclname parameter (optionally) specifies the name
 | 
				
			||||||
 | 
					 * of an access control list that will be used to validate
 | 
				
			||||||
 | 
					 * the peer's credentials. For x509 credentials, the ACL
 | 
				
			||||||
 | 
					 * will be matched against the CommonName shown in the peer's
 | 
				
			||||||
 | 
					 * certificate. If the session is acting as a server, setting
 | 
				
			||||||
 | 
					 * an ACL will require that the client provide a validate
 | 
				
			||||||
 | 
					 * x509 client certificate.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * After creating the session object, the I/O callbacks
 | 
				
			||||||
 | 
					 * must be set using the qcrypto_tls_session_set_callbacks()
 | 
				
			||||||
 | 
					 * method. A TLS handshake sequence must then be completed
 | 
				
			||||||
 | 
					 * using qcrypto_tls_session_handshake(), before payload
 | 
				
			||||||
 | 
					 * data is permitted to be sent/received.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The session object must be released by calling
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_free() when no longer required
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: a TLS session object, or NULL on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					QCryptoTLSSession *qcrypto_tls_session_new(QCryptoTLSCreds *creds,
 | 
				
			||||||
 | 
					                                           const char *hostname,
 | 
				
			||||||
 | 
					                                           const char *aclname,
 | 
				
			||||||
 | 
					                                           QCryptoTLSCredsEndpoint endpoint,
 | 
				
			||||||
 | 
					                                           Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_free:
 | 
				
			||||||
 | 
					 * @sess: the TLS session object
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Release all memory associated with the TLS session
 | 
				
			||||||
 | 
					 * object previously allocated by qcrypto_tls_session_new()
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void qcrypto_tls_session_free(QCryptoTLSSession *sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_check_credentials:
 | 
				
			||||||
 | 
					 * @sess: the TLS session object
 | 
				
			||||||
 | 
					 * @errp: pointer to an uninitialized error object
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Validate the peer's credentials after a successful
 | 
				
			||||||
 | 
					 * TLS handshake. It is an error to call this before
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_get_handshake_status() returns
 | 
				
			||||||
 | 
					 * QCRYPTO_TLS_HANDSHAKE_COMPLETE
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 if the credentials validated, -1 on error
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess,
 | 
				
			||||||
 | 
					                                          Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const char *buf,
 | 
				
			||||||
 | 
					                                              size_t len,
 | 
				
			||||||
 | 
					                                              void *opaque);
 | 
				
			||||||
 | 
					typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf,
 | 
				
			||||||
 | 
					                                             size_t len,
 | 
				
			||||||
 | 
					                                             void *opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_set_callbacks:
 | 
				
			||||||
 | 
					 * @sess: the TLS session object
 | 
				
			||||||
 | 
					 * @writeFunc: callback for sending data
 | 
				
			||||||
 | 
					 * @readFunc: callback to receiving data
 | 
				
			||||||
 | 
					 * @opaque: data to pass to callbacks
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Sets the callback functions that are to be used for sending
 | 
				
			||||||
 | 
					 * and receiving data on the underlying data channel. Typically
 | 
				
			||||||
 | 
					 * the callbacks to write/read to/from a TCP socket, but there
 | 
				
			||||||
 | 
					 * is no assumption made about the type of channel used.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The @writeFunc callback will be passed the encrypted
 | 
				
			||||||
 | 
					 * data to send to the remote peer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The @readFunc callback will be passed a pointer to fill
 | 
				
			||||||
 | 
					 * with encrypted data received from the remote peer
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
 | 
				
			||||||
 | 
					                                       QCryptoTLSSessionWriteFunc writeFunc,
 | 
				
			||||||
 | 
					                                       QCryptoTLSSessionReadFunc readFunc,
 | 
				
			||||||
 | 
					                                       void *opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_write:
 | 
				
			||||||
 | 
					 * @sess: the TLS session object
 | 
				
			||||||
 | 
					 * @buf: the plain text to send
 | 
				
			||||||
 | 
					 * @len: the length of @buf
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Encrypt @len bytes of the data in @buf and send
 | 
				
			||||||
 | 
					 * it to the remote peer using the callback previously
 | 
				
			||||||
 | 
					 * registered with qcrypto_tls_session_set_callbacks()
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It is an error to call this before
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_get_handshake_status() returns
 | 
				
			||||||
 | 
					 * QCRYPTO_TLS_HANDSHAKE_COMPLETE
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: the number of bytes sent, or -1 on error
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess,
 | 
				
			||||||
 | 
					                                  const char *buf,
 | 
				
			||||||
 | 
					                                  size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_read:
 | 
				
			||||||
 | 
					 * @sess: the TLS session object
 | 
				
			||||||
 | 
					 * @buf: to fill with plain text received
 | 
				
			||||||
 | 
					 * @len: the length of @buf
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Receive up to @len bytes of data from the remote peer
 | 
				
			||||||
 | 
					 * using the callback previously registered with
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_set_callbacks(), decrypt it and
 | 
				
			||||||
 | 
					 * store it in @buf.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It is an error to call this before
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_get_handshake_status() returns
 | 
				
			||||||
 | 
					 * QCRYPTO_TLS_HANDSHAKE_COMPLETE
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: the number of bytes received, or -1 on error
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess,
 | 
				
			||||||
 | 
					                                 char *buf,
 | 
				
			||||||
 | 
					                                 size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_handshake:
 | 
				
			||||||
 | 
					 * @sess: the TLS session object
 | 
				
			||||||
 | 
					 * @errp: pointer to an uninitialized error object
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Start, or continue, a TLS handshake sequence. If
 | 
				
			||||||
 | 
					 * the underlying data channel is non-blocking, then
 | 
				
			||||||
 | 
					 * this method may return control before the handshake
 | 
				
			||||||
 | 
					 * is complete. On non-blocking channels the
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_get_handshake_status() method
 | 
				
			||||||
 | 
					 * should be used to determine whether the handshake
 | 
				
			||||||
 | 
					 * has completed, or is waiting to send or receive
 | 
				
			||||||
 | 
					 * data. In the latter cases, the caller should setup
 | 
				
			||||||
 | 
					 * an event loop watch and call this method again
 | 
				
			||||||
 | 
					 * once the underlying data channel is ready to read
 | 
				
			||||||
 | 
					 * or write again
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int qcrypto_tls_session_handshake(QCryptoTLSSession *sess,
 | 
				
			||||||
 | 
					                                  Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    QCRYPTO_TLS_HANDSHAKE_COMPLETE,
 | 
				
			||||||
 | 
					    QCRYPTO_TLS_HANDSHAKE_SENDING,
 | 
				
			||||||
 | 
					    QCRYPTO_TLS_HANDSHAKE_RECVING,
 | 
				
			||||||
 | 
					} QCryptoTLSSessionHandshakeStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_get_handshake_status:
 | 
				
			||||||
 | 
					 * @sess: the TLS session object
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Check the status of the TLS handshake. This
 | 
				
			||||||
 | 
					 * is used with non-blocking data channels to
 | 
				
			||||||
 | 
					 * determine whether the handshake is waiting
 | 
				
			||||||
 | 
					 * to send or receive further data to/from the
 | 
				
			||||||
 | 
					 * remote peer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Once this returns QCRYPTO_TLS_HANDSHAKE_COMPLETE
 | 
				
			||||||
 | 
					 * it is permitted to send/receive payload data on
 | 
				
			||||||
 | 
					 * the channel
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					QCryptoTLSSessionHandshakeStatus
 | 
				
			||||||
 | 
					qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_get_key_size:
 | 
				
			||||||
 | 
					 * @sess: the TLS session object
 | 
				
			||||||
 | 
					 * @errp: pointer to an uninitialized error object
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Check the size of the data channel encryption key
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: the length in bytes of the encryption key
 | 
				
			||||||
 | 
					 * or -1 on error
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess,
 | 
				
			||||||
 | 
					                                     Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qcrypto_tls_session_get_peer_name:
 | 
				
			||||||
 | 
					 * @sess: the TLS session object
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Get the identified name of the remote peer. If the
 | 
				
			||||||
 | 
					 * TLS session was negotiated using x509 certificate
 | 
				
			||||||
 | 
					 * credentials, this will return the CommonName from
 | 
				
			||||||
 | 
					 * the peer's certificate. If no identified name is
 | 
				
			||||||
 | 
					 * available it will return NULL.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The returned data must be released with g_free()
 | 
				
			||||||
 | 
					 * when no longer required.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: the peer's name or NULL.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char *qcrypto_tls_session_get_peer_name(QCryptoTLSSession *sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* QCRYPTO_TLS_SESSION_H__ */
 | 
				
			||||||
@ -5,6 +5,9 @@
 | 
				
			|||||||
# QAPI common definitions
 | 
					# QAPI common definitions
 | 
				
			||||||
{ 'include': 'qapi/common.json' }
 | 
					{ 'include': 'qapi/common.json' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# QAPI crypto definitions
 | 
				
			||||||
 | 
					{ 'include': 'qapi/crypto.json' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# QAPI block definitions
 | 
					# QAPI block definitions
 | 
				
			||||||
{ 'include': 'qapi/block.json' }
 | 
					{ 'include': 'qapi/block.json' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										21
									
								
								qapi/crypto.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								qapi/crypto.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					# -*- Mode: Python -*-
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# QAPI crypto definitions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##
 | 
				
			||||||
 | 
					# QCryptoTLSCredsEndpoint:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The type of network endpoint that will be using the credentials.
 | 
				
			||||||
 | 
					# Most types of credential require different setup / structures
 | 
				
			||||||
 | 
					# depending on whether they will be used in a server versus a
 | 
				
			||||||
 | 
					# client.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# @client: the network endpoint is acting as the client
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# @server: the network endpoint is acting as the server
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Since: 2.5
 | 
				
			||||||
 | 
					##
 | 
				
			||||||
 | 
					{ 'enum': 'QCryptoTLSCredsEndpoint',
 | 
				
			||||||
 | 
					  'prefix': 'QCRYPTO_TLS_CREDS_ENDPOINT',
 | 
				
			||||||
 | 
					  'data': ['client', 'server']}
 | 
				
			||||||
@ -1217,8 +1217,9 @@ By definition the Websocket port is 5700+@var{display}. If @var{host} is
 | 
				
			|||||||
specified connections will only be allowed from this host.
 | 
					specified connections will only be allowed from this host.
 | 
				
			||||||
As an alternative the Websocket port could be specified by using
 | 
					As an alternative the Websocket port could be specified by using
 | 
				
			||||||
@code{websocket}=@var{port}.
 | 
					@code{websocket}=@var{port}.
 | 
				
			||||||
TLS encryption for the Websocket connection is supported if the required
 | 
					If no TLS credentials are provided, the websocket connection runs in
 | 
				
			||||||
certificates are specified with the VNC option @option{x509}.
 | 
					unencrypted mode. If TLS credentials are provided, the websocket connection
 | 
				
			||||||
 | 
					requires encrypted client connections.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item password
 | 
					@item password
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1239,6 +1240,20 @@ date and time).
 | 
				
			|||||||
You can also use keywords "now" or "never" for the expiration time to
 | 
					You can also use keywords "now" or "never" for the expiration time to
 | 
				
			||||||
allow <protocol> password to expire immediately or never expire.
 | 
					allow <protocol> password to expire immediately or never expire.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item tls-creds=@var{ID}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Provides the ID of a set of TLS credentials to use to secure the
 | 
				
			||||||
 | 
					VNC server. They will apply to both the normal VNC server socket
 | 
				
			||||||
 | 
					and the websocket socket (if enabled). Setting TLS credentials
 | 
				
			||||||
 | 
					will cause the VNC server socket to enable the VeNCrypt auth
 | 
				
			||||||
 | 
					mechanism.  The credentials should have been previously created
 | 
				
			||||||
 | 
					using the @option{-object tls-creds} argument.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The @option{tls-creds} parameter obsoletes the @option{tls},
 | 
				
			||||||
 | 
					@option{x509}, and @option{x509verify} options, and as such
 | 
				
			||||||
 | 
					it is not permitted to set both new and old type options at
 | 
				
			||||||
 | 
					the same time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item tls
 | 
					@item tls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Require that client use TLS when communicating with the VNC server. This
 | 
					Require that client use TLS when communicating with the VNC server. This
 | 
				
			||||||
@ -1246,6 +1261,9 @@ uses anonymous TLS credentials so is susceptible to a man-in-the-middle
 | 
				
			|||||||
attack. It is recommended that this option be combined with either the
 | 
					attack. It is recommended that this option be combined with either the
 | 
				
			||||||
@option{x509} or @option{x509verify} options.
 | 
					@option{x509} or @option{x509verify} options.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This option is now deprecated in favor of using the @option{tls-creds}
 | 
				
			||||||
 | 
					argument.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item x509=@var{/path/to/certificate/dir}
 | 
					@item x509=@var{/path/to/certificate/dir}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Valid if @option{tls} is specified. Require that x509 credentials are used
 | 
					Valid if @option{tls} is specified. Require that x509 credentials are used
 | 
				
			||||||
@ -1255,6 +1273,9 @@ to provide authentication of the client when this is used. The path following
 | 
				
			|||||||
this option specifies where the x509 certificates are to be loaded from.
 | 
					this option specifies where the x509 certificates are to be loaded from.
 | 
				
			||||||
See the @ref{vnc_security} section for details on generating certificates.
 | 
					See the @ref{vnc_security} section for details on generating certificates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This option is now deprecated in favour of using the @option{tls-creds}
 | 
				
			||||||
 | 
					argument.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item x509verify=@var{/path/to/certificate/dir}
 | 
					@item x509verify=@var{/path/to/certificate/dir}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Valid if @option{tls} is specified. Require that x509 credentials are used
 | 
					Valid if @option{tls} is specified. Require that x509 credentials are used
 | 
				
			||||||
@ -1268,6 +1289,9 @@ path following this option specifies where the x509 certificates are to
 | 
				
			|||||||
be loaded from. See the @ref{vnc_security} section for details on generating
 | 
					be loaded from. See the @ref{vnc_security} section for details on generating
 | 
				
			||||||
certificates.
 | 
					certificates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This option is now deprecated in favour of using the @option{tls-creds}
 | 
				
			||||||
 | 
					argument.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item sasl
 | 
					@item sasl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Require that the client use SASL to authenticate with the VNC server.
 | 
					Require that the client use SASL to authenticate with the VNC server.
 | 
				
			||||||
@ -3571,6 +3595,53 @@ the @option{virtio-rng} device. The @option{chardev} parameter is
 | 
				
			|||||||
the unique ID of a character device backend that provides the connection
 | 
					the unique ID of a character device backend that provides the connection
 | 
				
			||||||
to the RNG daemon.
 | 
					to the RNG daemon.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item -object tls-creds-anon,id=@var{id},endpoint=@var{endpoint},dir=@var{/path/to/cred/dir},verify-peer=@var{on|off}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Creates a TLS anonymous credentials object, which can be used to provide
 | 
				
			||||||
 | 
					TLS support on network backends. The @option{id} parameter is a unique
 | 
				
			||||||
 | 
					ID which network backends will use to access the credentials. The
 | 
				
			||||||
 | 
					@option{endpoint} is either @option{server} or @option{client} depending
 | 
				
			||||||
 | 
					on whether the QEMU network backend that uses the credentials will be
 | 
				
			||||||
 | 
					acting as a client or as a server. If @option{verify-peer} is enabled
 | 
				
			||||||
 | 
					(the default) then once the handshake is completed, the peer credentials
 | 
				
			||||||
 | 
					will be verified, though this is a no-op for anonymous credentials.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The @var{dir} parameter tells QEMU where to find the credential
 | 
				
			||||||
 | 
					files. For server endpoints, this directory may contain a file
 | 
				
			||||||
 | 
					@var{dh-params.pem} providing diffie-hellman parameters to use
 | 
				
			||||||
 | 
					for the TLS server. If the file is missing, QEMU will generate
 | 
				
			||||||
 | 
					a set of DH parameters at startup. This is a computationally
 | 
				
			||||||
 | 
					expensive operation that consumes random pool entropy, so it is
 | 
				
			||||||
 | 
					recommended that a persistent set of parameters be generated
 | 
				
			||||||
 | 
					upfront and saved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item -object tls-creds-x509,id=@var{id},endpoint=@var{endpoint},dir=@var{/path/to/cred/dir},verify-peer=@var{on|off}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Creates a TLS anonymous credentials object, which can be used to provide
 | 
				
			||||||
 | 
					TLS support on network backends. The @option{id} parameter is a unique
 | 
				
			||||||
 | 
					ID which network backends will use to access the credentials. The
 | 
				
			||||||
 | 
					@option{endpoint} is either @option{server} or @option{client} depending
 | 
				
			||||||
 | 
					on whether the QEMU network backend that uses the credentials will be
 | 
				
			||||||
 | 
					acting as a client or as a server. If @option{verify-peer} is enabled
 | 
				
			||||||
 | 
					(the default) then once the handshake is completed, the peer credentials
 | 
				
			||||||
 | 
					will be verified. With x509 certificates, this implies that the clients
 | 
				
			||||||
 | 
					must be provided with valid client certificates too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The @var{dir} parameter tells QEMU where to find the credential
 | 
				
			||||||
 | 
					files. For server endpoints, this directory may contain a file
 | 
				
			||||||
 | 
					@var{dh-params.pem} providing diffie-hellman parameters to use
 | 
				
			||||||
 | 
					for the TLS server. If the file is missing, QEMU will generate
 | 
				
			||||||
 | 
					a set of DH parameters at startup. This is a computationally
 | 
				
			||||||
 | 
					expensive operation that consumes random pool entropy, so it is
 | 
				
			||||||
 | 
					recommended that a persistent set of parameters be generated
 | 
				
			||||||
 | 
					upfront and saved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For x509 certificate credentials the directory will contain further files
 | 
				
			||||||
 | 
					providing the x509 certificates. The certificates must be stored
 | 
				
			||||||
 | 
					in PEM format, in filenames @var{ca-cert.pem}, @var{ca-crl.pem} (optional),
 | 
				
			||||||
 | 
					@var{server-cert.pem} (only servers), @var{server-key.pem} (only servers),
 | 
				
			||||||
 | 
					@var{client-cert.pem} (only clients), and @var{client-key.pem} (only clients).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@end table
 | 
					@end table
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ETEXI
 | 
					ETEXI
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,4 @@
 | 
				
			|||||||
common-obj-y = object.o container.o qom-qobject.o
 | 
					qom-obj-y = object.o container.o qom-qobject.o
 | 
				
			||||||
common-obj-y += cpu.o
 | 
					qom-obj-y += object_interfaces.o
 | 
				
			||||||
common-obj-y += object_interfaces.o
 | 
					
 | 
				
			||||||
 | 
					common-obj-y = cpu.o
 | 
				
			||||||
 | 
				
			|||||||
@ -101,20 +101,20 @@ struct %(name)s {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return ret
 | 
					    return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def generate_enum_lookup(name, values):
 | 
					def generate_enum_lookup(name, values, prefix=None):
 | 
				
			||||||
    ret = mcgen('''
 | 
					    ret = mcgen('''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *const %(name)s_lookup[] = {
 | 
					const char *const %(name)s_lookup[] = {
 | 
				
			||||||
''',
 | 
					''',
 | 
				
			||||||
                name=c_name(name))
 | 
					                name=c_name(name))
 | 
				
			||||||
    for value in values:
 | 
					    for value in values:
 | 
				
			||||||
        index = c_enum_const(name, value)
 | 
					        index = c_enum_const(name, value, prefix)
 | 
				
			||||||
        ret += mcgen('''
 | 
					        ret += mcgen('''
 | 
				
			||||||
    [%(index)s] = "%(value)s",
 | 
					    [%(index)s] = "%(value)s",
 | 
				
			||||||
''',
 | 
					''',
 | 
				
			||||||
                     index = index, value = value)
 | 
					                     index = index, value = value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    max_index = c_enum_const(name, 'MAX')
 | 
					    max_index = c_enum_const(name, 'MAX', prefix)
 | 
				
			||||||
    ret += mcgen('''
 | 
					    ret += mcgen('''
 | 
				
			||||||
    [%(max_index)s] = NULL,
 | 
					    [%(max_index)s] = NULL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -122,7 +122,7 @@ const char *const %(name)s_lookup[] = {
 | 
				
			|||||||
        max_index=max_index)
 | 
					        max_index=max_index)
 | 
				
			||||||
    return ret
 | 
					    return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def generate_enum(name, values):
 | 
					def generate_enum(name, values, prefix=None):
 | 
				
			||||||
    name = c_name(name)
 | 
					    name = c_name(name)
 | 
				
			||||||
    lookup_decl = mcgen('''
 | 
					    lookup_decl = mcgen('''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -141,7 +141,7 @@ typedef enum %(name)s {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    i = 0
 | 
					    i = 0
 | 
				
			||||||
    for value in enum_values:
 | 
					    for value in enum_values:
 | 
				
			||||||
        enum_full_value = c_enum_const(name, value)
 | 
					        enum_full_value = c_enum_const(name, value, prefix)
 | 
				
			||||||
        enum_decl += mcgen('''
 | 
					        enum_decl += mcgen('''
 | 
				
			||||||
    %(enum_full_value)s = %(i)d,
 | 
					    %(enum_full_value)s = %(i)d,
 | 
				
			||||||
''',
 | 
					''',
 | 
				
			||||||
@ -348,9 +348,11 @@ for expr in exprs:
 | 
				
			|||||||
    if expr.has_key('struct'):
 | 
					    if expr.has_key('struct'):
 | 
				
			||||||
        ret += generate_fwd_struct(expr['struct'])
 | 
					        ret += generate_fwd_struct(expr['struct'])
 | 
				
			||||||
    elif expr.has_key('enum'):
 | 
					    elif expr.has_key('enum'):
 | 
				
			||||||
        ret += generate_enum(expr['enum'], expr['data'])
 | 
					        ret += generate_enum(expr['enum'], expr['data'],
 | 
				
			||||||
 | 
					                             expr.get('prefix'))
 | 
				
			||||||
        ret += generate_fwd_enum_struct(expr['enum'])
 | 
					        ret += generate_fwd_enum_struct(expr['enum'])
 | 
				
			||||||
        fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
 | 
					        fdef.write(generate_enum_lookup(expr['enum'], expr['data'],
 | 
				
			||||||
 | 
					                                        expr.get('prefix')))
 | 
				
			||||||
    elif expr.has_key('union'):
 | 
					    elif expr.has_key('union'):
 | 
				
			||||||
        ret += generate_fwd_struct(expr['union'])
 | 
					        ret += generate_fwd_struct(expr['union'])
 | 
				
			||||||
        enum_define = discriminator_find_enum_define(expr)
 | 
					        enum_define = discriminator_find_enum_define(expr)
 | 
				
			||||||
 | 
				
			|||||||
@ -634,11 +634,15 @@ def check_alternate(expr, expr_info):
 | 
				
			|||||||
def check_enum(expr, expr_info):
 | 
					def check_enum(expr, expr_info):
 | 
				
			||||||
    name = expr['enum']
 | 
					    name = expr['enum']
 | 
				
			||||||
    members = expr.get('data')
 | 
					    members = expr.get('data')
 | 
				
			||||||
 | 
					    prefix = expr.get('prefix')
 | 
				
			||||||
    values = { 'MAX': '(automatic)' }
 | 
					    values = { 'MAX': '(automatic)' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not isinstance(members, list):
 | 
					    if not isinstance(members, list):
 | 
				
			||||||
        raise QAPIExprError(expr_info,
 | 
					        raise QAPIExprError(expr_info,
 | 
				
			||||||
                            "Enum '%s' requires an array for 'data'" % name)
 | 
					                            "Enum '%s' requires an array for 'data'" % name)
 | 
				
			||||||
 | 
					    if prefix is not None and not isinstance(prefix, str):
 | 
				
			||||||
 | 
					        raise QAPIExprError(expr_info,
 | 
				
			||||||
 | 
					                            "Enum '%s' requires a string for 'prefix'" % name)
 | 
				
			||||||
    for member in members:
 | 
					    for member in members:
 | 
				
			||||||
        check_name(expr_info, "Member of enum '%s'" %name, member,
 | 
					        check_name(expr_info, "Member of enum '%s'" %name, member,
 | 
				
			||||||
                   enum_member=True)
 | 
					                   enum_member=True)
 | 
				
			||||||
@ -693,7 +697,7 @@ def check_exprs(exprs):
 | 
				
			|||||||
        expr = expr_elem['expr']
 | 
					        expr = expr_elem['expr']
 | 
				
			||||||
        info = expr_elem['info']
 | 
					        info = expr_elem['info']
 | 
				
			||||||
        if expr.has_key('enum'):
 | 
					        if expr.has_key('enum'):
 | 
				
			||||||
            check_keys(expr_elem, 'enum', ['data'])
 | 
					            check_keys(expr_elem, 'enum', ['data'], ['prefix'])
 | 
				
			||||||
            add_enum(expr['enum'], info, expr['data'])
 | 
					            add_enum(expr['enum'], info, expr['data'])
 | 
				
			||||||
        elif expr.has_key('union'):
 | 
					        elif expr.has_key('union'):
 | 
				
			||||||
            check_keys(expr_elem, 'union', ['data'],
 | 
					            check_keys(expr_elem, 'union', ['data'],
 | 
				
			||||||
@ -813,7 +817,9 @@ def camel_to_upper(value):
 | 
				
			|||||||
        new_name += c
 | 
					        new_name += c
 | 
				
			||||||
    return new_name.lstrip('_').upper()
 | 
					    return new_name.lstrip('_').upper()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def c_enum_const(type_name, const_name):
 | 
					def c_enum_const(type_name, const_name, prefix=None):
 | 
				
			||||||
 | 
					    if prefix is not None:
 | 
				
			||||||
 | 
					        type_name = prefix
 | 
				
			||||||
    return camel_to_upper(type_name + '_' + const_name)
 | 
					    return camel_to_upper(type_name + '_' + const_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
c_name_trans = string.maketrans('.-', '__')
 | 
					c_name_trans = string.maketrans('.-', '__')
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								tests/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								tests/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -12,6 +12,13 @@ test-bitops
 | 
				
			|||||||
test-coroutine
 | 
					test-coroutine
 | 
				
			||||||
test-crypto-cipher
 | 
					test-crypto-cipher
 | 
				
			||||||
test-crypto-hash
 | 
					test-crypto-hash
 | 
				
			||||||
 | 
					test-crypto-tlscredsx509
 | 
				
			||||||
 | 
					test-crypto-tlscredsx509-work/
 | 
				
			||||||
 | 
					test-crypto-tlscredsx509-certs/
 | 
				
			||||||
 | 
					test-crypto-tlssession
 | 
				
			||||||
 | 
					test-crypto-tlssession-work/
 | 
				
			||||||
 | 
					test-crypto-tlssession-client/
 | 
				
			||||||
 | 
					test-crypto-tlssession-server/
 | 
				
			||||||
test-cutils
 | 
					test-cutils
 | 
				
			||||||
test-hbitmap
 | 
					test-hbitmap
 | 
				
			||||||
test-int128
 | 
					test-int128
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										102
									
								
								tests/Makefile
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								tests/Makefile
									
									
									
									
									
								
							@ -1,5 +1,7 @@
 | 
				
			|||||||
export SRC_PATH
 | 
					export SRC_PATH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Get the list of all supported sysemu targets
 | 
					# Get the list of all supported sysemu targets
 | 
				
			||||||
SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \
 | 
					SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \
 | 
				
			||||||
   $(wildcard $(SRC_PATH)/default-configs/*-softmmu.mak)))
 | 
					   $(wildcard $(SRC_PATH)/default-configs/*-softmmu.mak)))
 | 
				
			||||||
@ -76,6 +78,8 @@ check-unit-y += tests/test-write-threshold$(EXESUF)
 | 
				
			|||||||
gcov-files-test-write-threshold-y = block/write-threshold.c
 | 
					gcov-files-test-write-threshold-y = block/write-threshold.c
 | 
				
			||||||
check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF)
 | 
					check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF)
 | 
				
			||||||
check-unit-y += tests/test-crypto-cipher$(EXESUF)
 | 
					check-unit-y += tests/test-crypto-cipher$(EXESUF)
 | 
				
			||||||
 | 
					check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF)
 | 
				
			||||||
 | 
					check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 | 
					check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -221,7 +225,8 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
 | 
				
			|||||||
	comments.json empty.json enum-empty.json enum-missing-data.json \
 | 
						comments.json empty.json enum-empty.json enum-missing-data.json \
 | 
				
			||||||
	enum-wrong-data.json enum-int-member.json enum-dict-member.json \
 | 
						enum-wrong-data.json enum-int-member.json enum-dict-member.json \
 | 
				
			||||||
	enum-clash-member.json enum-max-member.json enum-union-clash.json \
 | 
						enum-clash-member.json enum-max-member.json enum-union-clash.json \
 | 
				
			||||||
	enum-bad-name.json funny-char.json indented-expr.json \
 | 
						enum-bad-name.json enum-bad-prefix.json \
 | 
				
			||||||
 | 
						funny-char.json indented-expr.json \
 | 
				
			||||||
	missing-type.json bad-ident.json ident-with-escape.json \
 | 
						missing-type.json bad-ident.json ident-with-escape.json \
 | 
				
			||||||
	escape-outside-string.json unknown-escape.json \
 | 
						escape-outside-string.json unknown-escape.json \
 | 
				
			||||||
	escape-too-short.json escape-too-big.json unicode-str.json \
 | 
						escape-too-short.json escape-too-big.json unicode-str.json \
 | 
				
			||||||
@ -275,47 +280,50 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
 | 
				
			|||||||
	tests/test-opts-visitor.o tests/test-qmp-event.o \
 | 
						tests/test-opts-visitor.o tests/test-qmp-event.o \
 | 
				
			||||||
	tests/rcutorture.o tests/test-rcu-list.o
 | 
						tests/rcutorture.o tests/test-rcu-list.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \
 | 
					 | 
				
			||||||
		  tests/test-qapi-event.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$(test-obj-y): QEMU_INCLUDES += -Itests
 | 
					$(test-obj-y): QEMU_INCLUDES += -Itests
 | 
				
			||||||
QEMU_CFLAGS += -I$(SRC_PATH)/tests
 | 
					QEMU_CFLAGS += -I$(SRC_PATH)/tests
 | 
				
			||||||
qom-core-obj = qom/object.o qom/qom-qobject.o qom/container.o qom/object_interfaces.o
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
tests/check-qint$(EXESUF): tests/check-qint.o libqemuutil.a
 | 
					
 | 
				
			||||||
tests/check-qstring$(EXESUF): tests/check-qstring.o libqemuutil.a
 | 
					# Deps that are common to various different sets of tests below
 | 
				
			||||||
tests/check-qdict$(EXESUF): tests/check-qdict.o libqemuutil.a
 | 
					test-util-obj-y = libqemuutil.a libqemustub.a
 | 
				
			||||||
tests/check-qlist$(EXESUF): tests/check-qlist.o libqemuutil.a
 | 
					test-qom-obj-y = $(qom-obj-y) $(test-util-obj-y)
 | 
				
			||||||
tests/check-qfloat$(EXESUF): tests/check-qfloat.o libqemuutil.a
 | 
					test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \
 | 
				
			||||||
tests/check-qjson$(EXESUF): tests/check-qjson.o libqemuutil.a libqemustub.a
 | 
						tests/test-qapi-event.o \
 | 
				
			||||||
tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(qom-core-obj) libqemuutil.a libqemustub.a
 | 
						$(test-qom-obj-y)
 | 
				
			||||||
tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(qom-core-obj) libqemuutil.a libqemustub.a
 | 
					test-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y)
 | 
				
			||||||
tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil.a libqemustub.a
 | 
					test-block-obj-y = $(block-obj-y) $(test-crypto-obj-y)
 | 
				
			||||||
tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a
 | 
					
 | 
				
			||||||
tests/test-rfifolock$(EXESUF): tests/test-rfifolock.o libqemuutil.a libqemustub.a
 | 
					tests/check-qint$(EXESUF): tests/check-qint.o $(test-util-obj-y)
 | 
				
			||||||
tests/test-throttle$(EXESUF): tests/test-throttle.o $(block-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y)
 | 
				
			||||||
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/check-qdict$(EXESUF): tests/check-qdict.o $(test-util-obj-y)
 | 
				
			||||||
tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a
 | 
					tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y)
 | 
				
			||||||
tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o libqemuutil.a libqemustub.a
 | 
					tests/check-qfloat$(EXESUF): tests/check-qfloat.o $(test-util-obj-y)
 | 
				
			||||||
 | 
					tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y)
 | 
				
			||||||
 | 
					tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom-obj-y)
 | 
				
			||||||
 | 
					tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y)
 | 
				
			||||||
 | 
					tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
 | 
				
			||||||
 | 
					tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
 | 
				
			||||||
 | 
					tests/test-rfifolock$(EXESUF): tests/test-rfifolock.o $(test-util-obj-y)
 | 
				
			||||||
 | 
					tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
 | 
				
			||||||
 | 
					tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
 | 
				
			||||||
 | 
					tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
 | 
				
			||||||
 | 
					tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y)
 | 
				
			||||||
tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o
 | 
					tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o
 | 
				
			||||||
tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o page_cache.o libqemuutil.a
 | 
					tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o page_cache.o $(test-util-obj-y)
 | 
				
			||||||
tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o
 | 
					tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o
 | 
				
			||||||
tests/test-int128$(EXESUF): tests/test-int128.o
 | 
					tests/test-int128$(EXESUF): tests/test-int128.o
 | 
				
			||||||
tests/rcutorture$(EXESUF): tests/rcutorture.o libqemuutil.a libqemustub.a
 | 
					tests/rcutorture$(EXESUF): tests/rcutorture.o $(test-util-obj-y)
 | 
				
			||||||
tests/test-rcu-list$(EXESUF): tests/test-rcu-list.o libqemuutil.a libqemustub.a
 | 
					tests/test-rcu-list$(EXESUF): tests/test-rcu-list.o $(test-util-obj-y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
 | 
					tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
 | 
				
			||||||
	hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\
 | 
						hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\
 | 
				
			||||||
	hw/core/irq.o \
 | 
						hw/core/irq.o \
 | 
				
			||||||
	hw/core/fw-path-provider.o \
 | 
						hw/core/fw-path-provider.o \
 | 
				
			||||||
	$(qom-core-obj) \
 | 
						$(test-qapi-obj-y)
 | 
				
			||||||
	$(test-qapi-obj-y) \
 | 
					 | 
				
			||||||
	libqemuutil.a libqemustub.a
 | 
					 | 
				
			||||||
tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
 | 
					tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
 | 
				
			||||||
	migration/vmstate.o migration/qemu-file.o migration/qemu-file-buf.o \
 | 
						migration/vmstate.o migration/qemu-file.o migration/qemu-file-buf.o \
 | 
				
			||||||
        migration/qemu-file-unix.o qjson.o \
 | 
					        migration/qemu-file-unix.o qjson.o \
 | 
				
			||||||
	$(qom-core-obj) \
 | 
						$(test-qom-obj-y)
 | 
				
			||||||
	libqemuutil.a libqemustub.a
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
tests/test-qapi-types.c tests/test-qapi-types.h :\
 | 
					tests/test-qapi-types.c tests/test-qapi-types.h :\
 | 
				
			||||||
$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
 | 
					$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
 | 
				
			||||||
@ -338,20 +346,24 @@ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-eve
 | 
				
			|||||||
		$(gen-out-type) -o tests -p "test-" $<, \
 | 
							$(gen-out-type) -o tests -p "test-" $<, \
 | 
				
			||||||
		"  GEN   $@")
 | 
							"  GEN   $@")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
 | 
				
			||||||
tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
 | 
				
			||||||
tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y)
 | 
				
			||||||
tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y)
 | 
				
			||||||
tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y)
 | 
				
			||||||
tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y)
 | 
				
			||||||
tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
 | 
				
			||||||
tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y)
 | 
				
			||||||
tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a
 | 
					tests/test-mul64$(EXESUF): tests/test-mul64.o $(test-util-obj-y)
 | 
				
			||||||
tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a
 | 
					tests/test-bitops$(EXESUF): tests/test-bitops.o $(test-util-obj-y)
 | 
				
			||||||
tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o libqemuutil.a libqemustub.a
 | 
					tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o $(test-crypto-obj-y)
 | 
				
			||||||
tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o libqemuutil.a libqemustub.a
 | 
					tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o $(test-crypto-obj-y)
 | 
				
			||||||
 | 
					tests/test-crypto-tlscredsx509$(EXESUF): tests/test-crypto-tlscredsx509.o \
 | 
				
			||||||
 | 
						tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o $(test-crypto-obj-y)
 | 
				
			||||||
 | 
					tests/test-crypto-tlssession$(EXESUF): tests/test-crypto-tlssession.o \
 | 
				
			||||||
 | 
						tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o $(test-crypto-obj-y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
 | 
					libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
 | 
				
			||||||
libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
 | 
					libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
 | 
				
			||||||
@ -414,12 +426,14 @@ tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
 | 
				
			|||||||
tests/pc-cpu-test$(EXESUF): tests/pc-cpu-test.o
 | 
					tests/pc-cpu-test$(EXESUF): tests/pc-cpu-test.o
 | 
				
			||||||
tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y)
 | 
					tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y)
 | 
				
			||||||
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
 | 
					tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
 | 
				
			||||||
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a
 | 
					tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y)
 | 
				
			||||||
tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(block-obj-y) libqemuutil.a libqemustub.a
 | 
					tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(CONFIG_POSIX),y)
 | 
					ifeq ($(CONFIG_POSIX),y)
 | 
				
			||||||
LIBS += -lutil
 | 
					LIBS += -lutil
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					LIBS += $(TEST_LIBS)
 | 
				
			||||||
 | 
					CFLAGS += $(TEST_CFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# QTest rules
 | 
					# QTest rules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -429,7 +443,7 @@ QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TA
 | 
				
			|||||||
check-qtest-y=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
 | 
					check-qtest-y=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a
 | 
					qtest-obj-y = tests/libqtest.o $(test-util-obj-y)
 | 
				
			||||||
$(check-qtest-y): $(qtest-obj-y)
 | 
					$(check-qtest-y): $(qtest-obj-y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: check-help
 | 
					.PHONY: check-help
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										485
									
								
								tests/crypto-tls-x509-helpers.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										485
									
								
								tests/crypto-tls-x509-helpers.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,485 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2.1 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library.  If not, see
 | 
				
			||||||
 | 
					 * <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Daniel P. Berrange <berrange@redhat.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "config-host.h"
 | 
				
			||||||
 | 
					#include "crypto-tls-x509-helpers.h"
 | 
				
			||||||
 | 
					#include "qemu/sockets.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This stores some static data that is needed when
 | 
				
			||||||
 | 
					 * encoding extensions in the x509 certs
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					ASN1_TYPE pkix_asn1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * To avoid consuming random entropy to generate keys,
 | 
				
			||||||
 | 
					 * here's one we prepared earlier :-)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					gnutls_x509_privkey_t privkey;
 | 
				
			||||||
 | 
					# define PRIVATE_KEY                                              \
 | 
				
			||||||
 | 
					    "-----BEGIN PRIVATE KEY-----\n"                               \
 | 
				
			||||||
 | 
					    "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALVcr\n"     \
 | 
				
			||||||
 | 
					    "BL40Tm6yq88FBhJNw1aaoCjmtg0l4dWQZ/e9Fimx4ARxFpT+ji4FE\n"     \
 | 
				
			||||||
 | 
					    "Cgl9s/SGqC+1nvlkm9ViSo0j7MKDbnDB+VRHDvMAzQhA2X7e8M0n9\n"     \
 | 
				
			||||||
 | 
					    "rPolUY2lIVC83q0BBaOBkCj2RSmT2xTEbbC2xLukSrg2WP/ihVOxc\n"     \
 | 
				
			||||||
 | 
					    "kXRuyFtzAgMBAAECgYB7slBexDwXrtItAMIH6m/U+LUpNe0Xx48OL\n"     \
 | 
				
			||||||
 | 
					    "IOn4a4whNgO/o84uIwygUK27ZGFZT0kAGAk8CdF9hA6ArcbQ62s1H\n"     \
 | 
				
			||||||
 | 
					    "myxrUbF9/mrLsQw1NEqpuUk9Ay2Tx5U/wPx35S3W/X2AvR/ZpTnCn\n"     \
 | 
				
			||||||
 | 
					    "2q/7ym9fyiSoj86drD7BTvmKXlOnOwQJBAPOFMp4mMa9NGpGuEssO\n"     \
 | 
				
			||||||
 | 
					    "m3Uwbp6lhcP0cA9MK+iOmeANpoKWfBdk5O34VbmeXnGYWEkrnX+9J\n"     \
 | 
				
			||||||
 | 
					    "bM4wVhnnBWtgBMCQQC+qAEmvwcfhauERKYznMVUVksyeuhxhCe7EK\n"     \
 | 
				
			||||||
 | 
					    "mPh+U2+g0WwdKvGDgO0PPt1gq0ILEjspMDeMHVdTwkaVBo/uMhAkA\n"     \
 | 
				
			||||||
 | 
					    "Z5SsZyCP2aTOPFDypXRdI4eqRcjaEPOUBq27r3uYb/jeboVb2weLa\n"     \
 | 
				
			||||||
 | 
					    "L1MmVuHiIHoa5clswPdWVI2y0em2IGoDAkBPSp/v9VKJEZabk9Frd\n"     \
 | 
				
			||||||
 | 
					    "a+7u4fanrM9QrEjY3KhduslSilXZZSxrWjjAJPyPiqFb3M8XXA26W\n"     \
 | 
				
			||||||
 | 
					    "nz1KYGnqYKhLcBAkB7dt57n9xfrhDpuyVEv+Uv1D3VVAhZlsaZ5Pp\n"     \
 | 
				
			||||||
 | 
					    "dcrhrkJn2sa/+O8OKvdrPSeeu/N5WwYhJf61+CPoenMp7IFci\n"         \
 | 
				
			||||||
 | 
					    "-----END PRIVATE KEY-----\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This loads the private key we defined earlier
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static gnutls_x509_privkey_t test_tls_load_key(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gnutls_x509_privkey_t key;
 | 
				
			||||||
 | 
					    const gnutls_datum_t data = { (unsigned char *)PRIVATE_KEY,
 | 
				
			||||||
 | 
					                                  strlen(PRIVATE_KEY) };
 | 
				
			||||||
 | 
					    int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    err = gnutls_x509_privkey_init(&key);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        g_critical("Failed to init key %s", gnutls_strerror(err));
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    err = gnutls_x509_privkey_import(key, &data,
 | 
				
			||||||
 | 
					                                     GNUTLS_X509_FMT_PEM);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        if (err != GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR &&
 | 
				
			||||||
 | 
					            err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
 | 
				
			||||||
 | 
					            g_critical("Failed to import key %s", gnutls_strerror(err));
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        err = gnutls_x509_privkey_import_pkcs8(
 | 
				
			||||||
 | 
					            key, &data, GNUTLS_X509_FMT_PEM, NULL, 0);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            g_critical("Failed to import PKCS8 key %s", gnutls_strerror(err));
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return key;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_tls_init(const char *keyfile)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gnutls_global_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (asn1_array2tree(pkix_asn1_tab, &pkix_asn1, NULL) != ASN1_SUCCESS) {
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    privkey = test_tls_load_key();
 | 
				
			||||||
 | 
					    if (!g_file_set_contents(keyfile, PRIVATE_KEY, -1, NULL)) {
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_tls_cleanup(const char *keyfile)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    asn1_delete_structure(&pkix_asn1);
 | 
				
			||||||
 | 
					    unlink(keyfile);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Turns an ASN1 object into a DER encoded byte array
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void test_tls_der_encode(ASN1_TYPE src,
 | 
				
			||||||
 | 
					                                const char *src_name,
 | 
				
			||||||
 | 
					                                gnutls_datum_t *res)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  int size;
 | 
				
			||||||
 | 
					  char *data = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  size = 0;
 | 
				
			||||||
 | 
					  asn1_der_coding(src, src_name, NULL, &size, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = g_new0(char, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  asn1_der_coding(src, src_name, data, &size, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  res->data = (unsigned char *)data;
 | 
				
			||||||
 | 
					  res->size = size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					test_tls_get_ipaddr(const char *addrstr,
 | 
				
			||||||
 | 
					                    char **data,
 | 
				
			||||||
 | 
					                    int *datalen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct addrinfo *res;
 | 
				
			||||||
 | 
					    struct addrinfo hints;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(&hints, 0, sizeof(hints));
 | 
				
			||||||
 | 
					    hints.ai_flags = AI_NUMERICHOST;
 | 
				
			||||||
 | 
					    g_assert(getaddrinfo(addrstr, NULL, &hints, &res) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *datalen = res->ai_addrlen;
 | 
				
			||||||
 | 
					    *data = g_new(char, *datalen);
 | 
				
			||||||
 | 
					    memcpy(*data, res->ai_addr, *datalen);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is a fairly lame x509 certificate generator.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Do not copy/use this code for generating real certificates
 | 
				
			||||||
 | 
					 * since it leaves out many things that you would want in
 | 
				
			||||||
 | 
					 * certificates for real world usage.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is good enough only for doing tests of the QEMU
 | 
				
			||||||
 | 
					 * TLS certificate code
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					test_tls_generate_cert(QCryptoTLSTestCertReq *req,
 | 
				
			||||||
 | 
					                       gnutls_x509_crt_t ca)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gnutls_x509_crt_t crt;
 | 
				
			||||||
 | 
					    int err;
 | 
				
			||||||
 | 
					    static char buffer[1024 * 1024];
 | 
				
			||||||
 | 
					    size_t size = sizeof(buffer);
 | 
				
			||||||
 | 
					    char serial[5] = { 1, 2, 3, 4, 0 };
 | 
				
			||||||
 | 
					    gnutls_datum_t der;
 | 
				
			||||||
 | 
					    time_t start = time(NULL) + (60 * 60 * req->start_offset);
 | 
				
			||||||
 | 
					    time_t expire = time(NULL) + (60 * 60 * (req->expire_offset
 | 
				
			||||||
 | 
					                                             ? req->expire_offset : 24));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Prepare our new certificate object
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    err = gnutls_x509_crt_init(&crt);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        g_critical("Failed to initialize certificate %s", gnutls_strerror(err));
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    err = gnutls_x509_crt_set_key(crt, privkey);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        g_critical("Failed to set certificate key %s", gnutls_strerror(err));
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * A v3 certificate is required in order to be able
 | 
				
			||||||
 | 
					     * set any of the basic constraints, key purpose and
 | 
				
			||||||
 | 
					     * key usage data
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    gnutls_x509_crt_set_version(crt, 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (req->country) {
 | 
				
			||||||
 | 
					        err = gnutls_x509_crt_set_dn_by_oid(
 | 
				
			||||||
 | 
					            crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
 | 
				
			||||||
 | 
					            req->country, strlen(req->country));
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            g_critical("Failed to set certificate country name %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(err));
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (req->cn) {
 | 
				
			||||||
 | 
					        err = gnutls_x509_crt_set_dn_by_oid(
 | 
				
			||||||
 | 
					            crt, GNUTLS_OID_X520_COMMON_NAME, 0,
 | 
				
			||||||
 | 
					            req->cn, strlen(req->cn));
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            g_critical("Failed to set certificate common name %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(err));
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Setup the subject altnames, which are used
 | 
				
			||||||
 | 
					     * for hostname checks in live sessions
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (req->altname1) {
 | 
				
			||||||
 | 
					        err = gnutls_x509_crt_set_subject_alt_name(
 | 
				
			||||||
 | 
					            crt, GNUTLS_SAN_DNSNAME,
 | 
				
			||||||
 | 
					            req->altname1,
 | 
				
			||||||
 | 
					            strlen(req->altname1),
 | 
				
			||||||
 | 
					            GNUTLS_FSAN_APPEND);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            g_critical("Failed to set certificate alt name %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(err));
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (req->altname2) {
 | 
				
			||||||
 | 
					        err = gnutls_x509_crt_set_subject_alt_name(
 | 
				
			||||||
 | 
					            crt, GNUTLS_SAN_DNSNAME,
 | 
				
			||||||
 | 
					            req->altname2,
 | 
				
			||||||
 | 
					            strlen(req->altname2),
 | 
				
			||||||
 | 
					            GNUTLS_FSAN_APPEND);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            g_critical("Failed to set certificate %s alt name",
 | 
				
			||||||
 | 
					                       gnutls_strerror(err));
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * IP address need to be put into the cert in their
 | 
				
			||||||
 | 
					     * raw byte form, not strings, hence this is a little
 | 
				
			||||||
 | 
					     * more complicated
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (req->ipaddr1) {
 | 
				
			||||||
 | 
					        char *data;
 | 
				
			||||||
 | 
					        int len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        test_tls_get_ipaddr(req->ipaddr1, &data, &len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        err = gnutls_x509_crt_set_subject_alt_name(
 | 
				
			||||||
 | 
					            crt, GNUTLS_SAN_IPADDRESS,
 | 
				
			||||||
 | 
					            data, len, GNUTLS_FSAN_APPEND);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            g_critical("Failed to set certificate alt name %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(err));
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        g_free(data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (req->ipaddr2) {
 | 
				
			||||||
 | 
					        char *data;
 | 
				
			||||||
 | 
					        int len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        test_tls_get_ipaddr(req->ipaddr2, &data, &len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        err = gnutls_x509_crt_set_subject_alt_name(
 | 
				
			||||||
 | 
					            crt, GNUTLS_SAN_IPADDRESS,
 | 
				
			||||||
 | 
					            data, len, GNUTLS_FSAN_APPEND);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            g_critical("Failed to set certificate alt name %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(err));
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        g_free(data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Basic constraints are used to decide if the cert
 | 
				
			||||||
 | 
					     * is for a CA or not. We can't use the convenient
 | 
				
			||||||
 | 
					     * gnutls API for setting this, since it hardcodes
 | 
				
			||||||
 | 
					     * the 'critical' field which we want control over
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (req->basicConstraintsEnable) {
 | 
				
			||||||
 | 
					        ASN1_TYPE ext = ASN1_TYPE_EMPTY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        asn1_create_element(pkix_asn1, "PKIX1.BasicConstraints", &ext);
 | 
				
			||||||
 | 
					        asn1_write_value(ext, "cA",
 | 
				
			||||||
 | 
					                         req->basicConstraintsIsCA ? "TRUE" : "FALSE", 1);
 | 
				
			||||||
 | 
					        asn1_write_value(ext, "pathLenConstraint", NULL, 0);
 | 
				
			||||||
 | 
					        test_tls_der_encode(ext, "", &der);
 | 
				
			||||||
 | 
					        err = gnutls_x509_crt_set_extension_by_oid(
 | 
				
			||||||
 | 
					            crt, "2.5.29.19",
 | 
				
			||||||
 | 
					            der.data, der.size,
 | 
				
			||||||
 | 
					            req->basicConstraintsCritical);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            g_critical("Failed to set certificate basic constraints %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(err));
 | 
				
			||||||
 | 
					            g_free(der.data);
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        asn1_delete_structure(&ext);
 | 
				
			||||||
 | 
					        g_free(der.data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Next up the key usage extension. Again we can't
 | 
				
			||||||
 | 
					     * use the gnutls API since it hardcodes the extension
 | 
				
			||||||
 | 
					     * to be 'critical'
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (req->keyUsageEnable) {
 | 
				
			||||||
 | 
					        ASN1_TYPE ext = ASN1_TYPE_EMPTY;
 | 
				
			||||||
 | 
					        char str[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        str[0] = req->keyUsageValue & 0xff;
 | 
				
			||||||
 | 
					        str[1] = (req->keyUsageValue >> 8) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        asn1_create_element(pkix_asn1, "PKIX1.KeyUsage", &ext);
 | 
				
			||||||
 | 
					        asn1_write_value(ext, "", str, 9);
 | 
				
			||||||
 | 
					        test_tls_der_encode(ext, "", &der);
 | 
				
			||||||
 | 
					        err = gnutls_x509_crt_set_extension_by_oid(
 | 
				
			||||||
 | 
					            crt, "2.5.29.15",
 | 
				
			||||||
 | 
					            der.data, der.size,
 | 
				
			||||||
 | 
					            req->keyUsageCritical);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            g_critical("Failed to set certificate key usage %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(err));
 | 
				
			||||||
 | 
					            g_free(der.data);
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        asn1_delete_structure(&ext);
 | 
				
			||||||
 | 
					        g_free(der.data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Finally the key purpose extension. This time
 | 
				
			||||||
 | 
					     * gnutls has the opposite problem, always hardcoding
 | 
				
			||||||
 | 
					     * it to be non-critical. So once again we have to
 | 
				
			||||||
 | 
					     * set this the hard way building up ASN1 data ourselves
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (req->keyPurposeEnable) {
 | 
				
			||||||
 | 
					        ASN1_TYPE ext = ASN1_TYPE_EMPTY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        asn1_create_element(pkix_asn1, "PKIX1.ExtKeyUsageSyntax", &ext);
 | 
				
			||||||
 | 
					        if (req->keyPurposeOID1) {
 | 
				
			||||||
 | 
					            asn1_write_value(ext, "", "NEW", 1);
 | 
				
			||||||
 | 
					            asn1_write_value(ext, "?LAST", req->keyPurposeOID1, 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (req->keyPurposeOID2) {
 | 
				
			||||||
 | 
					            asn1_write_value(ext, "", "NEW", 1);
 | 
				
			||||||
 | 
					            asn1_write_value(ext, "?LAST", req->keyPurposeOID2, 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        test_tls_der_encode(ext, "", &der);
 | 
				
			||||||
 | 
					        err = gnutls_x509_crt_set_extension_by_oid(
 | 
				
			||||||
 | 
					            crt, "2.5.29.37",
 | 
				
			||||||
 | 
					            der.data, der.size,
 | 
				
			||||||
 | 
					            req->keyPurposeCritical);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            g_critical("Failed to set certificate key purpose %s",
 | 
				
			||||||
 | 
					                       gnutls_strerror(err));
 | 
				
			||||||
 | 
					            g_free(der.data);
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        asn1_delete_structure(&ext);
 | 
				
			||||||
 | 
					        g_free(der.data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Any old serial number will do, so lets pick 5
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    err = gnutls_x509_crt_set_serial(crt, serial, 5);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        g_critical("Failed to set certificate serial %s",
 | 
				
			||||||
 | 
					                   gnutls_strerror(err));
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    err = gnutls_x509_crt_set_activation_time(crt, start);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        g_critical("Failed to set certificate activation %s",
 | 
				
			||||||
 | 
					                   gnutls_strerror(err));
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    err = gnutls_x509_crt_set_expiration_time(crt, expire);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        g_critical("Failed to set certificate expiration %s",
 | 
				
			||||||
 | 
					                   gnutls_strerror(err));
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * If no 'ca' is set then we are self signing
 | 
				
			||||||
 | 
					     * the cert. This is done for the root CA certs
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    err = gnutls_x509_crt_sign(crt, ca ? ca : crt, privkey);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        g_critical("Failed to sign certificate %s",
 | 
				
			||||||
 | 
					                   gnutls_strerror(err));
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Finally write the new cert out to disk
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    err = gnutls_x509_crt_export(
 | 
				
			||||||
 | 
					        crt, GNUTLS_X509_FMT_PEM, buffer, &size);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        g_critical("Failed to export certificate %s: %d",
 | 
				
			||||||
 | 
					                   gnutls_strerror(err), err);
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!g_file_set_contents(req->filename, buffer, -1, NULL)) {
 | 
				
			||||||
 | 
					        g_critical("Failed to write certificate %s",
 | 
				
			||||||
 | 
					                   req->filename);
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    req->crt = crt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_tls_write_cert_chain(const char *filename,
 | 
				
			||||||
 | 
					                               gnutls_x509_crt_t *certs,
 | 
				
			||||||
 | 
					                               size_t ncerts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					    size_t capacity = 1024, offset = 0;
 | 
				
			||||||
 | 
					    char *buffer = g_new0(char, capacity);
 | 
				
			||||||
 | 
					    int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < ncerts; i++) {
 | 
				
			||||||
 | 
					        size_t len = capacity - offset;
 | 
				
			||||||
 | 
					    retry:
 | 
				
			||||||
 | 
					        err = gnutls_x509_crt_export(certs[i], GNUTLS_X509_FMT_PEM,
 | 
				
			||||||
 | 
					                                     buffer + offset, &len);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            if (err == GNUTLS_E_SHORT_MEMORY_BUFFER) {
 | 
				
			||||||
 | 
					                buffer = g_renew(char, buffer, offset + len);
 | 
				
			||||||
 | 
					                capacity = offset + len;
 | 
				
			||||||
 | 
					                goto retry;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            g_critical("Failed to export certificate chain %s: %d",
 | 
				
			||||||
 | 
					                       gnutls_strerror(err), err);
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        offset += len;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!g_file_set_contents(filename, buffer, offset, NULL)) {
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_tls_discard_cert(QCryptoTLSTestCertReq *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!req->crt) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gnutls_x509_crt_deinit(req->crt);
 | 
				
			||||||
 | 
					    req->crt = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (getenv("QEMU_TEST_DEBUG_CERTS") == NULL) {
 | 
				
			||||||
 | 
					        unlink(req->filename);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */
 | 
				
			||||||
							
								
								
									
										133
									
								
								tests/crypto-tls-x509-helpers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								tests/crypto-tls-x509-helpers.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,133 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2.1 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library.  If not, see
 | 
				
			||||||
 | 
					 * <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Daniel P. Berrange <berrange@redhat.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <gnutls/gnutls.h>
 | 
				
			||||||
 | 
					#include <gnutls/x509.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <gnutls/gnutls.h>
 | 
				
			||||||
 | 
					#include <gnutls/x509.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !(defined WIN32) && \
 | 
				
			||||||
 | 
					    defined(CONFIG_TASN1) && \
 | 
				
			||||||
 | 
					    defined(LIBGNUTLS_VERSION_NUMBER) && \
 | 
				
			||||||
 | 
					    (LIBGNUTLS_VERSION_NUMBER >= 0x020600)
 | 
				
			||||||
 | 
					# define QCRYPTO_HAVE_TLS_TEST_SUPPORT
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
 | 
				
			||||||
 | 
					# include <libtasn1.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# include "qemu-common.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This contains parameter about how to generate
 | 
				
			||||||
 | 
					 * certificates.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct QCryptoTLSTestCertReq QCryptoTLSTestCertReq;
 | 
				
			||||||
 | 
					struct QCryptoTLSTestCertReq {
 | 
				
			||||||
 | 
					    gnutls_x509_crt_t crt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *filename;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Identifying information */
 | 
				
			||||||
 | 
					    const char *country;
 | 
				
			||||||
 | 
					    const char *cn;
 | 
				
			||||||
 | 
					    const char *altname1;
 | 
				
			||||||
 | 
					    const char *altname2;
 | 
				
			||||||
 | 
					    const char *ipaddr1;
 | 
				
			||||||
 | 
					    const char *ipaddr2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Basic constraints */
 | 
				
			||||||
 | 
					    bool basicConstraintsEnable;
 | 
				
			||||||
 | 
					    bool basicConstraintsCritical;
 | 
				
			||||||
 | 
					    bool basicConstraintsIsCA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Key usage */
 | 
				
			||||||
 | 
					    bool keyUsageEnable;
 | 
				
			||||||
 | 
					    bool keyUsageCritical;
 | 
				
			||||||
 | 
					    int keyUsageValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Key purpose (aka Extended key usage) */
 | 
				
			||||||
 | 
					    bool keyPurposeEnable;
 | 
				
			||||||
 | 
					    bool keyPurposeCritical;
 | 
				
			||||||
 | 
					    const char *keyPurposeOID1;
 | 
				
			||||||
 | 
					    const char *keyPurposeOID2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* zero for current time, or non-zero for hours from now */
 | 
				
			||||||
 | 
					    int start_offset;
 | 
				
			||||||
 | 
					    /* zero for 24 hours from now, or non-zero for hours from now */
 | 
				
			||||||
 | 
					    int expire_offset;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_tls_generate_cert(QCryptoTLSTestCertReq *req,
 | 
				
			||||||
 | 
					                            gnutls_x509_crt_t ca);
 | 
				
			||||||
 | 
					void test_tls_write_cert_chain(const char *filename,
 | 
				
			||||||
 | 
					                               gnutls_x509_crt_t *certs,
 | 
				
			||||||
 | 
					                               size_t ncerts);
 | 
				
			||||||
 | 
					void test_tls_discard_cert(QCryptoTLSTestCertReq *req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_tls_init(const char *keyfile);
 | 
				
			||||||
 | 
					void test_tls_cleanup(const char *keyfile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# define TLS_CERT_REQ(varname, cavarname,                               \
 | 
				
			||||||
 | 
					                      country, commonname,                              \
 | 
				
			||||||
 | 
					                      altname1, altname2,                               \
 | 
				
			||||||
 | 
					                      ipaddr1, ipaddr2,                                 \
 | 
				
			||||||
 | 
					                      basicconsenable, basicconscritical, basicconsca,  \
 | 
				
			||||||
 | 
					                      keyusageenable, keyusagecritical, keyusagevalue,  \
 | 
				
			||||||
 | 
					                      keypurposeenable, keypurposecritical,             \
 | 
				
			||||||
 | 
					                      keypurposeoid1, keypurposeoid2,                   \
 | 
				
			||||||
 | 
					                      startoffset, endoffset)                           \
 | 
				
			||||||
 | 
					    static QCryptoTLSTestCertReq varname = {                            \
 | 
				
			||||||
 | 
					        NULL, WORKDIR #varname "-ctx.pem",                              \
 | 
				
			||||||
 | 
					        country, commonname, altname1, altname2,                        \
 | 
				
			||||||
 | 
					        ipaddr1, ipaddr2,                                               \
 | 
				
			||||||
 | 
					        basicconsenable, basicconscritical, basicconsca,                \
 | 
				
			||||||
 | 
					        keyusageenable, keyusagecritical, keyusagevalue,                \
 | 
				
			||||||
 | 
					        keypurposeenable, keypurposecritical,                           \
 | 
				
			||||||
 | 
					        keypurposeoid1, keypurposeoid2,                                 \
 | 
				
			||||||
 | 
					        startoffset, endoffset                                          \
 | 
				
			||||||
 | 
					    };                                                                  \
 | 
				
			||||||
 | 
					    test_tls_generate_cert(&varname, cavarname.crt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# define TLS_ROOT_REQ(varname,                                          \
 | 
				
			||||||
 | 
					                      country, commonname,                              \
 | 
				
			||||||
 | 
					                      altname1, altname2,                               \
 | 
				
			||||||
 | 
					                      ipaddr1, ipaddr2,                                 \
 | 
				
			||||||
 | 
					                      basicconsenable, basicconscritical, basicconsca,  \
 | 
				
			||||||
 | 
					                      keyusageenable, keyusagecritical, keyusagevalue,  \
 | 
				
			||||||
 | 
					                      keypurposeenable, keypurposecritical,             \
 | 
				
			||||||
 | 
					                      keypurposeoid1, keypurposeoid2,                   \
 | 
				
			||||||
 | 
					                      startoffset, endoffset)                           \
 | 
				
			||||||
 | 
					    static QCryptoTLSTestCertReq varname = {                            \
 | 
				
			||||||
 | 
					        NULL, WORKDIR #varname "-ctx.pem",                              \
 | 
				
			||||||
 | 
					        country, commonname, altname1, altname2,                        \
 | 
				
			||||||
 | 
					        ipaddr1, ipaddr2,                                               \
 | 
				
			||||||
 | 
					        basicconsenable, basicconscritical, basicconsca,                \
 | 
				
			||||||
 | 
					        keyusageenable, keyusagecritical, keyusagevalue,                \
 | 
				
			||||||
 | 
					        keypurposeenable, keypurposecritical,                           \
 | 
				
			||||||
 | 
					        keypurposeoid1, keypurposeoid2,                                 \
 | 
				
			||||||
 | 
					        startoffset, endoffset                                          \
 | 
				
			||||||
 | 
					    };                                                                  \
 | 
				
			||||||
 | 
					    test_tls_generate_cert(&varname, NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const ASN1_ARRAY_TYPE pkix_asn1_tab[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */
 | 
				
			||||||
							
								
								
									
										1104
									
								
								tests/pkix_asn1_tab.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1104
									
								
								tests/pkix_asn1_tab.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1
									
								
								tests/qapi-schema/enum-bad-prefix.err
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/qapi-schema/enum-bad-prefix.err
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					tests/qapi-schema/enum-bad-prefix.json:2: Enum 'MyEnum' requires a string for 'prefix'
 | 
				
			||||||
							
								
								
									
										1
									
								
								tests/qapi-schema/enum-bad-prefix.exit
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/qapi-schema/enum-bad-prefix.exit
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					1
 | 
				
			||||||
							
								
								
									
										2
									
								
								tests/qapi-schema/enum-bad-prefix.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/qapi-schema/enum-bad-prefix.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					# The prefix must be a string type
 | 
				
			||||||
 | 
					{ 'enum': 'MyEnum', 'data': [ 'one' ], 'prefix': [ 'fish' ] }
 | 
				
			||||||
							
								
								
									
										0
									
								
								tests/qapi-schema/enum-bad-prefix.out
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/qapi-schema/enum-bad-prefix.out
									
									
									
									
									
										Normal file
									
								
							@ -6,6 +6,11 @@
 | 
				
			|||||||
{ 'struct': 'NestedEnumsOne',
 | 
					{ 'struct': 'NestedEnumsOne',
 | 
				
			||||||
  'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
 | 
					  'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# for testing override of default naming heuristic
 | 
				
			||||||
 | 
					{ 'enum': 'QEnumTwo',
 | 
				
			||||||
 | 
					  'prefix': 'QENUM_TWO',
 | 
				
			||||||
 | 
					  'data': [ 'value1', 'value2' ] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# for testing nested structs
 | 
					# for testing nested structs
 | 
				
			||||||
{ 'struct': 'UserDefOne',
 | 
					{ 'struct': 'UserDefOne',
 | 
				
			||||||
  'base': 'UserDefZero',        # intentional forward reference
 | 
					  'base': 'UserDefZero',        # intentional forward reference
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
[OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]),
 | 
					[OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]),
 | 
				
			||||||
 OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
 | 
					 OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
 | 
				
			||||||
 | 
					 OrderedDict([('enum', 'QEnumTwo'), ('prefix', 'QENUM_TWO'), ('data', ['value1', 'value2'])]),
 | 
				
			||||||
 OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]),
 | 
					 OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]),
 | 
				
			||||||
 OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
 | 
					 OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
 | 
				
			||||||
 OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]),
 | 
					 OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]),
 | 
				
			||||||
@ -33,6 +34,7 @@
 | 
				
			|||||||
 OrderedDict([('event', '__ORG.QEMU_X-EVENT'), ('data', '__org.qemu_x-Struct')]),
 | 
					 OrderedDict([('event', '__ORG.QEMU_X-EVENT'), ('data', '__org.qemu_x-Struct')]),
 | 
				
			||||||
 OrderedDict([('command', '__org.qemu_x-command'), ('data', OrderedDict([('a', ['__org.qemu_x-Enum']), ('b', ['__org.qemu_x-Struct']), ('c', '__org.qemu_x-Union2'), ('d', '__org.qemu_x-Alt')])), ('returns', '__org.qemu_x-Union1')])]
 | 
					 OrderedDict([('command', '__org.qemu_x-command'), ('data', OrderedDict([('a', ['__org.qemu_x-Enum']), ('b', ['__org.qemu_x-Struct']), ('c', '__org.qemu_x-Union2'), ('d', '__org.qemu_x-Alt')])), ('returns', '__org.qemu_x-Union1')])]
 | 
				
			||||||
[{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']},
 | 
					[{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']},
 | 
				
			||||||
 | 
					 {'enum_name': 'QEnumTwo', 'enum_values': ['value1', 'value2']},
 | 
				
			||||||
 {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']},
 | 
					 {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']},
 | 
				
			||||||
 {'enum_name': 'UserDefAlternateKind', 'enum_values': None},
 | 
					 {'enum_name': 'UserDefAlternateKind', 'enum_values': None},
 | 
				
			||||||
 {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None},
 | 
					 {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None},
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										731
									
								
								tests/test-crypto-tlscredsx509.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										731
									
								
								tests/test-crypto-tlscredsx509.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,731 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2.1 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library.  If not, see
 | 
				
			||||||
 | 
					 * <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Daniel P. Berrange <berrange@redhat.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "config-host.h"
 | 
				
			||||||
 | 
					#include "crypto-tls-x509-helpers.h"
 | 
				
			||||||
 | 
					#include "crypto/tlscredsx509.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define WORKDIR "tests/test-crypto-tlscredsx509-work/"
 | 
				
			||||||
 | 
					#define KEYFILE WORKDIR "key-ctx.pem"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct QCryptoTLSCredsTestData {
 | 
				
			||||||
 | 
					    bool isServer;
 | 
				
			||||||
 | 
					    const char *cacrt;
 | 
				
			||||||
 | 
					    const char *crt;
 | 
				
			||||||
 | 
					    bool expectFail;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint,
 | 
				
			||||||
 | 
					                                              const char *certdir,
 | 
				
			||||||
 | 
					                                              Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Object *parent = object_get_objects_root();
 | 
				
			||||||
 | 
					    Object *creds = object_new_with_props(
 | 
				
			||||||
 | 
					        TYPE_QCRYPTO_TLS_CREDS_X509,
 | 
				
			||||||
 | 
					        parent,
 | 
				
			||||||
 | 
					        "testtlscreds",
 | 
				
			||||||
 | 
					        errp,
 | 
				
			||||||
 | 
					        "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
 | 
				
			||||||
 | 
					                     "server" : "client"),
 | 
				
			||||||
 | 
					        "dir", certdir,
 | 
				
			||||||
 | 
					        "verify-peer", "yes",
 | 
				
			||||||
 | 
					        "sanity-check", "yes",
 | 
				
			||||||
 | 
					        NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*errp) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return QCRYPTO_TLS_CREDS(creds);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This tests sanity checking of our own certificates
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The code being tested is used when TLS creds are created,
 | 
				
			||||||
 | 
					 * and aim to ensure QMEU has been configured with sane
 | 
				
			||||||
 | 
					 * certificates. This allows us to give much much much
 | 
				
			||||||
 | 
					 * clearer error messages to the admin when they misconfigure
 | 
				
			||||||
 | 
					 * things.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void test_tls_creds(const void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct QCryptoTLSCredsTestData *data =
 | 
				
			||||||
 | 
					        (struct QCryptoTLSCredsTestData *)opaque;
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *creds;
 | 
				
			||||||
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CERT_DIR "tests/test-crypto-tlscredsx509-certs/"
 | 
				
			||||||
 | 
					    mkdir(CERT_DIR, 0700);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
 | 
				
			||||||
 | 
					    if (data->isServer) {
 | 
				
			||||||
 | 
					        unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
 | 
				
			||||||
 | 
					        unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
 | 
				
			||||||
 | 
					        unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (access(data->cacrt, R_OK) == 0) {
 | 
				
			||||||
 | 
					        g_assert(link(data->cacrt,
 | 
				
			||||||
 | 
					                      CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (data->isServer) {
 | 
				
			||||||
 | 
					        if (access(data->crt, R_OK) == 0) {
 | 
				
			||||||
 | 
					            g_assert(link(data->crt,
 | 
				
			||||||
 | 
					                          CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        g_assert(link(KEYFILE,
 | 
				
			||||||
 | 
					                      CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (access(data->crt, R_OK) == 0) {
 | 
				
			||||||
 | 
					            g_assert(link(data->crt,
 | 
				
			||||||
 | 
					                          CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        g_assert(link(KEYFILE,
 | 
				
			||||||
 | 
					                      CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    creds = test_tls_creds_create(
 | 
				
			||||||
 | 
					        (data->isServer ?
 | 
				
			||||||
 | 
					         QCRYPTO_TLS_CREDS_ENDPOINT_SERVER :
 | 
				
			||||||
 | 
					         QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT),
 | 
				
			||||||
 | 
					        CERT_DIR,
 | 
				
			||||||
 | 
					        &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (data->expectFail) {
 | 
				
			||||||
 | 
					        error_free(err);
 | 
				
			||||||
 | 
					        g_assert(creds == NULL);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            g_printerr("Failed to generate creds: %s\n",
 | 
				
			||||||
 | 
					                       error_get_pretty(err));
 | 
				
			||||||
 | 
					            error_free(err);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        g_assert(creds != NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
 | 
				
			||||||
 | 
					    if (data->isServer) {
 | 
				
			||||||
 | 
					        unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
 | 
				
			||||||
 | 
					        unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
 | 
				
			||||||
 | 
					        unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    rmdir(CERT_DIR);
 | 
				
			||||||
 | 
					    if (creds) {
 | 
				
			||||||
 | 
					        object_unparent(OBJECT(creds));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    module_call_init(MODULE_INIT_QOM);
 | 
				
			||||||
 | 
					    g_test_init(&argc, &argv, NULL);
 | 
				
			||||||
 | 
					    setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mkdir(WORKDIR, 0700);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_init(KEYFILE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# define TLS_TEST_REG(name, isServer, caCrt, crt, expectFail)           \
 | 
				
			||||||
 | 
					    struct QCryptoTLSCredsTestData name = {                             \
 | 
				
			||||||
 | 
					        isServer, caCrt, crt, expectFail                                \
 | 
				
			||||||
 | 
					    };                                                                  \
 | 
				
			||||||
 | 
					    g_test_add_data_func("/qcrypto/tlscredsx509/" # name,               \
 | 
				
			||||||
 | 
					                         &name, test_tls_creds);                        \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* A perfect CA, perfect client & perfect server */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Basic:CA:critical */
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu CA", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercertreq, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcertreq, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_TEST_REG(perfectserver, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercertreq.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(perfectclient, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcertreq.filename, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Some other CAs which are good */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Basic:CA:critical */
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacert1req,
 | 
				
			||||||
 | 
					                 "UK", "qemu CA 1", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert1req, cacert1req,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Basic:CA:not-critical */
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacert2req,
 | 
				
			||||||
 | 
					                 "UK", "qemu CA 2", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, false, true,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert2req, cacert2req,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Key usage:cert-sign:critical */
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacert3req,
 | 
				
			||||||
 | 
					                 "UK", "qemu CA 3", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert3req, cacert3req,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodca1, true,
 | 
				
			||||||
 | 
					                 cacert1req.filename, servercert1req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodca2, true,
 | 
				
			||||||
 | 
					                 cacert2req.filename, servercert2req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodca3, true,
 | 
				
			||||||
 | 
					                 cacert3req.filename, servercert3req.filename, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Now some bad certs */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Key usage:dig-sig:not-critical */
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacert4req,
 | 
				
			||||||
 | 
					                 "UK", "qemu CA 4", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, false, GNUTLS_KEY_DIGITAL_SIGNATURE,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert4req, cacert4req,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* no-basic */
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacert5req,
 | 
				
			||||||
 | 
					                 "UK", "qemu CA 5", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 false, false, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert5req, cacert5req,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* Key usage:dig-sig:critical */
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacert6req,
 | 
				
			||||||
 | 
					                 "UK", "qemu CA 6", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_DIGITAL_SIGNATURE,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert6req, cacert6req,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Technically a CA cert with basic constraints
 | 
				
			||||||
 | 
					     * key purpose == key signing + non-critical should
 | 
				
			||||||
 | 
					     * be rejected. GNUTLS < 3.1 does not reject it and
 | 
				
			||||||
 | 
					     * we don't anticipate them changing this behaviour
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    TLS_TEST_REG(badca1, true, cacert4req.filename, servercert4req.filename,
 | 
				
			||||||
 | 
					                (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR >= 1) ||
 | 
				
			||||||
 | 
					                GNUTLS_VERSION_MAJOR > 3);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(badca2, true,
 | 
				
			||||||
 | 
					                 cacert5req.filename, servercert5req.filename, true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(badca3, true,
 | 
				
			||||||
 | 
					                 cacert6req.filename, servercert6req.filename, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Various good servers */
 | 
				
			||||||
 | 
					    /* no usage or purpose */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert7req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* usage:cert-sign+dig-sig+encipher:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert8req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT |
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* usage:cert-sign:not-critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert9req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, false, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* purpose:server:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert10req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* purpose:server:not-critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert11req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 true, false, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* purpose:client+server:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert12req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* purpose:client+server:not-critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert13req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 true, false,
 | 
				
			||||||
 | 
					                 GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodserver1, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercert7req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodserver2, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercert8req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodserver3, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercert9req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodserver4, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercert10req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodserver5, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercert11req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodserver6, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercert12req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodserver7, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercert13req.filename, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Bad servers */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* usage:cert-sign:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert14req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* purpose:client:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert15req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* usage: none:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercert16req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true, 0,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_TEST_REG(badserver1, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercert14req.filename, true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(badserver2, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercert15req.filename, true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(badserver3, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercert16req.filename, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Various good clients */
 | 
				
			||||||
 | 
					    /* no usage or purpose */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcert1req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* usage:cert-sign+dig-sig+encipher:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcert2req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT |
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* usage:cert-sign:not-critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcert3req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, false, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* purpose:client:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcert4req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* purpose:client:not-critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcert5req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 true, false, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* purpose:client+client:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcert6req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* purpose:client+client:not-critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcert7req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 true, false,
 | 
				
			||||||
 | 
					                 GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodclient1, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcert1req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodclient2, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcert2req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodclient3, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcert3req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodclient4, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcert4req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodclient5, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcert5req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodclient6, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcert6req.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(goodclient7, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcert7req.filename, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Bad clients */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* usage:cert-sign:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcert8req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* purpose:client:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcert9req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* usage: none:critical */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcert10req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true, 0,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_TEST_REG(badclient1, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcert8req.filename, true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(badclient2, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcert9req.filename, true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(badclient3, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcert10req.filename, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Expired stuff */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacertexpreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, -1);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercertexpreq, cacertexpreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercertexp1req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, -1);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcertexp1req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
 | 
				
			||||||
 | 
					                 0, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_TEST_REG(expired1, true,
 | 
				
			||||||
 | 
					                 cacertexpreq.filename, servercertexpreq.filename, true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(expired2, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercertexp1req.filename, true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(expired3, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcertexp1req.filename, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Not activated stuff */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacertnewreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 1, 2);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercertnewreq, cacertnewreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercertnew1req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 1, 2);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcertnew1req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
 | 
				
			||||||
 | 
					                 1, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_TEST_REG(inactive1, true,
 | 
				
			||||||
 | 
					                 cacertnewreq.filename, servercertnewreq.filename, true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(inactive2, true,
 | 
				
			||||||
 | 
					                 cacertreq.filename, servercertnew1req.filename, true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(inactive3, false,
 | 
				
			||||||
 | 
					                 cacertreq.filename, clientcertnew1req.filename, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacertrootreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu root", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(cacertlevel1areq, cacertrootreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu level 1a", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(cacertlevel1breq, cacertrootreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu level 1b", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(cacertlevel2areq, cacertlevel1areq,
 | 
				
			||||||
 | 
					                 "UK", "qemu level 2a", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercertlevel3areq, cacertlevel2areq,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq,
 | 
				
			||||||
 | 
					                 "UK", "qemu client level 2b", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gnutls_x509_crt_t certchain[] = {
 | 
				
			||||||
 | 
					        cacertrootreq.crt,
 | 
				
			||||||
 | 
					        cacertlevel1areq.crt,
 | 
				
			||||||
 | 
					        cacertlevel1breq.crt,
 | 
				
			||||||
 | 
					        cacertlevel2areq.crt,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_write_cert_chain(WORKDIR "cacertchain-ctx.pem",
 | 
				
			||||||
 | 
					                              certchain,
 | 
				
			||||||
 | 
					                              G_N_ELEMENTS(certchain));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_TEST_REG(chain1, true,
 | 
				
			||||||
 | 
					                 WORKDIR "cacertchain-ctx.pem",
 | 
				
			||||||
 | 
					                 servercertlevel3areq.filename, false);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(chain2, false,
 | 
				
			||||||
 | 
					                 WORKDIR "cacertchain-ctx.pem",
 | 
				
			||||||
 | 
					                 clientcertlevel2breq.filename, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Some missing certs - first two are fatal, the last
 | 
				
			||||||
 | 
					     * is ok
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    TLS_TEST_REG(missingca, true,
 | 
				
			||||||
 | 
					                 "cacertdoesnotexist.pem",
 | 
				
			||||||
 | 
					                 servercert1req.filename, true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(missingserver, true,
 | 
				
			||||||
 | 
					                 cacert1req.filename,
 | 
				
			||||||
 | 
					                 "servercertdoesnotexist.pem", true);
 | 
				
			||||||
 | 
					    TLS_TEST_REG(missingclient, false,
 | 
				
			||||||
 | 
					                 cacert1req.filename,
 | 
				
			||||||
 | 
					                 "clientcertdoesnotexist.pem", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = g_test_run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacert1req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacert2req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacert3req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacert4req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacert5req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacert6req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercertreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert1req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert2req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert3req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert4req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert5req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert6req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert7req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert8req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert9req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert10req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert11req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert12req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert13req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert14req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert15req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercert16req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcertreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcert1req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcert2req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcert3req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcert4req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcert5req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcert6req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcert7req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcert8req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcert9req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcert10req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertexpreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercertexpreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercertexp1req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcertexp1req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertnewreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercertnewreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercertnew1req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcertnew1req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertrootreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertlevel1areq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertlevel1breq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertlevel2areq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercertlevel3areq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcertlevel2breq);
 | 
				
			||||||
 | 
					    unlink(WORKDIR "cacertchain-ctx.pem");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_cleanup(KEYFILE);
 | 
				
			||||||
 | 
					    rmdir(WORKDIR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return EXIT_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */
 | 
				
			||||||
							
								
								
									
										535
									
								
								tests/test-crypto-tlssession.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										535
									
								
								tests/test-crypto-tlssession.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,535 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License as published by the Free Software Foundation; either
 | 
				
			||||||
 | 
					 * version 2.1 of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * Lesser General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License along with this library.  If not, see
 | 
				
			||||||
 | 
					 * <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Daniel P. Berrange <berrange@redhat.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "config-host.h"
 | 
				
			||||||
 | 
					#include "crypto-tls-x509-helpers.h"
 | 
				
			||||||
 | 
					#include "crypto/tlscredsx509.h"
 | 
				
			||||||
 | 
					#include "crypto/tlssession.h"
 | 
				
			||||||
 | 
					#include "qom/object_interfaces.h"
 | 
				
			||||||
 | 
					#include "qemu/sockets.h"
 | 
				
			||||||
 | 
					#include "qemu/acl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define WORKDIR "tests/test-crypto-tlssession-work/"
 | 
				
			||||||
 | 
					#define KEYFILE WORKDIR "key-ctx.pem"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct QCryptoTLSSessionTestData {
 | 
				
			||||||
 | 
					    const char *servercacrt;
 | 
				
			||||||
 | 
					    const char *clientcacrt;
 | 
				
			||||||
 | 
					    const char *servercrt;
 | 
				
			||||||
 | 
					    const char *clientcrt;
 | 
				
			||||||
 | 
					    bool expectServerFail;
 | 
				
			||||||
 | 
					    bool expectClientFail;
 | 
				
			||||||
 | 
					    const char *hostname;
 | 
				
			||||||
 | 
					    const char *const *wildcards;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t testWrite(const char *buf, size_t len, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int *fd = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return write(*fd, buf, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t testRead(char *buf, size_t len, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int *fd = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return read(*fd, buf, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint,
 | 
				
			||||||
 | 
					                                              const char *certdir,
 | 
				
			||||||
 | 
					                                              Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					    Object *parent = object_get_objects_root();
 | 
				
			||||||
 | 
					    Object *creds = object_new_with_props(
 | 
				
			||||||
 | 
					        TYPE_QCRYPTO_TLS_CREDS_X509,
 | 
				
			||||||
 | 
					        parent,
 | 
				
			||||||
 | 
					        (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
 | 
				
			||||||
 | 
					         "testtlscredsserver" : "testtlscredsclient"),
 | 
				
			||||||
 | 
					        &err,
 | 
				
			||||||
 | 
					        "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
 | 
				
			||||||
 | 
					                     "server" : "client"),
 | 
				
			||||||
 | 
					        "dir", certdir,
 | 
				
			||||||
 | 
					        "verify-peer", "yes",
 | 
				
			||||||
 | 
					        /* We skip initial sanity checks here because we
 | 
				
			||||||
 | 
					         * want to make sure that problems are being
 | 
				
			||||||
 | 
					         * detected at the TLS session validation stage,
 | 
				
			||||||
 | 
					         * and the test-crypto-tlscreds test already
 | 
				
			||||||
 | 
					         * validate the sanity check code.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        "sanity-check", "no",
 | 
				
			||||||
 | 
					        NULL
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (err) {
 | 
				
			||||||
 | 
					        error_propagate(errp, err);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return QCRYPTO_TLS_CREDS(creds);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This tests validation checking of peer certificates
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is replicating the checks that are done for an
 | 
				
			||||||
 | 
					 * active TLS session after handshake completes. To
 | 
				
			||||||
 | 
					 * simulate that we create our TLS contexts, skipping
 | 
				
			||||||
 | 
					 * sanity checks. We then get a socketpair, and
 | 
				
			||||||
 | 
					 * initiate a TLS session across them. Finally do
 | 
				
			||||||
 | 
					 * do actual cert validation tests
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void test_crypto_tls_session(const void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct QCryptoTLSSessionTestData *data =
 | 
				
			||||||
 | 
					        (struct QCryptoTLSSessionTestData *)opaque;
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *clientCreds;
 | 
				
			||||||
 | 
					    QCryptoTLSCreds *serverCreds;
 | 
				
			||||||
 | 
					    QCryptoTLSSession *clientSess = NULL;
 | 
				
			||||||
 | 
					    QCryptoTLSSession *serverSess = NULL;
 | 
				
			||||||
 | 
					    qemu_acl *acl;
 | 
				
			||||||
 | 
					    const char * const *wildcards;
 | 
				
			||||||
 | 
					    int channel[2];
 | 
				
			||||||
 | 
					    bool clientShake = false;
 | 
				
			||||||
 | 
					    bool serverShake = false;
 | 
				
			||||||
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* We'll use this for our fake client-server connection */
 | 
				
			||||||
 | 
					    ret = socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
 | 
				
			||||||
 | 
					    g_assert(ret == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * We have an evil loop to do the handshake in a single
 | 
				
			||||||
 | 
					     * thread, so we need these non-blocking to avoid deadlock
 | 
				
			||||||
 | 
					     * of ourselves
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    qemu_set_nonblock(channel[0]);
 | 
				
			||||||
 | 
					    qemu_set_nonblock(channel[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/"
 | 
				
			||||||
 | 
					#define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/"
 | 
				
			||||||
 | 
					    mkdir(CLIENT_CERT_DIR, 0700);
 | 
				
			||||||
 | 
					    mkdir(SERVER_CERT_DIR, 0700);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
 | 
				
			||||||
 | 
					    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
 | 
				
			||||||
 | 
					    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
 | 
				
			||||||
 | 
					    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
 | 
				
			||||||
 | 
					    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_assert(link(data->servercacrt,
 | 
				
			||||||
 | 
					                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
 | 
				
			||||||
 | 
					    g_assert(link(data->servercrt,
 | 
				
			||||||
 | 
					                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0);
 | 
				
			||||||
 | 
					    g_assert(link(KEYFILE,
 | 
				
			||||||
 | 
					                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_assert(link(data->clientcacrt,
 | 
				
			||||||
 | 
					                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
 | 
				
			||||||
 | 
					    g_assert(link(data->clientcrt,
 | 
				
			||||||
 | 
					                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0);
 | 
				
			||||||
 | 
					    g_assert(link(KEYFILE,
 | 
				
			||||||
 | 
					                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clientCreds = test_tls_creds_create(
 | 
				
			||||||
 | 
					        QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
 | 
				
			||||||
 | 
					        CLIENT_CERT_DIR,
 | 
				
			||||||
 | 
					        &err);
 | 
				
			||||||
 | 
					    g_assert(clientCreds != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    serverCreds = test_tls_creds_create(
 | 
				
			||||||
 | 
					        QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
 | 
				
			||||||
 | 
					        SERVER_CERT_DIR,
 | 
				
			||||||
 | 
					        &err);
 | 
				
			||||||
 | 
					    g_assert(serverCreds != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    acl = qemu_acl_init("tlssessionacl");
 | 
				
			||||||
 | 
					    qemu_acl_reset(acl);
 | 
				
			||||||
 | 
					    wildcards = data->wildcards;
 | 
				
			||||||
 | 
					    while (wildcards && *wildcards) {
 | 
				
			||||||
 | 
					        qemu_acl_append(acl, 0, *wildcards);
 | 
				
			||||||
 | 
					        wildcards++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Now the real part of the test, setup the sessions */
 | 
				
			||||||
 | 
					    clientSess = qcrypto_tls_session_new(
 | 
				
			||||||
 | 
					        clientCreds, data->hostname, NULL,
 | 
				
			||||||
 | 
					        QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, &err);
 | 
				
			||||||
 | 
					    serverSess = qcrypto_tls_session_new(
 | 
				
			||||||
 | 
					        serverCreds, NULL,
 | 
				
			||||||
 | 
					        data->wildcards ? "tlssessionacl" : NULL,
 | 
				
			||||||
 | 
					        QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_assert(clientSess != NULL);
 | 
				
			||||||
 | 
					    g_assert(serverSess != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* For handshake to work, we need to set the I/O callbacks
 | 
				
			||||||
 | 
					     * to read/write over the socketpair
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    qcrypto_tls_session_set_callbacks(serverSess,
 | 
				
			||||||
 | 
					                                      testWrite, testRead,
 | 
				
			||||||
 | 
					                                      &channel[0]);
 | 
				
			||||||
 | 
					    qcrypto_tls_session_set_callbacks(clientSess,
 | 
				
			||||||
 | 
					                                      testWrite, testRead,
 | 
				
			||||||
 | 
					                                      &channel[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Finally we loop around & around doing handshake on each
 | 
				
			||||||
 | 
					     * session until we get an error, or the handshake completes.
 | 
				
			||||||
 | 
					     * This relies on the socketpair being nonblocking to avoid
 | 
				
			||||||
 | 
					     * deadlocking ourselves upon handshake
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        int rv;
 | 
				
			||||||
 | 
					        if (!serverShake) {
 | 
				
			||||||
 | 
					            rv = qcrypto_tls_session_handshake(serverSess,
 | 
				
			||||||
 | 
					                                               &err);
 | 
				
			||||||
 | 
					            g_assert(rv >= 0);
 | 
				
			||||||
 | 
					            if (qcrypto_tls_session_get_handshake_status(serverSess) ==
 | 
				
			||||||
 | 
					                QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
 | 
				
			||||||
 | 
					                serverShake = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!clientShake) {
 | 
				
			||||||
 | 
					            rv = qcrypto_tls_session_handshake(clientSess,
 | 
				
			||||||
 | 
					                                               &err);
 | 
				
			||||||
 | 
					            g_assert(rv >= 0);
 | 
				
			||||||
 | 
					            if (qcrypto_tls_session_get_handshake_status(clientSess) ==
 | 
				
			||||||
 | 
					                QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
 | 
				
			||||||
 | 
					                clientShake = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } while (!clientShake && !serverShake);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Finally make sure the server validation does what
 | 
				
			||||||
 | 
					     * we were expecting
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (qcrypto_tls_session_check_credentials(serverSess, &err) < 0) {
 | 
				
			||||||
 | 
					        g_assert(data->expectServerFail);
 | 
				
			||||||
 | 
					        error_free(err);
 | 
				
			||||||
 | 
					        err = NULL;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        g_assert(!data->expectServerFail);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * And the same for the client validation check
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (qcrypto_tls_session_check_credentials(clientSess, &err) < 0) {
 | 
				
			||||||
 | 
					        g_assert(data->expectClientFail);
 | 
				
			||||||
 | 
					        error_free(err);
 | 
				
			||||||
 | 
					        err = NULL;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        g_assert(!data->expectClientFail);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
 | 
				
			||||||
 | 
					    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
 | 
				
			||||||
 | 
					    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
 | 
				
			||||||
 | 
					    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
 | 
				
			||||||
 | 
					    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rmdir(CLIENT_CERT_DIR);
 | 
				
			||||||
 | 
					    rmdir(SERVER_CERT_DIR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    object_unparent(OBJECT(serverCreds));
 | 
				
			||||||
 | 
					    object_unparent(OBJECT(clientCreds));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qcrypto_tls_session_free(serverSess);
 | 
				
			||||||
 | 
					    qcrypto_tls_session_free(clientSess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    close(channel[0]);
 | 
				
			||||||
 | 
					    close(channel[1]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    module_call_init(MODULE_INIT_QOM);
 | 
				
			||||||
 | 
					    g_test_init(&argc, &argv, NULL);
 | 
				
			||||||
 | 
					    setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mkdir(WORKDIR, 0700);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_init(KEYFILE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# define TEST_SESS_REG(name, caCrt,                                     \
 | 
				
			||||||
 | 
					                       serverCrt, clientCrt,                            \
 | 
				
			||||||
 | 
					                       expectServerFail, expectClientFail,              \
 | 
				
			||||||
 | 
					                       hostname, wildcards)                             \
 | 
				
			||||||
 | 
					    struct QCryptoTLSSessionTestData name = {                           \
 | 
				
			||||||
 | 
					        caCrt, caCrt, serverCrt, clientCrt,                             \
 | 
				
			||||||
 | 
					        expectServerFail, expectClientFail,                             \
 | 
				
			||||||
 | 
					        hostname, wildcards                                             \
 | 
				
			||||||
 | 
					    };                                                                  \
 | 
				
			||||||
 | 
					    g_test_add_data_func("/qcrypto/tlssession/" # name,                 \
 | 
				
			||||||
 | 
					                         &name, test_crypto_tls_session);               \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# define TEST_SESS_REG_EXT(name, serverCaCrt, clientCaCrt,              \
 | 
				
			||||||
 | 
					                           serverCrt, clientCrt,                        \
 | 
				
			||||||
 | 
					                           expectServerFail, expectClientFail,          \
 | 
				
			||||||
 | 
					                           hostname, wildcards)                         \
 | 
				
			||||||
 | 
					    struct QCryptoTLSSessionTestData name = {                           \
 | 
				
			||||||
 | 
					        serverCaCrt, clientCaCrt, serverCrt, clientCrt,                 \
 | 
				
			||||||
 | 
					        expectServerFail, expectClientFail,                             \
 | 
				
			||||||
 | 
					        hostname, wildcards                                             \
 | 
				
			||||||
 | 
					    };                                                                  \
 | 
				
			||||||
 | 
					    g_test_add_data_func("/qcrypto/tlssession/" # name,                 \
 | 
				
			||||||
 | 
					                         &name, test_crypto_tls_session);               \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* A perfect CA, perfect client & perfect server */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Basic:CA:critical */
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu CA", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(altcacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu CA 1", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 false, false, 0,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercertreq, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcertreq, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcertaltreq, altcacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TEST_SESS_REG(basicca, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertreq.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, false, "qemu.org", NULL);
 | 
				
			||||||
 | 
					    TEST_SESS_REG_EXT(differentca, cacertreq.filename,
 | 
				
			||||||
 | 
					                      altcacertreq.filename, servercertreq.filename,
 | 
				
			||||||
 | 
					                      clientcertaltreq.filename, true, true, "qemu.org", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* When an altname is set, the CN is ignored, so it must be duplicated
 | 
				
			||||||
 | 
					     * as an altname for it to match */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercertalt1req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", "www.qemu.org", "qemu.org",
 | 
				
			||||||
 | 
					                 "192.168.122.1", "fec0::dead:beaf",
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    /* This intentionally doesn't replicate */
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercertalt2req, cacertreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", "www.qemu.org", "wiki.qemu.org",
 | 
				
			||||||
 | 
					                 "192.168.122.1", "fec0::dead:beaf",
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TEST_SESS_REG(altname1, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertalt1req.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, false, "qemu.org", NULL);
 | 
				
			||||||
 | 
					    TEST_SESS_REG(altname2, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertalt1req.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, false, "www.qemu.org", NULL);
 | 
				
			||||||
 | 
					    TEST_SESS_REG(altname3, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertalt1req.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, true, "wiki.qemu.org", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TEST_SESS_REG(altname4, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertalt2req.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, true, "qemu.org", NULL);
 | 
				
			||||||
 | 
					    TEST_SESS_REG(altname5, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertalt2req.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, false, "www.qemu.org", NULL);
 | 
				
			||||||
 | 
					    TEST_SESS_REG(altname6, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertalt2req.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, false, "wiki.qemu.org", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *const wildcards1[] = {
 | 
				
			||||||
 | 
					        "C=UK,CN=dogfood",
 | 
				
			||||||
 | 
					        NULL,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const char *const wildcards2[] = {
 | 
				
			||||||
 | 
					        "C=UK,CN=qemu",
 | 
				
			||||||
 | 
					        NULL,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const char *const wildcards3[] = {
 | 
				
			||||||
 | 
					        "C=UK,CN=dogfood",
 | 
				
			||||||
 | 
					        "C=UK,CN=qemu",
 | 
				
			||||||
 | 
					        NULL,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const char *const wildcards4[] = {
 | 
				
			||||||
 | 
					        "C=UK,CN=qemustuff",
 | 
				
			||||||
 | 
					        NULL,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const char *const wildcards5[] = {
 | 
				
			||||||
 | 
					        "C=UK,CN=qemu*",
 | 
				
			||||||
 | 
					        NULL,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const char *const wildcards6[] = {
 | 
				
			||||||
 | 
					        "C=UK,CN=*emu*",
 | 
				
			||||||
 | 
					        NULL,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TEST_SESS_REG(wildcard1, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertreq.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  true, false, "qemu.org", wildcards1);
 | 
				
			||||||
 | 
					    TEST_SESS_REG(wildcard2, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertreq.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, false, "qemu.org", wildcards2);
 | 
				
			||||||
 | 
					    TEST_SESS_REG(wildcard3, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertreq.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, false, "qemu.org", wildcards3);
 | 
				
			||||||
 | 
					    TEST_SESS_REG(wildcard4, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertreq.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  true, false, "qemu.org", wildcards4);
 | 
				
			||||||
 | 
					    TEST_SESS_REG(wildcard5, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertreq.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, false, "qemu.org", wildcards5);
 | 
				
			||||||
 | 
					    TEST_SESS_REG(wildcard6, cacertreq.filename,
 | 
				
			||||||
 | 
					                  servercertreq.filename, clientcertreq.filename,
 | 
				
			||||||
 | 
					                  false, false, "qemu.org", wildcards6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TLS_ROOT_REQ(cacertrootreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu root", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(cacertlevel1areq, cacertrootreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu level 1a", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(cacertlevel1breq, cacertrootreq,
 | 
				
			||||||
 | 
					                 "UK", "qemu level 1b", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(cacertlevel2areq, cacertlevel1areq,
 | 
				
			||||||
 | 
					                 "UK", "qemu level 2a", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, true,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
 | 
				
			||||||
 | 
					                 false, false, NULL, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(servercertlevel3areq, cacertlevel2areq,
 | 
				
			||||||
 | 
					                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					    TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq,
 | 
				
			||||||
 | 
					                 "UK", "qemu client level 2b", NULL, NULL, NULL, NULL,
 | 
				
			||||||
 | 
					                 true, true, false,
 | 
				
			||||||
 | 
					                 true, true,
 | 
				
			||||||
 | 
					                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 | 
				
			||||||
 | 
					                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
 | 
				
			||||||
 | 
					                 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gnutls_x509_crt_t certchain[] = {
 | 
				
			||||||
 | 
					        cacertrootreq.crt,
 | 
				
			||||||
 | 
					        cacertlevel1areq.crt,
 | 
				
			||||||
 | 
					        cacertlevel1breq.crt,
 | 
				
			||||||
 | 
					        cacertlevel2areq.crt,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_write_cert_chain(WORKDIR "cacertchain-sess.pem",
 | 
				
			||||||
 | 
					                              certchain,
 | 
				
			||||||
 | 
					                              G_N_ELEMENTS(certchain));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TEST_SESS_REG(cachain, WORKDIR "cacertchain-sess.pem",
 | 
				
			||||||
 | 
					                  servercertlevel3areq.filename, clientcertlevel2breq.filename,
 | 
				
			||||||
 | 
					                  false, false, "qemu.org", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = g_test_run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcertreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcertaltreq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercertreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercertalt1req);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercertalt2req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&altcacertreq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertrootreq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertlevel1areq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertlevel1breq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&cacertlevel2areq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&servercertlevel3areq);
 | 
				
			||||||
 | 
					    test_tls_discard_cert(&clientcertlevel2breq);
 | 
				
			||||||
 | 
					    unlink(WORKDIR "cacertchain-sess.pem");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_tls_cleanup(KEYFILE);
 | 
				
			||||||
 | 
					    rmdir(WORKDIR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return EXIT_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */
 | 
				
			||||||
							
								
								
									
										18
									
								
								trace-events
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								trace-events
									
									
									
									
									
								
							@ -1667,3 +1667,21 @@ alsa_no_frames(int state) "No frames available and ALSA state is %d"
 | 
				
			|||||||
# audio/ossaudio.c
 | 
					# audio/ossaudio.c
 | 
				
			||||||
oss_version(int version) "OSS version = %#x"
 | 
					oss_version(int version) "OSS version = %#x"
 | 
				
			||||||
oss_invalid_available_size(int size, int bufsize) "Invalid available size, size=%d bufsize=%d"
 | 
					oss_invalid_available_size(int size, int bufsize) "Invalid available size, size=%d bufsize=%d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# crypto/tlscreds.c
 | 
				
			||||||
 | 
					qcrypto_tls_creds_load_dh(void *creds, const char *filename) "TLS creds load DH creds=%p filename=%s"
 | 
				
			||||||
 | 
					qcrypto_tls_creds_get_path(void *creds, const char *filename, const char *path) "TLS creds path creds=%p filename=%s path=%s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# crypto/tlscredsanon.c
 | 
				
			||||||
 | 
					qcrypto_tls_creds_anon_load(void *creds, const char *dir) "TLS creds anon load creds=%p dir=%s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# crypto/tlscredsx509.c
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_load(void *creds, const char *dir) "TLS creds x509 load creds=%p dir=%s"
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_check_basic_constraints(void *creds, const char *file, int status) "TLS creds x509 check basic constraints creds=%p file=%s status=%d"
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_check_key_usage(void *creds, const char *file, int status, int usage, int critical) "TLS creds x509 check key usage creds=%p file=%s status=%d usage=%d critical=%d"
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_check_key_purpose(void *creds, const char *file, int status, const char *usage, int critical) "TLS creds x509 check key usage creds=%p file=%s status=%d usage=%s critical=%d"
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_load_cert(void *creds, int isServer, const char *file) "TLS creds x509 load cert creds=%p isServer=%d file=%s"
 | 
				
			||||||
 | 
					qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds x509 load cert list creds=%p file=%s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# crypto/tlssession.c
 | 
				
			||||||
 | 
					qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *aclname, int endpoint) "TLS session new session=%p creds=%p hostname=%s aclname=%s endpoint=%d"
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@ vnc-obj-y += vnc.o
 | 
				
			|||||||
vnc-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
 | 
					vnc-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
 | 
				
			||||||
vnc-obj-y += vnc-enc-tight.o vnc-palette.o
 | 
					vnc-obj-y += vnc-enc-tight.o vnc-palette.o
 | 
				
			||||||
vnc-obj-y += vnc-enc-zrle.o
 | 
					vnc-obj-y += vnc-enc-zrle.o
 | 
				
			||||||
vnc-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
 | 
					vnc-obj-y += vnc-auth-vencrypt.o
 | 
				
			||||||
vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
 | 
					vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
 | 
				
			||||||
vnc-obj-y += vnc-ws.o
 | 
					vnc-obj-y += vnc-ws.o
 | 
				
			||||||
vnc-obj-y += vnc-jobs.o
 | 
					vnc-obj-y += vnc-jobs.o
 | 
				
			||||||
 | 
				
			|||||||
@ -525,21 +525,24 @@ void start_auth_sasl(VncState *vs)
 | 
				
			|||||||
        goto authabort;
 | 
					        goto authabort;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					 | 
				
			||||||
    /* Inform SASL that we've got an external SSF layer from TLS/x509 */
 | 
					    /* Inform SASL that we've got an external SSF layer from TLS/x509 */
 | 
				
			||||||
    if (vs->auth == VNC_AUTH_VENCRYPT &&
 | 
					    if (vs->auth == VNC_AUTH_VENCRYPT &&
 | 
				
			||||||
        vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
 | 
					        vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
 | 
				
			||||||
        gnutls_cipher_algorithm_t cipher;
 | 
					        Error *local_err = NULL;
 | 
				
			||||||
 | 
					        int keysize;
 | 
				
			||||||
        sasl_ssf_t ssf;
 | 
					        sasl_ssf_t ssf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        cipher = gnutls_cipher_get(vs->tls.session);
 | 
					        keysize = qcrypto_tls_session_get_key_size(vs->tls,
 | 
				
			||||||
        if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
 | 
					                                                   &local_err);
 | 
				
			||||||
            VNC_DEBUG("%s", "cannot TLS get cipher size\n");
 | 
					        if (keysize < 0) {
 | 
				
			||||||
 | 
					            VNC_DEBUG("cannot TLS get cipher size: %s\n",
 | 
				
			||||||
 | 
					                      error_get_pretty(local_err));
 | 
				
			||||||
 | 
					            error_free(local_err);
 | 
				
			||||||
            sasl_dispose(&vs->sasl.conn);
 | 
					            sasl_dispose(&vs->sasl.conn);
 | 
				
			||||||
            vs->sasl.conn = NULL;
 | 
					            vs->sasl.conn = NULL;
 | 
				
			||||||
            goto authabort;
 | 
					            goto authabort;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        ssf *= 8; /* tls key size is bytes, sasl wants bits */
 | 
					        ssf = keysize * CHAR_BIT; /* tls key size is bytes, sasl wants bits */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
 | 
					        err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
 | 
				
			||||||
        if (err != SASL_OK) {
 | 
					        if (err != SASL_OK) {
 | 
				
			||||||
@ -549,20 +552,19 @@ void start_auth_sasl(VncState *vs)
 | 
				
			|||||||
            vs->sasl.conn = NULL;
 | 
					            vs->sasl.conn = NULL;
 | 
				
			||||||
            goto authabort;
 | 
					            goto authabort;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else
 | 
					    } else {
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
        vs->sasl.wantSSF = 1;
 | 
					        vs->sasl.wantSSF = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memset (&secprops, 0, sizeof secprops);
 | 
					    memset (&secprops, 0, sizeof secprops);
 | 
				
			||||||
    /* Inform SASL that we've got an external SSF layer from TLS */
 | 
					    /* Inform SASL that we've got an external SSF layer from TLS.
 | 
				
			||||||
    if (vs->vd->is_unix
 | 
					     *
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					     * Disable SSF, if using TLS+x509+SASL only. TLS without x509
 | 
				
			||||||
        /* Disable SSF, if using TLS+x509+SASL only. TLS without x509
 | 
					     * is not sufficiently strong
 | 
				
			||||||
           is not sufficiently strong */
 | 
					     */
 | 
				
			||||||
        || (vs->auth == VNC_AUTH_VENCRYPT &&
 | 
					    if (vs->vd->is_unix ||
 | 
				
			||||||
            vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)
 | 
					        (vs->auth == VNC_AUTH_VENCRYPT &&
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					         vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)) {
 | 
				
			||||||
        ) {
 | 
					 | 
				
			||||||
        /* If we've got TLS or UNIX domain sock, we don't care about SSF */
 | 
					        /* If we've got TLS or UNIX domain sock, we don't care about SSF */
 | 
				
			||||||
        secprops.min_ssf = 0;
 | 
					        secprops.min_ssf = 0;
 | 
				
			||||||
        secprops.max_ssf = 0;
 | 
					        secprops.max_ssf = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -67,38 +67,42 @@ static void vnc_tls_handshake_io(void *opaque);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int vnc_start_vencrypt_handshake(VncState *vs)
 | 
					static int vnc_start_vencrypt_handshake(VncState *vs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret;
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((ret = gnutls_handshake(vs->tls.session)) < 0) {
 | 
					    if (qcrypto_tls_session_handshake(vs->tls, &err) < 0) {
 | 
				
			||||||
       if (!gnutls_error_is_fatal(ret)) {
 | 
					        goto error;
 | 
				
			||||||
           VNC_DEBUG("Handshake interrupted (blocking)\n");
 | 
					 | 
				
			||||||
           if (!gnutls_record_get_direction(vs->tls.session))
 | 
					 | 
				
			||||||
               qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
 | 
					 | 
				
			||||||
           else
 | 
					 | 
				
			||||||
               qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
 | 
					 | 
				
			||||||
           return 0;
 | 
					 | 
				
			||||||
       }
 | 
					 | 
				
			||||||
       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
 | 
					 | 
				
			||||||
       vnc_client_error(vs);
 | 
					 | 
				
			||||||
       return -1;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (vs->vd->tls.x509verify) {
 | 
					    switch (qcrypto_tls_session_get_handshake_status(vs->tls)) {
 | 
				
			||||||
        if (vnc_tls_validate_certificate(vs) < 0) {
 | 
					    case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
 | 
				
			||||||
            VNC_DEBUG("Client verification failed\n");
 | 
					        VNC_DEBUG("Handshake done, checking credentials\n");
 | 
				
			||||||
            vnc_client_error(vs);
 | 
					        if (qcrypto_tls_session_check_credentials(vs->tls, &err) < 0) {
 | 
				
			||||||
            return -1;
 | 
					            goto error;
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            VNC_DEBUG("Client verification passed\n");
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					        VNC_DEBUG("Client verification passed, starting TLS I/O\n");
 | 
				
			||||||
 | 
					 | 
				
			||||||
    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
 | 
					 | 
				
			||||||
        qemu_set_fd_handler(vs->csock, vnc_client_read, vnc_client_write, vs);
 | 
					        qemu_set_fd_handler(vs->csock, vnc_client_read, vnc_client_write, vs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        start_auth_vencrypt_subauth(vs);
 | 
					        start_auth_vencrypt_subauth(vs);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case QCRYPTO_TLS_HANDSHAKE_RECVING:
 | 
				
			||||||
 | 
					        VNC_DEBUG("Handshake interrupted (blocking read)\n");
 | 
				
			||||||
 | 
					        qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case QCRYPTO_TLS_HANDSHAKE_SENDING:
 | 
				
			||||||
 | 
					        VNC_DEBUG("Handshake interrupted (blocking write)\n");
 | 
				
			||||||
 | 
					        qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 error:
 | 
				
			||||||
 | 
					    VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
 | 
				
			||||||
 | 
					    error_free(err);
 | 
				
			||||||
 | 
					    vnc_client_error(vs);
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void vnc_tls_handshake_io(void *opaque)
 | 
					static void vnc_tls_handshake_io(void *opaque)
 | 
				
			||||||
@ -110,14 +114,6 @@ static void vnc_tls_handshake_io(void *opaque)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#define NEED_X509_AUTH(vs)                              \
 | 
					 | 
				
			||||||
    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
 | 
					 | 
				
			||||||
     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
 | 
					 | 
				
			||||||
     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN ||  \
 | 
					 | 
				
			||||||
     (vs)->subauth == VNC_AUTH_VENCRYPT_X509SASL)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
 | 
					static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int auth = read_u32(data, 0);
 | 
					    int auth = read_u32(data, 0);
 | 
				
			||||||
@ -128,15 +124,29 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
 | 
				
			|||||||
        vnc_flush(vs);
 | 
					        vnc_flush(vs);
 | 
				
			||||||
        vnc_client_error(vs);
 | 
					        vnc_client_error(vs);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
					        Error *err = NULL;
 | 
				
			||||||
        VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
 | 
					        VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
 | 
				
			||||||
        vnc_write_u8(vs, 1); /* Accept auth */
 | 
					        vnc_write_u8(vs, 1); /* Accept auth */
 | 
				
			||||||
        vnc_flush(vs);
 | 
					        vnc_flush(vs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) {
 | 
					        vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds,
 | 
				
			||||||
            VNC_DEBUG("Failed to setup TLS\n");
 | 
					                                          NULL,
 | 
				
			||||||
 | 
					                                          vs->vd->tlsaclname,
 | 
				
			||||||
 | 
					                                          QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
 | 
				
			||||||
 | 
					                                          &err);
 | 
				
			||||||
 | 
					        if (!vs->tls) {
 | 
				
			||||||
 | 
					            VNC_DEBUG("Failed to setup TLS %s\n",
 | 
				
			||||||
 | 
					                      error_get_pretty(err));
 | 
				
			||||||
 | 
					            error_free(err);
 | 
				
			||||||
 | 
					            vnc_client_error(vs);
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        qcrypto_tls_session_set_callbacks(vs->tls,
 | 
				
			||||||
 | 
					                                          vnc_tls_push,
 | 
				
			||||||
 | 
					                                          vnc_tls_pull,
 | 
				
			||||||
 | 
					                                          vs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
 | 
					        VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
 | 
				
			||||||
        if (vnc_start_vencrypt_handshake(vs) < 0) {
 | 
					        if (vnc_start_vencrypt_handshake(vs) < 0) {
 | 
				
			||||||
            VNC_DEBUG("Failed to start TLS handshake\n");
 | 
					            VNC_DEBUG("Failed to start TLS handshake\n");
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										474
									
								
								ui/vnc-tls.c
									
									
									
									
									
								
							
							
						
						
									
										474
									
								
								ui/vnc-tls.c
									
									
									
									
									
								
							@ -1,474 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * QEMU VNC display driver: TLS helpers
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
 | 
					 | 
				
			||||||
 * Copyright (C) 2006 Fabrice Bellard
 | 
					 | 
				
			||||||
 * Copyright (C) 2009 Red Hat, Inc
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 | 
				
			||||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
					 | 
				
			||||||
 * in the Software without restriction, including without limitation the rights
 | 
					 | 
				
			||||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					 | 
				
			||||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
					 | 
				
			||||||
 * furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice shall be included in
 | 
					 | 
				
			||||||
 * all copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
					 | 
				
			||||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					 | 
				
			||||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
					 | 
				
			||||||
 * THE SOFTWARE.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "qemu-x509.h"
 | 
					 | 
				
			||||||
#include "vnc.h"
 | 
					 | 
				
			||||||
#include "qemu/sockets.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
 | 
					 | 
				
			||||||
/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
 | 
					 | 
				
			||||||
static void vnc_debug_gnutls_log(int level, const char* str) {
 | 
					 | 
				
			||||||
    VNC_DEBUG("%d %s", level, str);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif /* defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define DH_BITS 1024
 | 
					 | 
				
			||||||
static gnutls_dh_params_t dh_params;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int vnc_tls_initialize(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    static int tlsinitialized = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (tlsinitialized)
 | 
					 | 
				
			||||||
        return 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (gnutls_global_init () < 0)
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* XXX ought to re-generate diffie-hellman params periodically */
 | 
					 | 
				
			||||||
    if (gnutls_dh_params_init (&dh_params) < 0)
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
 | 
					 | 
				
			||||||
    gnutls_global_set_log_level(10);
 | 
					 | 
				
			||||||
    gnutls_global_set_log_function(vnc_debug_gnutls_log);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tlsinitialized = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
 | 
					 | 
				
			||||||
                            const void *data,
 | 
					 | 
				
			||||||
                            size_t len) {
 | 
					 | 
				
			||||||
    VncState *vs = (VncState *)transport;
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 retry:
 | 
					 | 
				
			||||||
    ret = send(vs->csock, data, len, 0);
 | 
					 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        if (errno == EINTR)
 | 
					 | 
				
			||||||
            goto retry;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
 | 
					 | 
				
			||||||
                            void *data,
 | 
					 | 
				
			||||||
                            size_t len) {
 | 
					 | 
				
			||||||
    VncState *vs = (VncState *)transport;
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 retry:
 | 
					 | 
				
			||||||
    ret = qemu_recv(vs->csock, data, len, 0);
 | 
					 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        if (errno == EINTR)
 | 
					 | 
				
			||||||
            goto retry;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gnutls_anon_server_credentials_t vnc_tls_initialize_anon_cred(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    gnutls_anon_server_credentials_t anon_cred;
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
 | 
					 | 
				
			||||||
        VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
 | 
					 | 
				
			||||||
        return NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return anon_cred;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncDisplay *vd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    gnutls_certificate_credentials_t x509_cred;
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!vd->tls.x509cacert) {
 | 
					 | 
				
			||||||
        VNC_DEBUG("No CA x509 certificate specified\n");
 | 
					 | 
				
			||||||
        return NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!vd->tls.x509cert) {
 | 
					 | 
				
			||||||
        VNC_DEBUG("No server x509 certificate specified\n");
 | 
					 | 
				
			||||||
        return NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!vd->tls.x509key) {
 | 
					 | 
				
			||||||
        VNC_DEBUG("No server private key specified\n");
 | 
					 | 
				
			||||||
        return NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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,
 | 
					 | 
				
			||||||
                                                      vd->tls.x509cacert,
 | 
					 | 
				
			||||||
                                                      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,
 | 
					 | 
				
			||||||
                                                     vd->tls.x509cert,
 | 
					 | 
				
			||||||
                                                     vd->tls.x509key,
 | 
					 | 
				
			||||||
                                                     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 (vd->tls.x509cacrl) {
 | 
					 | 
				
			||||||
        if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
 | 
					 | 
				
			||||||
                                                        vd->tls.x509cacrl,
 | 
					 | 
				
			||||||
                                                        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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int vnc_tls_validate_certificate(VncState *vs)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
    unsigned int status;
 | 
					 | 
				
			||||||
    const gnutls_datum_t *certs;
 | 
					 | 
				
			||||||
    unsigned int nCerts, i;
 | 
					 | 
				
			||||||
    time_t now;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    VNC_DEBUG("Validating client certificate\n");
 | 
					 | 
				
			||||||
    if ((ret = gnutls_certificate_verify_peers2 (vs->tls.session, &status)) < 0) {
 | 
					 | 
				
			||||||
        VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((now = time(NULL)) == ((time_t)-1)) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (status != 0) {
 | 
					 | 
				
			||||||
        if (status & GNUTLS_CERT_INVALID)
 | 
					 | 
				
			||||||
            VNC_DEBUG("The certificate is not trusted.\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
 | 
					 | 
				
			||||||
            VNC_DEBUG("The certificate hasn't got a known issuer.\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (status & GNUTLS_CERT_REVOKED)
 | 
					 | 
				
			||||||
            VNC_DEBUG("The certificate has been revoked.\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
 | 
					 | 
				
			||||||
            VNC_DEBUG("The certificate uses an insecure algorithm\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        VNC_DEBUG("Certificate is valid!\n");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Only support x509 for now */
 | 
					 | 
				
			||||||
    if (gnutls_certificate_type_get(vs->tls.session) != GNUTLS_CRT_X509)
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!(certs = gnutls_certificate_get_peers(vs->tls.session, &nCerts)))
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0 ; i < nCerts ; i++) {
 | 
					 | 
				
			||||||
        gnutls_x509_crt_t cert;
 | 
					 | 
				
			||||||
        VNC_DEBUG ("Checking certificate chain %d\n", i);
 | 
					 | 
				
			||||||
        if (gnutls_x509_crt_init (&cert) < 0)
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
 | 
					 | 
				
			||||||
            gnutls_x509_crt_deinit (cert);
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
 | 
					 | 
				
			||||||
            VNC_DEBUG("The certificate has expired\n");
 | 
					 | 
				
			||||||
            gnutls_x509_crt_deinit (cert);
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (gnutls_x509_crt_get_activation_time (cert) > now) {
 | 
					 | 
				
			||||||
            VNC_DEBUG("The certificate is not yet activated\n");
 | 
					 | 
				
			||||||
            gnutls_x509_crt_deinit (cert);
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (gnutls_x509_crt_get_activation_time (cert) > now) {
 | 
					 | 
				
			||||||
            VNC_DEBUG("The certificate is not yet activated\n");
 | 
					 | 
				
			||||||
            gnutls_x509_crt_deinit (cert);
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (i == 0) {
 | 
					 | 
				
			||||||
            size_t dnameSize = 1024;
 | 
					 | 
				
			||||||
            vs->tls.dname = g_malloc(dnameSize);
 | 
					 | 
				
			||||||
        requery:
 | 
					 | 
				
			||||||
            if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) {
 | 
					 | 
				
			||||||
                if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
 | 
					 | 
				
			||||||
                    vs->tls.dname = g_realloc(vs->tls.dname, dnameSize);
 | 
					 | 
				
			||||||
                    goto requery;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                gnutls_x509_crt_deinit (cert);
 | 
					 | 
				
			||||||
                VNC_DEBUG("Cannot get client distinguished name: %s",
 | 
					 | 
				
			||||||
                          gnutls_strerror (ret));
 | 
					 | 
				
			||||||
                return -1;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (vs->vd->tls.x509verify) {
 | 
					 | 
				
			||||||
                int allow;
 | 
					 | 
				
			||||||
                if (!vs->vd->tls.acl) {
 | 
					 | 
				
			||||||
                    VNC_DEBUG("no ACL activated, allowing access");
 | 
					 | 
				
			||||||
                    gnutls_x509_crt_deinit (cert);
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                allow = qemu_acl_party_is_allowed(vs->vd->tls.acl,
 | 
					 | 
				
			||||||
                                                  vs->tls.dname);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                VNC_DEBUG("TLS x509 ACL check for %s is %s\n",
 | 
					 | 
				
			||||||
                          vs->tls.dname, allow ? "allowed" : "denied");
 | 
					 | 
				
			||||||
                if (!allow) {
 | 
					 | 
				
			||||||
                    gnutls_x509_crt_deinit (cert);
 | 
					 | 
				
			||||||
                    return -1;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        gnutls_x509_crt_deinit (cert);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(GNUTLS_VERSION_NUMBER) && \
 | 
					 | 
				
			||||||
    GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    const char *priority = x509 ? "NORMAL" : "NORMAL:+ANON-DH";
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rc = gnutls_priority_set_direct(s, priority, NULL);
 | 
					 | 
				
			||||||
    if (rc != GNUTLS_E_SUCCESS) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    static const int cert_types[] = { GNUTLS_CRT_X509, 0 };
 | 
					 | 
				
			||||||
    static const int protocols[] = {
 | 
					 | 
				
			||||||
        GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    static const int kx_anon[] = { GNUTLS_KX_ANON_DH, 0 };
 | 
					 | 
				
			||||||
    static const int kx_x509[] = {
 | 
					 | 
				
			||||||
        GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA,
 | 
					 | 
				
			||||||
        GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rc = gnutls_kx_set_priority(s, x509 ? kx_x509 : kx_anon);
 | 
					 | 
				
			||||||
    if (rc != GNUTLS_E_SUCCESS) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rc = gnutls_certificate_type_set_priority(s, cert_types);
 | 
					 | 
				
			||||||
    if (rc != GNUTLS_E_SUCCESS) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rc = gnutls_protocol_set_priority(s, protocols);
 | 
					 | 
				
			||||||
    if (rc != GNUTLS_E_SUCCESS) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int vnc_tls_client_setup(VncState *vs,
 | 
					 | 
				
			||||||
                         int needX509Creds) {
 | 
					 | 
				
			||||||
    VNC_DEBUG("Do TLS setup\n");
 | 
					 | 
				
			||||||
    if (vnc_tls_initialize() < 0) {
 | 
					 | 
				
			||||||
        VNC_DEBUG("Failed to init TLS\n");
 | 
					 | 
				
			||||||
        vnc_client_error(vs);
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (vs->tls.session == NULL) {
 | 
					 | 
				
			||||||
        if (gnutls_init(&vs->tls.session, GNUTLS_SERVER) < 0) {
 | 
					 | 
				
			||||||
            vnc_client_error(vs);
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (gnutls_set_default_priority(vs->tls.session) < 0) {
 | 
					 | 
				
			||||||
            gnutls_deinit(vs->tls.session);
 | 
					 | 
				
			||||||
            vs->tls.session = NULL;
 | 
					 | 
				
			||||||
            vnc_client_error(vs);
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (vnc_set_gnutls_priority(vs->tls.session, needX509Creds) < 0) {
 | 
					 | 
				
			||||||
            gnutls_deinit(vs->tls.session);
 | 
					 | 
				
			||||||
            vs->tls.session = NULL;
 | 
					 | 
				
			||||||
            vnc_client_error(vs);
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (needX509Creds) {
 | 
					 | 
				
			||||||
            gnutls_certificate_server_credentials x509_cred =
 | 
					 | 
				
			||||||
                vnc_tls_initialize_x509_cred(vs->vd);
 | 
					 | 
				
			||||||
            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;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (vs->vd->tls.x509verify) {
 | 
					 | 
				
			||||||
                VNC_DEBUG("Requesting a client certificate\n");
 | 
					 | 
				
			||||||
                gnutls_certificate_server_set_request(vs->tls.session,
 | 
					 | 
				
			||||||
                                                      GNUTLS_CERT_REQUEST);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            gnutls_anon_server_credentials_t 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);
 | 
					 | 
				
			||||||
        gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push);
 | 
					 | 
				
			||||||
        gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void vnc_tls_client_cleanup(VncState *vs)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (vs->tls.session) {
 | 
					 | 
				
			||||||
        gnutls_deinit(vs->tls.session);
 | 
					 | 
				
			||||||
        vs->tls.session = NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    g_free(vs->tls.dname);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int vnc_set_x509_credential(VncDisplay *vd,
 | 
					 | 
				
			||||||
                                   const char *certdir,
 | 
					 | 
				
			||||||
                                   const char *filename,
 | 
					 | 
				
			||||||
                                   char **cred,
 | 
					 | 
				
			||||||
                                   int ignoreMissing)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct stat sb;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    g_free(*cred);
 | 
					 | 
				
			||||||
    *cred = g_malloc(strlen(certdir) + strlen(filename) + 2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    strcpy(*cred, certdir);
 | 
					 | 
				
			||||||
    strcat(*cred, "/");
 | 
					 | 
				
			||||||
    strcat(*cred, filename);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    VNC_DEBUG("Check %s\n", *cred);
 | 
					 | 
				
			||||||
    if (stat(*cred, &sb) < 0) {
 | 
					 | 
				
			||||||
        g_free(*cred);
 | 
					 | 
				
			||||||
        *cred = NULL;
 | 
					 | 
				
			||||||
        if (ignoreMissing && errno == ENOENT)
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
 | 
					 | 
				
			||||||
                               const char *certdir)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (vnc_set_x509_credential(vd, certdir, X509_CA_CERT_FILE, &vd->tls.x509cacert, 0) < 0)
 | 
					 | 
				
			||||||
        goto cleanup;
 | 
					 | 
				
			||||||
    if (vnc_set_x509_credential(vd, certdir, X509_CA_CRL_FILE, &vd->tls.x509cacrl, 1) < 0)
 | 
					 | 
				
			||||||
        goto cleanup;
 | 
					 | 
				
			||||||
    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_CERT_FILE, &vd->tls.x509cert, 0) < 0)
 | 
					 | 
				
			||||||
        goto cleanup;
 | 
					 | 
				
			||||||
    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_KEY_FILE, &vd->tls.x509key, 0) < 0)
 | 
					 | 
				
			||||||
        goto cleanup;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 cleanup:
 | 
					 | 
				
			||||||
    g_free(vd->tls.x509cacert);
 | 
					 | 
				
			||||||
    g_free(vd->tls.x509cacrl);
 | 
					 | 
				
			||||||
    g_free(vd->tls.x509cert);
 | 
					 | 
				
			||||||
    g_free(vd->tls.x509key);
 | 
					 | 
				
			||||||
    vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										69
									
								
								ui/vnc-tls.h
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								ui/vnc-tls.h
									
									
									
									
									
								
							@ -1,69 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * QEMU VNC display driver. TLS helpers
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
 | 
					 | 
				
			||||||
 * Copyright (C) 2006 Fabrice Bellard
 | 
					 | 
				
			||||||
 * Copyright (C) 2009 Red Hat, Inc
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 | 
				
			||||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
					 | 
				
			||||||
 * in the Software without restriction, including without limitation the rights
 | 
					 | 
				
			||||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					 | 
				
			||||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
					 | 
				
			||||||
 * furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice shall be included in
 | 
					 | 
				
			||||||
 * all copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
					 | 
				
			||||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					 | 
				
			||||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
					 | 
				
			||||||
 * THE SOFTWARE.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef __QEMU_VNC_TLS_H__
 | 
					 | 
				
			||||||
#define __QEMU_VNC_TLS_H__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gnutls/gnutls.h>
 | 
					 | 
				
			||||||
#include <gnutls/x509.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "qemu/acl.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VncDisplayTLS VncDisplayTLS;
 | 
					 | 
				
			||||||
typedef struct VncStateTLS VncStateTLS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Server state */
 | 
					 | 
				
			||||||
struct VncDisplayTLS {
 | 
					 | 
				
			||||||
    int x509verify; /* Non-zero if server requests & validates client cert */
 | 
					 | 
				
			||||||
    qemu_acl *acl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Paths to x509 certs/keys */
 | 
					 | 
				
			||||||
    char *x509cacert;
 | 
					 | 
				
			||||||
    char *x509cacrl;
 | 
					 | 
				
			||||||
    char *x509cert;
 | 
					 | 
				
			||||||
    char *x509key;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Per client state */
 | 
					 | 
				
			||||||
struct VncStateTLS {
 | 
					 | 
				
			||||||
    gnutls_session_t session;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Client's Distinguished Name from the x509 cert */
 | 
					 | 
				
			||||||
    char *dname;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int vnc_tls_client_setup(VncState *vs, int x509Creds);
 | 
					 | 
				
			||||||
void vnc_tls_client_cleanup(VncState *vs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int vnc_tls_validate_certificate(VncState *vs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
 | 
					 | 
				
			||||||
			       const char *path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* __QEMU_VNC_TLS_H__ */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										80
									
								
								ui/vnc-ws.c
									
									
									
									
									
								
							
							
						
						
									
										80
									
								
								ui/vnc-ws.c
									
									
									
									
									
								
							@ -22,60 +22,70 @@
 | 
				
			|||||||
#include "qemu/main-loop.h"
 | 
					#include "qemu/main-loop.h"
 | 
				
			||||||
#include "crypto/hash.h"
 | 
					#include "crypto/hash.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					 | 
				
			||||||
#include "qemu/sockets.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int vncws_start_tls_handshake(VncState *vs)
 | 
					static int vncws_start_tls_handshake(VncState *vs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = gnutls_handshake(vs->tls.session);
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (qcrypto_tls_session_handshake(vs->tls, &err) < 0) {
 | 
				
			||||||
        if (!gnutls_error_is_fatal(ret)) {
 | 
					        goto error;
 | 
				
			||||||
            VNC_DEBUG("Handshake interrupted (blocking)\n");
 | 
					 | 
				
			||||||
            if (!gnutls_record_get_direction(vs->tls.session)) {
 | 
					 | 
				
			||||||
                qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io,
 | 
					 | 
				
			||||||
                                    NULL, vs);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                qemu_set_fd_handler(vs->csock, NULL, vncws_tls_handshake_io,
 | 
					 | 
				
			||||||
                                    vs);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
 | 
					 | 
				
			||||||
        vnc_client_error(vs);
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (vs->vd->tls.x509verify) {
 | 
					    switch (qcrypto_tls_session_get_handshake_status(vs->tls)) {
 | 
				
			||||||
        if (vnc_tls_validate_certificate(vs) < 0) {
 | 
					    case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
 | 
				
			||||||
            VNC_DEBUG("Client verification failed\n");
 | 
					        VNC_DEBUG("Handshake done, checking credentials\n");
 | 
				
			||||||
            vnc_client_error(vs);
 | 
					        if (qcrypto_tls_session_check_credentials(vs->tls, &err) < 0) {
 | 
				
			||||||
            return -1;
 | 
					            goto error;
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            VNC_DEBUG("Client verification passed\n");
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					        VNC_DEBUG("Client verification passed, starting TLS I/O\n");
 | 
				
			||||||
 | 
					 | 
				
			||||||
    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
 | 
					 | 
				
			||||||
        qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs);
 | 
					        qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case QCRYPTO_TLS_HANDSHAKE_RECVING:
 | 
				
			||||||
 | 
					        VNC_DEBUG("Handshake interrupted (blocking read)\n");
 | 
				
			||||||
 | 
					        qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, NULL, vs);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case QCRYPTO_TLS_HANDSHAKE_SENDING:
 | 
				
			||||||
 | 
					        VNC_DEBUG("Handshake interrupted (blocking write)\n");
 | 
				
			||||||
 | 
					        qemu_set_fd_handler(vs->csock, NULL, vncws_tls_handshake_io, vs);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 error:
 | 
				
			||||||
 | 
					    VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
 | 
				
			||||||
 | 
					    error_free(err);
 | 
				
			||||||
 | 
					    vnc_client_error(vs);
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void vncws_tls_handshake_io(void *opaque)
 | 
					void vncws_tls_handshake_io(void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    VncState *vs = (VncState *)opaque;
 | 
					    VncState *vs = (VncState *)opaque;
 | 
				
			||||||
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!vs->tls.session) {
 | 
					    vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds,
 | 
				
			||||||
        VNC_DEBUG("TLS Websocket setup\n");
 | 
					                                      NULL,
 | 
				
			||||||
        if (vnc_tls_client_setup(vs, vs->vd->tls.x509cert != NULL) < 0) {
 | 
					                                      vs->vd->tlsaclname,
 | 
				
			||||||
 | 
					                                      QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
 | 
				
			||||||
 | 
					                                      &err);
 | 
				
			||||||
 | 
					    if (!vs->tls) {
 | 
				
			||||||
 | 
					        VNC_DEBUG("Failed to setup TLS %s\n",
 | 
				
			||||||
 | 
					                  error_get_pretty(err));
 | 
				
			||||||
 | 
					        error_free(err);
 | 
				
			||||||
 | 
					        vnc_client_error(vs);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					
 | 
				
			||||||
    VNC_DEBUG("Handshake IO continue\n");
 | 
					    qcrypto_tls_session_set_callbacks(vs->tls,
 | 
				
			||||||
 | 
					                                      vnc_tls_push,
 | 
				
			||||||
 | 
					                                      vnc_tls_pull,
 | 
				
			||||||
 | 
					                                      vs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VNC_DEBUG("Start TLS WS handshake process\n");
 | 
				
			||||||
    vncws_start_tls_handshake(vs);
 | 
					    vncws_start_tls_handshake(vs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void vncws_handshake_read(void *opaque)
 | 
					void vncws_handshake_read(void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
				
			|||||||
@ -72,9 +72,7 @@ enum {
 | 
				
			|||||||
    WS_OPCODE_PONG = 0xA
 | 
					    WS_OPCODE_PONG = 0xA
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					 | 
				
			||||||
void vncws_tls_handshake_io(void *opaque);
 | 
					void vncws_tls_handshake_io(void *opaque);
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
void vncws_handshake_read(void *opaque);
 | 
					void vncws_handshake_read(void *opaque);
 | 
				
			||||||
long vnc_client_write_ws(VncState *vs);
 | 
					long vnc_client_write_ws(VncState *vs);
 | 
				
			||||||
long vnc_client_read_ws(VncState *vs);
 | 
					long vnc_client_read_ws(VncState *vs);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										358
									
								
								ui/vnc.c
									
									
									
									
									
								
							
							
						
						
									
										358
									
								
								ui/vnc.c
									
									
									
									
									
								
							@ -41,6 +41,9 @@
 | 
				
			|||||||
#include "ui/input.h"
 | 
					#include "ui/input.h"
 | 
				
			||||||
#include "qapi-event.h"
 | 
					#include "qapi-event.h"
 | 
				
			||||||
#include "crypto/hash.h"
 | 
					#include "crypto/hash.h"
 | 
				
			||||||
 | 
					#include "crypto/tlscredsanon.h"
 | 
				
			||||||
 | 
					#include "crypto/tlscredsx509.h"
 | 
				
			||||||
 | 
					#include "qom/object_interfaces.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
 | 
					#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
 | 
				
			||||||
#define VNC_REFRESH_INTERVAL_INC  50
 | 
					#define VNC_REFRESH_INTERVAL_INC  50
 | 
				
			||||||
@ -222,7 +225,6 @@ static const char *vnc_auth_name(VncDisplay *vd) {
 | 
				
			|||||||
    case VNC_AUTH_TLS:
 | 
					    case VNC_AUTH_TLS:
 | 
				
			||||||
        return "tls";
 | 
					        return "tls";
 | 
				
			||||||
    case VNC_AUTH_VENCRYPT:
 | 
					    case VNC_AUTH_VENCRYPT:
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					 | 
				
			||||||
        switch (vd->subauth) {
 | 
					        switch (vd->subauth) {
 | 
				
			||||||
        case VNC_AUTH_VENCRYPT_PLAIN:
 | 
					        case VNC_AUTH_VENCRYPT_PLAIN:
 | 
				
			||||||
            return "vencrypt+plain";
 | 
					            return "vencrypt+plain";
 | 
				
			||||||
@ -245,9 +247,6 @@ static const char *vnc_auth_name(VncDisplay *vd) {
 | 
				
			|||||||
        default:
 | 
					        default:
 | 
				
			||||||
            return "vencrypt";
 | 
					            return "vencrypt";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        return "vencrypt";
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    case VNC_AUTH_SASL:
 | 
					    case VNC_AUTH_SASL:
 | 
				
			||||||
        return "sasl";
 | 
					        return "sasl";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -275,13 +274,12 @@ static void vnc_client_cache_auth(VncState *client)
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    if (client->tls) {
 | 
				
			||||||
    if (client->tls.session &&
 | 
					        client->info->x509_dname =
 | 
				
			||||||
        client->tls.dname) {
 | 
					            qcrypto_tls_session_get_peer_name(client->tls);
 | 
				
			||||||
        client->info->has_x509_dname = true;
 | 
					        client->info->has_x509_dname =
 | 
				
			||||||
        client->info->x509_dname = g_strdup(client->tls.dname);
 | 
					            client->info->x509_dname != NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
    if (client->sasl.conn &&
 | 
					    if (client->sasl.conn &&
 | 
				
			||||||
        client->sasl.username) {
 | 
					        client->sasl.username) {
 | 
				
			||||||
@ -358,12 +356,10 @@ static VncClientInfo *qmp_query_vnc_client(const VncState *client)
 | 
				
			|||||||
    info->base->family = inet_netfamily(sa.ss_family);
 | 
					    info->base->family = inet_netfamily(sa.ss_family);
 | 
				
			||||||
    info->base->websocket = client->websocket;
 | 
					    info->base->websocket = client->websocket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    if (client->tls) {
 | 
				
			||||||
    if (client->tls.session && client->tls.dname) {
 | 
					        info->x509_dname = qcrypto_tls_session_get_peer_name(client->tls);
 | 
				
			||||||
        info->has_x509_dname = true;
 | 
					        info->has_x509_dname = info->x509_dname != NULL;
 | 
				
			||||||
        info->x509_dname = g_strdup(client->tls.dname);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
    if (client->sasl.conn && client->sasl.username) {
 | 
					    if (client->sasl.conn && client->sasl.username) {
 | 
				
			||||||
        info->has_sasl_username = true;
 | 
					        info->has_sasl_username = true;
 | 
				
			||||||
@ -513,7 +509,6 @@ static void qmp_query_auth(VncDisplay *vd, VncInfo2 *info)
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case VNC_AUTH_VENCRYPT:
 | 
					    case VNC_AUTH_VENCRYPT:
 | 
				
			||||||
        info->auth = VNC_PRIMARY_AUTH_VENCRYPT;
 | 
					        info->auth = VNC_PRIMARY_AUTH_VENCRYPT;
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					 | 
				
			||||||
        info->has_vencrypt = true;
 | 
					        info->has_vencrypt = true;
 | 
				
			||||||
        switch (vd->subauth) {
 | 
					        switch (vd->subauth) {
 | 
				
			||||||
        case VNC_AUTH_VENCRYPT_PLAIN:
 | 
					        case VNC_AUTH_VENCRYPT_PLAIN:
 | 
				
			||||||
@ -547,7 +542,6 @@ static void qmp_query_auth(VncDisplay *vd, VncInfo2 *info)
 | 
				
			|||||||
            info->has_vencrypt = false;
 | 
					            info->has_vencrypt = false;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case VNC_AUTH_SASL:
 | 
					    case VNC_AUTH_SASL:
 | 
				
			||||||
        info->auth = VNC_PRIMARY_AUTH_SASL;
 | 
					        info->auth = VNC_PRIMARY_AUTH_SASL;
 | 
				
			||||||
@ -1237,9 +1231,7 @@ void vnc_disconnect_finish(VncState *vs)
 | 
				
			|||||||
    vnc_tight_clear(vs);
 | 
					    vnc_tight_clear(vs);
 | 
				
			||||||
    vnc_zrle_clear(vs);
 | 
					    vnc_zrle_clear(vs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    qcrypto_tls_session_free(vs->tls);
 | 
				
			||||||
    vnc_tls_client_cleanup(vs);
 | 
					 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
    vnc_sasl_client_cleanup(vs);
 | 
					    vnc_sasl_client_cleanup(vs);
 | 
				
			||||||
#endif /* CONFIG_VNC_SASL */
 | 
					#endif /* CONFIG_VNC_SASL */
 | 
				
			||||||
@ -1268,7 +1260,7 @@ void vnc_disconnect_finish(VncState *vs)
 | 
				
			|||||||
    g_free(vs);
 | 
					    g_free(vs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int vnc_client_io_error(VncState *vs, int ret, int last_errno)
 | 
					ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, int last_errno)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (ret == 0 || ret == -1) {
 | 
					    if (ret == 0 || ret == -1) {
 | 
				
			||||||
        if (ret == -1) {
 | 
					        if (ret == -1) {
 | 
				
			||||||
@ -1284,7 +1276,7 @@ int vnc_client_io_error(VncState *vs, int ret, int last_errno)
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
 | 
					        VNC_DEBUG("Closing down client sock: ret %zd, errno %d\n",
 | 
				
			||||||
                  ret, ret < 0 ? last_errno : 0);
 | 
					                  ret, ret < 0 ? last_errno : 0);
 | 
				
			||||||
        vnc_disconnect_start(vs);
 | 
					        vnc_disconnect_start(vs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1300,23 +1292,40 @@ void vnc_client_error(VncState *vs)
 | 
				
			|||||||
    vnc_disconnect_start(vs);
 | 
					    vnc_disconnect_start(vs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					
 | 
				
			||||||
static long vnc_client_write_tls(gnutls_session_t *session,
 | 
					ssize_t vnc_tls_pull(char *buf, size_t len, void *opaque)
 | 
				
			||||||
                                 const uint8_t *data,
 | 
					 | 
				
			||||||
                                 size_t datalen)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    long ret = gnutls_write(*session, data, datalen);
 | 
					    VncState *vs = opaque;
 | 
				
			||||||
 | 
					    ssize_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 retry:
 | 
				
			||||||
 | 
					    ret = qemu_recv(vs->csock, buf, len, 0);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        if (ret == GNUTLS_E_AGAIN) {
 | 
					        if (errno == EINTR) {
 | 
				
			||||||
            errno = EAGAIN;
 | 
					            goto retry;
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            errno = EIO;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        ret = -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ssize_t vnc_tls_push(const char *buf, size_t len, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VncState *vs = opaque;
 | 
				
			||||||
 | 
					    ssize_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 retry:
 | 
				
			||||||
 | 
					    ret = send(vs->csock, buf, len, 0);
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        if (errno == EINTR) {
 | 
				
			||||||
 | 
					            goto retry;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Called to write a chunk of data to the client socket. The data may
 | 
					 * Called to write a chunk of data to the client socket. The data may
 | 
				
			||||||
@ -1333,20 +1342,23 @@ static long vnc_client_write_tls(gnutls_session_t *session,
 | 
				
			|||||||
 * the requested 'datalen' if the socket would block. Returns
 | 
					 * the requested 'datalen' if the socket would block. Returns
 | 
				
			||||||
 * -1 on error, and disconnects the client socket.
 | 
					 * -1 on error, and disconnects the client socket.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
 | 
					ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    long ret;
 | 
					    ssize_t ret;
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    int err = 0;
 | 
				
			||||||
    if (vs->tls.session) {
 | 
					    if (vs->tls) {
 | 
				
			||||||
        ret = vnc_client_write_tls(&vs->tls.session, data, datalen);
 | 
					        ret = qcrypto_tls_session_write(vs->tls, (const char *)data, datalen);
 | 
				
			||||||
    } else {
 | 
					        if (ret < 0) {
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					            err = errno;
 | 
				
			||||||
        ret = send(vs->csock, (const void *)data, datalen, 0);
 | 
					        }
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    } else {
 | 
				
			||||||
 | 
					        ret = send(vs->csock, (const void *)data, datalen, 0);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            err = socket_error();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
 | 
					    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
 | 
				
			||||||
    return vnc_client_io_error(vs, ret, socket_error());
 | 
					    return vnc_client_io_error(vs, ret, err);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1360,9 +1372,9 @@ long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
 | 
				
			|||||||
 * the buffered output data if the socket would block. Returns
 | 
					 * the buffered output data if the socket would block. Returns
 | 
				
			||||||
 * -1 on error, and disconnects the client socket.
 | 
					 * -1 on error, and disconnects the client socket.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static long vnc_client_write_plain(VncState *vs)
 | 
					static ssize_t vnc_client_write_plain(VncState *vs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    long ret;
 | 
					    ssize_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
 | 
					    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
 | 
				
			||||||
@ -1435,22 +1447,6 @@ void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
 | 
				
			|||||||
    vs->read_handler_expect = expecting;
 | 
					    vs->read_handler_expect = expecting;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					 | 
				
			||||||
static long vnc_client_read_tls(gnutls_session_t *session, uint8_t *data,
 | 
					 | 
				
			||||||
                                size_t datalen)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    long ret = gnutls_read(*session, data, datalen);
 | 
					 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        if (ret == GNUTLS_E_AGAIN) {
 | 
					 | 
				
			||||||
            errno = EAGAIN;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            errno = EIO;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        ret = -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Called to read a chunk of data from the client socket. The data may
 | 
					 * Called to read a chunk of data from the client socket. The data may
 | 
				
			||||||
@ -1467,20 +1463,23 @@ static long vnc_client_read_tls(gnutls_session_t *session, uint8_t *data,
 | 
				
			|||||||
 * the requested 'datalen' if the socket would block. Returns
 | 
					 * the requested 'datalen' if the socket would block. Returns
 | 
				
			||||||
 * -1 on error, and disconnects the client socket.
 | 
					 * -1 on error, and disconnects the client socket.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
 | 
					ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    long ret;
 | 
					    ssize_t ret;
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    int err = -1;
 | 
				
			||||||
    if (vs->tls.session) {
 | 
					    if (vs->tls) {
 | 
				
			||||||
        ret = vnc_client_read_tls(&vs->tls.session, data, datalen);
 | 
					        ret = qcrypto_tls_session_read(vs->tls, (char *)data, datalen);
 | 
				
			||||||
    } else {
 | 
					        if (ret < 0) {
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					            err = errno;
 | 
				
			||||||
        ret = qemu_recv(vs->csock, data, datalen, 0);
 | 
					        }
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    } else {
 | 
				
			||||||
 | 
					        ret = qemu_recv(vs->csock, data, datalen, 0);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            err = socket_error();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
 | 
					    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
 | 
				
			||||||
    return vnc_client_io_error(vs, ret, socket_error());
 | 
					    return vnc_client_io_error(vs, ret, err);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1492,9 +1491,9 @@ long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
 | 
				
			|||||||
 * Returns the number of bytes read. Returns -1 on error, and
 | 
					 * Returns the number of bytes read. Returns -1 on error, and
 | 
				
			||||||
 * disconnects the client socket.
 | 
					 * disconnects the client socket.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static long vnc_client_read_plain(VncState *vs)
 | 
					static ssize_t vnc_client_read_plain(VncState *vs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret;
 | 
					    ssize_t ret;
 | 
				
			||||||
    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
 | 
					    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
 | 
				
			||||||
              vs->input.buffer, vs->input.capacity, vs->input.offset);
 | 
					              vs->input.buffer, vs->input.capacity, vs->input.offset);
 | 
				
			||||||
    buffer_reserve(&vs->input, 4096);
 | 
					    buffer_reserve(&vs->input, 4096);
 | 
				
			||||||
@ -1520,7 +1519,7 @@ static void vnc_jobs_bh(void *opaque)
 | 
				
			|||||||
void vnc_client_read(void *opaque)
 | 
					void vnc_client_read(void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    VncState *vs = opaque;
 | 
					    VncState *vs = opaque;
 | 
				
			||||||
    long ret;
 | 
					    ssize_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
    if (vs->sasl.conn && vs->sasl.runSSF)
 | 
					    if (vs->sasl.conn && vs->sasl.runSSF)
 | 
				
			||||||
@ -2631,12 +2630,10 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
 | 
				
			|||||||
           start_auth_vnc(vs);
 | 
					           start_auth_vnc(vs);
 | 
				
			||||||
           break;
 | 
					           break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					 | 
				
			||||||
       case VNC_AUTH_VENCRYPT:
 | 
					       case VNC_AUTH_VENCRYPT:
 | 
				
			||||||
           VNC_DEBUG("Accept VeNCrypt auth\n");
 | 
					           VNC_DEBUG("Accept VeNCrypt auth\n");
 | 
				
			||||||
           start_auth_vencrypt(vs);
 | 
					           start_auth_vencrypt(vs);
 | 
				
			||||||
           break;
 | 
					           break;
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
       case VNC_AUTH_SASL:
 | 
					       case VNC_AUTH_SASL:
 | 
				
			||||||
@ -3033,12 +3030,9 @@ static void vnc_connect(VncDisplay *vd, int csock,
 | 
				
			|||||||
    qemu_set_nonblock(vs->csock);
 | 
					    qemu_set_nonblock(vs->csock);
 | 
				
			||||||
    if (websocket) {
 | 
					    if (websocket) {
 | 
				
			||||||
        vs->websocket = 1;
 | 
					        vs->websocket = 1;
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					 | 
				
			||||||
        if (vd->ws_tls) {
 | 
					        if (vd->ws_tls) {
 | 
				
			||||||
            qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, NULL, vs);
 | 
					            qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, NULL, vs);
 | 
				
			||||||
        } else
 | 
					        } else {
 | 
				
			||||||
#endif /* CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs);
 | 
					            qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else
 | 
					    } else
 | 
				
			||||||
@ -3194,9 +3188,11 @@ static void vnc_display_close(VncDisplay *vs)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    vs->auth = VNC_AUTH_INVALID;
 | 
					    vs->auth = VNC_AUTH_INVALID;
 | 
				
			||||||
    vs->subauth = VNC_AUTH_INVALID;
 | 
					    vs->subauth = VNC_AUTH_INVALID;
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    if (vs->tlscreds) {
 | 
				
			||||||
    vs->tls.x509verify = 0;
 | 
					        object_unparent(OBJECT(vs->tlscreds));
 | 
				
			||||||
#endif
 | 
					    }
 | 
				
			||||||
 | 
					    g_free(vs->tlsaclname);
 | 
				
			||||||
 | 
					    vs->tlsaclname = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int vnc_display_password(const char *id, const char *password)
 | 
					int vnc_display_password(const char *id, const char *password)
 | 
				
			||||||
@ -3250,6 +3246,10 @@ static QemuOptsList qemu_vnc_opts = {
 | 
				
			|||||||
            .name = "websocket",
 | 
					            .name = "websocket",
 | 
				
			||||||
            .type = QEMU_OPT_STRING,
 | 
					            .type = QEMU_OPT_STRING,
 | 
				
			||||||
        },{
 | 
					        },{
 | 
				
			||||||
 | 
					            .name = "tls-creds",
 | 
				
			||||||
 | 
					            .type = QEMU_OPT_STRING,
 | 
				
			||||||
 | 
					        },{
 | 
				
			||||||
 | 
					            /* Deprecated in favour of tls-creds */
 | 
				
			||||||
            .name = "x509",
 | 
					            .name = "x509",
 | 
				
			||||||
            .type = QEMU_OPT_STRING,
 | 
					            .type = QEMU_OPT_STRING,
 | 
				
			||||||
        },{
 | 
					        },{
 | 
				
			||||||
@ -3286,9 +3286,11 @@ static QemuOptsList qemu_vnc_opts = {
 | 
				
			|||||||
            .name = "sasl",
 | 
					            .name = "sasl",
 | 
				
			||||||
            .type = QEMU_OPT_BOOL,
 | 
					            .type = QEMU_OPT_BOOL,
 | 
				
			||||||
        },{
 | 
					        },{
 | 
				
			||||||
 | 
					            /* Deprecated in favour of tls-creds */
 | 
				
			||||||
            .name = "tls",
 | 
					            .name = "tls",
 | 
				
			||||||
            .type = QEMU_OPT_BOOL,
 | 
					            .type = QEMU_OPT_BOOL,
 | 
				
			||||||
        },{
 | 
					        },{
 | 
				
			||||||
 | 
					            /* Deprecated in favour of tls-creds */
 | 
				
			||||||
            .name = "x509verify",
 | 
					            .name = "x509verify",
 | 
				
			||||||
            .type = QEMU_OPT_STRING,
 | 
					            .type = QEMU_OPT_STRING,
 | 
				
			||||||
        },{
 | 
					        },{
 | 
				
			||||||
@ -3306,13 +3308,12 @@ static QemuOptsList qemu_vnc_opts = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static int
 | 
				
			||||||
vnc_display_setup_auth(VncDisplay *vs,
 | 
					vnc_display_setup_auth(VncDisplay *vs,
 | 
				
			||||||
                       bool password,
 | 
					                       bool password,
 | 
				
			||||||
                       bool sasl,
 | 
					                       bool sasl,
 | 
				
			||||||
                       bool tls,
 | 
					                       bool websocket,
 | 
				
			||||||
                       bool x509,
 | 
					                       Error **errp)
 | 
				
			||||||
                       bool websocket)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * We have a choice of 3 authentication options
 | 
					     * We have a choice of 3 authentication options
 | 
				
			||||||
@ -3362,17 +3363,24 @@ vnc_display_setup_auth(VncDisplay *vs,
 | 
				
			|||||||
     * result has the same security characteristics.
 | 
					     * result has the same security characteristics.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    if (password) {
 | 
					    if (password) {
 | 
				
			||||||
        if (tls) {
 | 
					        if (vs->tlscreds) {
 | 
				
			||||||
            vs->auth = VNC_AUTH_VENCRYPT;
 | 
					            vs->auth = VNC_AUTH_VENCRYPT;
 | 
				
			||||||
            if (websocket) {
 | 
					            if (websocket) {
 | 
				
			||||||
                vs->ws_tls = true;
 | 
					                vs->ws_tls = true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (x509) {
 | 
					            if (object_dynamic_cast(OBJECT(vs->tlscreds),
 | 
				
			||||||
 | 
					                                    TYPE_QCRYPTO_TLS_CREDS_X509)) {
 | 
				
			||||||
                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
 | 
					                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
 | 
				
			||||||
                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
 | 
					                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
 | 
				
			||||||
            } else {
 | 
					            } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
 | 
				
			||||||
 | 
					                                           TYPE_QCRYPTO_TLS_CREDS_ANON)) {
 | 
				
			||||||
                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
 | 
					                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
 | 
				
			||||||
                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
 | 
					                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                error_setg(errp,
 | 
				
			||||||
 | 
					                           "Unsupported TLS cred type %s",
 | 
				
			||||||
 | 
					                           object_get_typename(OBJECT(vs->tlscreds)));
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            VNC_DEBUG("Initializing VNC server with password auth\n");
 | 
					            VNC_DEBUG("Initializing VNC server with password auth\n");
 | 
				
			||||||
@ -3385,17 +3393,24 @@ vnc_display_setup_auth(VncDisplay *vs,
 | 
				
			|||||||
            vs->ws_auth = VNC_AUTH_INVALID;
 | 
					            vs->ws_auth = VNC_AUTH_INVALID;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else if (sasl) {
 | 
					    } else if (sasl) {
 | 
				
			||||||
        if (tls) {
 | 
					        if (vs->tlscreds) {
 | 
				
			||||||
            vs->auth = VNC_AUTH_VENCRYPT;
 | 
					            vs->auth = VNC_AUTH_VENCRYPT;
 | 
				
			||||||
            if (websocket) {
 | 
					            if (websocket) {
 | 
				
			||||||
                vs->ws_tls = true;
 | 
					                vs->ws_tls = true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (x509) {
 | 
					            if (object_dynamic_cast(OBJECT(vs->tlscreds),
 | 
				
			||||||
 | 
					                                    TYPE_QCRYPTO_TLS_CREDS_X509)) {
 | 
				
			||||||
                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
 | 
					                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
 | 
				
			||||||
                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
 | 
					                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
 | 
				
			||||||
            } else {
 | 
					            } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
 | 
				
			||||||
 | 
					                                           TYPE_QCRYPTO_TLS_CREDS_ANON)) {
 | 
				
			||||||
                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
 | 
					                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
 | 
				
			||||||
                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
 | 
					                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                error_setg(errp,
 | 
				
			||||||
 | 
					                           "Unsupported TLS cred type %s",
 | 
				
			||||||
 | 
					                           object_get_typename(OBJECT(vs->tlscreds)));
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            VNC_DEBUG("Initializing VNC server with SASL auth\n");
 | 
					            VNC_DEBUG("Initializing VNC server with SASL auth\n");
 | 
				
			||||||
@ -3408,17 +3423,24 @@ vnc_display_setup_auth(VncDisplay *vs,
 | 
				
			|||||||
            vs->ws_auth = VNC_AUTH_INVALID;
 | 
					            vs->ws_auth = VNC_AUTH_INVALID;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        if (tls) {
 | 
					        if (vs->tlscreds) {
 | 
				
			||||||
            vs->auth = VNC_AUTH_VENCRYPT;
 | 
					            vs->auth = VNC_AUTH_VENCRYPT;
 | 
				
			||||||
            if (websocket) {
 | 
					            if (websocket) {
 | 
				
			||||||
                vs->ws_tls = true;
 | 
					                vs->ws_tls = true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (x509) {
 | 
					            if (object_dynamic_cast(OBJECT(vs->tlscreds),
 | 
				
			||||||
 | 
					                                    TYPE_QCRYPTO_TLS_CREDS_X509)) {
 | 
				
			||||||
                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
 | 
					                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
 | 
				
			||||||
                vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
 | 
					                vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
 | 
				
			||||||
            } else {
 | 
					            } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
 | 
				
			||||||
 | 
					                                           TYPE_QCRYPTO_TLS_CREDS_ANON)) {
 | 
				
			||||||
                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
 | 
					                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
 | 
				
			||||||
                vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
 | 
					                vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                error_setg(errp,
 | 
				
			||||||
 | 
					                           "Unsupported TLS cred type %s",
 | 
				
			||||||
 | 
					                           object_get_typename(OBJECT(vs->tlscreds)));
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            VNC_DEBUG("Initializing VNC server with no auth\n");
 | 
					            VNC_DEBUG("Initializing VNC server with no auth\n");
 | 
				
			||||||
@ -3431,8 +3453,55 @@ vnc_display_setup_auth(VncDisplay *vs,
 | 
				
			|||||||
            vs->ws_auth = VNC_AUTH_INVALID;
 | 
					            vs->ws_auth = VNC_AUTH_INVALID;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Handle back compat with old CLI syntax by creating some
 | 
				
			||||||
 | 
					 * suitable QCryptoTLSCreds objects
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static QCryptoTLSCreds *
 | 
				
			||||||
 | 
					vnc_display_create_creds(bool x509,
 | 
				
			||||||
 | 
					                         bool x509verify,
 | 
				
			||||||
 | 
					                         const char *dir,
 | 
				
			||||||
 | 
					                         const char *id,
 | 
				
			||||||
 | 
					                         Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gchar *credsid = g_strdup_printf("tlsvnc%s", id);
 | 
				
			||||||
 | 
					    Object *parent = object_get_objects_root();
 | 
				
			||||||
 | 
					    Object *creds;
 | 
				
			||||||
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (x509) {
 | 
				
			||||||
 | 
					        creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_X509,
 | 
				
			||||||
 | 
					                                      parent,
 | 
				
			||||||
 | 
					                                      credsid,
 | 
				
			||||||
 | 
					                                      &err,
 | 
				
			||||||
 | 
					                                      "endpoint", "server",
 | 
				
			||||||
 | 
					                                      "dir", dir,
 | 
				
			||||||
 | 
					                                      "verify-peer", x509verify ? "yes" : "no",
 | 
				
			||||||
 | 
					                                      NULL);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON,
 | 
				
			||||||
 | 
					                                      parent,
 | 
				
			||||||
 | 
					                                      credsid,
 | 
				
			||||||
 | 
					                                      &err,
 | 
				
			||||||
 | 
					                                      "endpoint", "server",
 | 
				
			||||||
 | 
					                                      NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_free(credsid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (err) {
 | 
				
			||||||
 | 
					        error_propagate(errp, err);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return QCRYPTO_TLS_CREDS(creds);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void vnc_display_open(const char *id, Error **errp)
 | 
					void vnc_display_open(const char *id, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    VncDisplay *vs = vnc_display_find(id);
 | 
					    VncDisplay *vs = vnc_display_find(id);
 | 
				
			||||||
@ -3447,18 +3516,13 @@ void vnc_display_open(const char *id, Error **errp)
 | 
				
			|||||||
    char *h;
 | 
					    char *h;
 | 
				
			||||||
    bool has_ipv4 = false;
 | 
					    bool has_ipv4 = false;
 | 
				
			||||||
    bool has_ipv6 = false;
 | 
					    bool has_ipv6 = false;
 | 
				
			||||||
 | 
					    const char *credid;
 | 
				
			||||||
    const char *websocket;
 | 
					    const char *websocket;
 | 
				
			||||||
    bool tls = false, x509 = false;
 | 
					 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					 | 
				
			||||||
    const char *path;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    bool sasl = false;
 | 
					    bool sasl = false;
 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
    int saslErr;
 | 
					    int saslErr;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
 | 
					 | 
				
			||||||
    int acl = 0;
 | 
					    int acl = 0;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    int lock_key_sync = 1;
 | 
					    int lock_key_sync = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!vs) {
 | 
					    if (!vs) {
 | 
				
			||||||
@ -3539,32 +3603,67 @@ void vnc_display_open(const char *id, Error **errp)
 | 
				
			|||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif /* CONFIG_VNC_SASL */
 | 
					#endif /* CONFIG_VNC_SASL */
 | 
				
			||||||
 | 
					    credid = qemu_opt_get(opts, "tls-creds");
 | 
				
			||||||
 | 
					    if (credid) {
 | 
				
			||||||
 | 
					        Object *creds;
 | 
				
			||||||
 | 
					        if (qemu_opt_get(opts, "tls") ||
 | 
				
			||||||
 | 
					            qemu_opt_get(opts, "x509") ||
 | 
				
			||||||
 | 
					            qemu_opt_get(opts, "x509verify")) {
 | 
				
			||||||
 | 
					            error_setg(errp,
 | 
				
			||||||
 | 
					                       "'credid' parameter is mutually exclusive with "
 | 
				
			||||||
 | 
					                       "'tls', 'x509' and 'x509verify' parameters");
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        creds = object_resolve_path_component(
 | 
				
			||||||
 | 
					            object_get_objects_root(), credid);
 | 
				
			||||||
 | 
					        if (!creds) {
 | 
				
			||||||
 | 
					            error_setg(errp, "No TLS credentials with id '%s'",
 | 
				
			||||||
 | 
					                       credid);
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        vs->tlscreds = (QCryptoTLSCreds *)
 | 
				
			||||||
 | 
					            object_dynamic_cast(creds,
 | 
				
			||||||
 | 
					                                TYPE_QCRYPTO_TLS_CREDS);
 | 
				
			||||||
 | 
					        if (!vs->tlscreds) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Object with id '%s' is not TLS credentials",
 | 
				
			||||||
 | 
					                       credid);
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        object_ref(OBJECT(vs->tlscreds));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (vs->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
 | 
				
			||||||
 | 
					            error_setg(errp,
 | 
				
			||||||
 | 
					                       "Expecting TLS credentials with a server endpoint");
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        const char *path;
 | 
				
			||||||
 | 
					        bool tls = false, x509 = false, x509verify = false;
 | 
				
			||||||
        tls  = qemu_opt_get_bool(opts, "tls", false);
 | 
					        tls  = qemu_opt_get_bool(opts, "tls", false);
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					        if (tls) {
 | 
				
			||||||
            path = qemu_opt_get(opts, "x509");
 | 
					            path = qemu_opt_get(opts, "x509");
 | 
				
			||||||
    if (!path) {
 | 
					
 | 
				
			||||||
        path = qemu_opt_get(opts, "x509verify");
 | 
					 | 
				
			||||||
        if (path) {
 | 
					 | 
				
			||||||
            vs->tls.x509verify = true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
            if (path) {
 | 
					            if (path) {
 | 
				
			||||||
                x509 = true;
 | 
					                x509 = true;
 | 
				
			||||||
        if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
 | 
					            } else {
 | 
				
			||||||
            error_setg(errp, "Failed to find x509 certificates/keys in %s",
 | 
					                path = qemu_opt_get(opts, "x509verify");
 | 
				
			||||||
                       path);
 | 
					                if (path) {
 | 
				
			||||||
 | 
					                    x509 = true;
 | 
				
			||||||
 | 
					                    x509verify = true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            vs->tlscreds = vnc_display_create_creds(x509,
 | 
				
			||||||
 | 
					                                                    x509verify,
 | 
				
			||||||
 | 
					                                                    path,
 | 
				
			||||||
 | 
					                                                    vs->id,
 | 
				
			||||||
 | 
					                                                    errp);
 | 
				
			||||||
 | 
					            if (!vs->tlscreds) {
 | 
				
			||||||
                goto fail;
 | 
					                goto fail;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
#else /* ! CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
    if (tls) {
 | 
					 | 
				
			||||||
        error_setg(errp, "VNC TLS auth requires gnutls support");
 | 
					 | 
				
			||||||
        goto fail;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif /* ! CONFIG_VNC_TLS */
 | 
					 | 
				
			||||||
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
 | 
					 | 
				
			||||||
    acl = qemu_opt_get_bool(opts, "acl", false);
 | 
					    acl = qemu_opt_get_bool(opts, "acl", false);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    share = qemu_opt_get(opts, "share");
 | 
					    share = qemu_opt_get(opts, "share");
 | 
				
			||||||
    if (share) {
 | 
					    if (share) {
 | 
				
			||||||
@ -3604,19 +3703,14 @@ void vnc_display_open(const char *id, Error **errp)
 | 
				
			|||||||
        vs->non_adaptive = true;
 | 
					        vs->non_adaptive = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    if (acl) {
 | 
				
			||||||
    if (acl && x509 && vs->tls.x509verify) {
 | 
					 | 
				
			||||||
        char *aclname;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (strcmp(vs->id, "default") == 0) {
 | 
					        if (strcmp(vs->id, "default") == 0) {
 | 
				
			||||||
            aclname = g_strdup("vnc.x509dname");
 | 
					            vs->tlsaclname = g_strdup("vnc.x509dname");
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            aclname = g_strdup_printf("vnc.%s.x509dname", vs->id);
 | 
					            vs->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vs->id);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        vs->tls.acl = qemu_acl_init(aclname);
 | 
					        qemu_acl_init(vs->tlsaclname);
 | 
				
			||||||
        g_free(aclname);
 | 
					 | 
				
			||||||
     }
 | 
					     }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
    if (acl && sasl) {
 | 
					    if (acl && sasl) {
 | 
				
			||||||
        char *aclname;
 | 
					        char *aclname;
 | 
				
			||||||
@ -3631,7 +3725,9 @@ void vnc_display_open(const char *id, Error **errp)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vnc_display_setup_auth(vs, password, sasl, tls, x509, websocket);
 | 
					    if (vnc_display_setup_auth(vs, password, sasl, websocket, errp) < 0) {
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
 | 
					    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										21
									
								
								ui/vnc.h
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								ui/vnc.h
									
									
									
									
									
								
							@ -33,6 +33,7 @@
 | 
				
			|||||||
#include "ui/console.h"
 | 
					#include "ui/console.h"
 | 
				
			||||||
#include "audio/audio.h"
 | 
					#include "audio/audio.h"
 | 
				
			||||||
#include "qemu/bitmap.h"
 | 
					#include "qemu/bitmap.h"
 | 
				
			||||||
 | 
					#include "crypto/tlssession.h"
 | 
				
			||||||
#include <zlib.h>
 | 
					#include <zlib.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -101,10 +102,7 @@ typedef void VncSendHextileTile(VncState *vs,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
typedef struct VncDisplay VncDisplay;
 | 
					typedef struct VncDisplay VncDisplay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					 | 
				
			||||||
#include "vnc-tls.h"
 | 
					 | 
				
			||||||
#include "vnc-auth-vencrypt.h"
 | 
					#include "vnc-auth-vencrypt.h"
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
#include "vnc-auth-sasl.h"
 | 
					#include "vnc-auth-sasl.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -181,9 +179,8 @@ struct VncDisplay
 | 
				
			|||||||
    bool ws_tls; /* Used by websockets */
 | 
					    bool ws_tls; /* Used by websockets */
 | 
				
			||||||
    bool lossy;
 | 
					    bool lossy;
 | 
				
			||||||
    bool non_adaptive;
 | 
					    bool non_adaptive;
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    QCryptoTLSCreds *tlscreds;
 | 
				
			||||||
    VncDisplayTLS tls;
 | 
					    char *tlsaclname;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
    VncDisplaySASL sasl;
 | 
					    VncDisplaySASL sasl;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -284,9 +281,7 @@ struct VncState
 | 
				
			|||||||
    int auth;
 | 
					    int auth;
 | 
				
			||||||
    int subauth; /* Used by VeNCrypt */
 | 
					    int subauth; /* Used by VeNCrypt */
 | 
				
			||||||
    char challenge[VNC_AUTH_CHALLENGE_SIZE];
 | 
					    char challenge[VNC_AUTH_CHALLENGE_SIZE];
 | 
				
			||||||
#ifdef CONFIG_VNC_TLS
 | 
					    QCryptoTLSSession *tls;
 | 
				
			||||||
    VncStateTLS tls;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef CONFIG_VNC_SASL
 | 
					#ifdef CONFIG_VNC_SASL
 | 
				
			||||||
    VncStateSASL sasl;
 | 
					    VncStateSASL sasl;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -513,8 +508,10 @@ enum {
 | 
				
			|||||||
void vnc_client_read(void *opaque);
 | 
					void vnc_client_read(void *opaque);
 | 
				
			||||||
void vnc_client_write(void *opaque);
 | 
					void vnc_client_write(void *opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen);
 | 
					ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen);
 | 
				
			||||||
long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen);
 | 
					ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen);
 | 
				
			||||||
 | 
					ssize_t vnc_tls_pull(char *buf, size_t len, void *opaque);
 | 
				
			||||||
 | 
					ssize_t vnc_tls_push(const char *buf, size_t len, void *opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Protocol I/O functions */
 | 
					/* Protocol I/O functions */
 | 
				
			||||||
void vnc_write(VncState *vs, const void *data, size_t len);
 | 
					void vnc_write(VncState *vs, const void *data, size_t len);
 | 
				
			||||||
@ -533,7 +530,7 @@ uint32_t read_u32(uint8_t *data, size_t offset);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Protocol stage functions */
 | 
					/* Protocol stage functions */
 | 
				
			||||||
void vnc_client_error(VncState *vs);
 | 
					void vnc_client_error(VncState *vs);
 | 
				
			||||||
int vnc_client_io_error(VncState *vs, int ret, int last_errno);
 | 
					ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, int last_errno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void start_client_init(VncState *vs);
 | 
					void start_client_init(VncState *vs);
 | 
				
			||||||
void start_auth_vnc(VncState *vs);
 | 
					void start_auth_vnc(VncState *vs);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user