Commit c5cb1afc authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/bonzini/configure' into staging



* remotes/bonzini/configure:
  rules.mak: Rewrite unnest-vars
  configure: unset interfering variables
  configure: duplicate/incorrect order of -lrt
  libcacard: improve documentation
  libcacard: actually use symbols file
  libcacard: replace qemu thread primitives with glib ones
  vscclient: use glib thread primitives not qemu
  glib-compat.h: add new thread API emulation on top of pre-2.31 API

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents b780bf8e 1c33ac57
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -3,6 +3,11 @@
# qemu configure script (c) 2003 Fabrice Bellard
#

# Unset some variables known to interfere with behavior of common tools,
# just as autoconf does.
CLICOLOR_FORCE= GREP_OPTIONS=
unset CLICOLOR_FORCE GREP_OPTIONS

# Temporary directory used for files created while
# configure runs. Since it is in the build directory
# we can safely blow away any previous version of it
@@ -3452,9 +3457,9 @@ EOF
if compile_prog "" "" ; then
  :
# we need pthread for static linking. use previous pthread test result
elif compile_prog "" "-lrt $pthread_lib" ; then
  LIBS="-lrt $LIBS"
  libs_qga="-lrt $libs_qga"
elif compile_prog "" "$pthread_lib -lrt" ; then
  LIBS="$LIBS -lrt"
  libs_qga="$libs_qga -lrt"
fi

if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \
+8 −21
Original line number Diff line number Diff line
@@ -30,20 +30,14 @@ typedef struct {
    CoroutineAction action;
} CoroutineGThread;

static GStaticMutex coroutine_lock = G_STATIC_MUTEX_INIT;
static CompatGMutex coroutine_lock;
static CompatGCond coroutine_cond;

/* GLib 2.31 and beyond deprecated various parts of the thread API,
 * but the new interfaces are not available in older GLib versions
 * so we have to cope with both.
 */
#if GLIB_CHECK_VERSION(2, 31, 0)
/* Default zero-initialisation is sufficient for 2.31+ GCond */
static GCond the_coroutine_cond;
static GCond *coroutine_cond = &the_coroutine_cond;
static inline void init_coroutine_cond(void)
{
}

/* Awkwardly, the GPrivate API doesn't provide a way to update the
 * GDestroyNotify handler for the coroutine key dynamically. So instead
 * we track whether or not the CoroutineGThread should be freed on
@@ -84,11 +78,6 @@ static inline GThread *create_thread(GThreadFunc func, gpointer data)
#else

/* Handle older GLib versions */
static GCond *coroutine_cond;
static inline void init_coroutine_cond(void)
{
    coroutine_cond = g_cond_new();
}

static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT;

@@ -120,22 +109,20 @@ static void __attribute__((constructor)) coroutine_init(void)
        g_thread_init(NULL);
    }
#endif

    init_coroutine_cond();
}

static void coroutine_wait_runnable_locked(CoroutineGThread *co)
{
    while (!co->runnable) {
        g_cond_wait(coroutine_cond, g_static_mutex_get_mutex(&coroutine_lock));
        g_cond_wait(&coroutine_cond, &coroutine_lock);
    }
}

static void coroutine_wait_runnable(CoroutineGThread *co)
{
    g_static_mutex_lock(&coroutine_lock);
    g_mutex_lock(&coroutine_lock);
    coroutine_wait_runnable_locked(co);
    g_static_mutex_unlock(&coroutine_lock);
    g_mutex_unlock(&coroutine_lock);
}

static gpointer coroutine_thread(gpointer opaque)
@@ -177,17 +164,17 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_,
    CoroutineGThread *from = DO_UPCAST(CoroutineGThread, base, from_);
    CoroutineGThread *to = DO_UPCAST(CoroutineGThread, base, to_);

    g_static_mutex_lock(&coroutine_lock);
    g_mutex_lock(&coroutine_lock);
    from->runnable = false;
    from->action = action;
    to->runnable = true;
    to->action = action;
    g_cond_broadcast(coroutine_cond);
    g_cond_broadcast(&coroutine_cond);

    if (action != COROUTINE_TERMINATE) {
        coroutine_wait_runnable_locked(from);
    }
    g_static_mutex_unlock(&coroutine_lock);
    g_mutex_unlock(&coroutine_lock);
    return from->action;
}

+63 −17
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ In ubuntu/debian:
Configuring and building:
    ./configure --enable-smartcard && make


3. Using ccid-card-emulated with hardware

Assuming you have a working smartcard on the host with the current
@@ -54,19 +55,55 @@ user, using NSS, qemu acts as another NSS client using ccid-card-emulated:

    qemu -usb -device usb-ccid -device ccid-card-emulated

4. Using ccid-card-emulated with certificates

You must create the certificates. This is a one time process. We use NSS
certificates:
4. Using ccid-card-emulated with certificates stored in files

You must create the CA and card certificates. This is a one time process.
We use NSS certificates:

    certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=cert1" -n cert1
    mkdir fake-smartcard
    cd fake-smartcard
    certutil -N -d sql:$PWD
    certutil -S -d sql:$PWD -s "CN=Fake Smart Card CA" -x -t TC,TC,TC -n fake-smartcard-ca
    certutil -S -d sql:$PWD -t ,, -s "CN=John Doe" -n id-cert -c fake-smartcard-ca
    certutil -S -d sql:$PWD -t ,, -s "CN=John Doe (signing)" --nsCertType smime -n signing-cert -c fake-smartcard-ca
    certutil -S -d sql:$PWD -t ,, -s "CN=John Doe (encryption)" --nsCertType sslClient -n encryption-cert -c fake-smartcard-ca

Note: you must have exactly three certificates.

Assuming the current user can access the certificates (use certutil -L to
verify), you can use the emulated card type with the certificates backend:
You can use the emulated card type with the certificates backend:

    qemu -usb -device usb-ccid -device ccid-card-emulated,backend=certificates,db=sql:$PWD,cert1=id-cert,cert2=signing-cert,cert3=encryption-cert

To use the certificates in the guest, export the CA certificate:

    certutil -L -r -d sql:$PWD -o fake-smartcard-ca.cer -n fake-smartcard-ca

and import it in the guest:

    certutil -A -d /etc/pki/nssdb -i fake-smartcard-ca.cer -t TC,TC,TC -n fake-smartcard-ca

In a Linux guest you can then use the CoolKey PKCS #11 module to access
the card:

    certutil -d /etc/pki/nssdb -L -h all

It will prompt you for the PIN (which is the password you assigned to the
certificate database early on), and then show you all three certificates
together with the manually imported CA cert:

    Certificate Nickname                        Trust Attributes
    fake-smartcard-ca                           CT,C,C
    John Doe:CAC ID Certificate                 u,u,u
    John Doe:CAC Email Signature Certificate    u,u,u
    John Doe:CAC Email Encryption Certificate   u,u,u

If this does not happen, CoolKey is not installed or not registered with
NSS.  Registration can be done from Firefox or the command line:

    modutil -dbdir /etc/pki/nssdb -add "CAC Module" -libfile /usr/lib64/pkcs11/libcoolkeypk11.so
    modutil -dbdir /etc/pki/nssdb -list

    qemu -usb -device usb-ccid -device ccid-card-emulated,backend=certificates,cert1=cert1,cert2=cert2,cert3=cert3

5. Using ccid-card-passthru with client side hardware

@@ -74,15 +111,23 @@ on the host specify the ccid-card-passthru device with a suitable chardev:

    qemu -chardev socket,server,host=0.0.0.0,port=2001,id=ccid,nowait -usb -device usb-ccid -device ccid-card-passthru,chardev=ccid

on the client run vscclient, built when you built the libcacard library:
    libcacard/vscclient <qemu-host> 2001
on the client run vscclient, built when you built QEMU:

    vscclient <qemu-host> 2001


6. Using ccid-card-passthru with client side certificates

Run qemu as per #5, and run vscclient as follows:
(Note: vscclient command line interface is in a state of change)
This case is not particularly useful, but you can use it to debug
your setup if #4 works but #5 does not.

Follow instructions as per #4, except run QEMU and vscclient as follows:
Run qemu as per #5, and run vscclient from the "fake-smartcard"
directory as follows:

    qemu -chardev socket,server,host=0.0.0.0,port=2001,id=ccid,nowait -usb -device usb-ccid -device ccid-card-passthru,chardev=ccid
    vscclient -e "db=\"sql:$PWD\" use_hw=no soft=(,Test,CAC,,id-cert,signing-cert,encryption-cert)" <qemu-host> 2001

    libcacard/vscclient -e "db=\"/etc/pki/nssdb\" use_hw=no soft=(,Test,CAC,,cert1,cert2,cert3)" <qemu-host> 2001

7. Passthrough protocol scenario

@@ -126,10 +171,11 @@ kill/quit | | | |

8. libcacard

ccid-card-passthru and vscclient use libcacard as the card emulator.
libcacard implements a completely virtual CAC (DoD standard for smart cards)
compliant card and uses NSS to actually retrive certificates and do any
encryption using the backend (real reader + card or file backed certificates).
Both ccid-card-emulated and vscclient use libcacard as the card emulator.
libcacard implements a completely virtual CAC (DoD standard for smart
cards) compliant card and uses NSS to retrieve certificates and do
any encryption.  The backend can then be a real reader and card, or
certificates stored in files.

For documentation of cac_card see README in libcacard subdirectory.
For documentation of the library see docs/libcacard.txt.
+119 −0
Original line number Diff line number Diff line
@@ -5,6 +5,8 @@
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *  Michael Tokarev   <mjt@tls.msk.ru>
 *  Paolo Bonzini     <pbonzini@redhat.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
@@ -43,4 +45,121 @@ static inline gint g_poll(GPollFD *fds, guint nfds, gint timeout)
}
#endif

#if !GLIB_CHECK_VERSION(2, 31, 0)
/* before glib-2.31, GMutex and GCond was dynamic-only (there was a separate
 * GStaticMutex, but it didn't work with condition variables).
 *
 * Our implementation uses GOnce to fake a static implementation that does
 * not require separate initialization.
 * We need to rename the types to avoid passing our CompatGMutex/CompatGCond
 * by mistake to a function that expects GMutex/GCond.  However, for ease
 * of use we keep the GLib function names.  GLib uses macros for the
 * implementation, we use inline functions instead and undefine the macros.
 */

typedef struct CompatGMutex {
    GOnce once;
} CompatGMutex;

typedef struct CompatGCond {
    GOnce once;
} CompatGCond;

static inline gpointer do_g_mutex_new(gpointer unused)
{
    return (gpointer) g_mutex_new();
}

static inline void g_mutex_init(CompatGMutex *mutex)
{
    mutex->once = (GOnce) G_ONCE_INIT;
}

static inline void g_mutex_clear(CompatGMutex *mutex)
{
    assert(mutex->once.status != G_ONCE_STATUS_PROGRESS);
    if (mutex->once.retval) {
        g_mutex_free((GMutex *) mutex->once.retval);
    }
    mutex->once = (GOnce) G_ONCE_INIT;
}

static inline void (g_mutex_lock)(CompatGMutex *mutex)
{
    g_once(&mutex->once, do_g_mutex_new, NULL);
    g_mutex_lock((GMutex *) mutex->once.retval);
}
#undef g_mutex_lock

static inline gboolean (g_mutex_trylock)(CompatGMutex *mutex)
{
    g_once(&mutex->once, do_g_mutex_new, NULL);
    return g_mutex_trylock((GMutex *) mutex->once.retval);
}
#undef g_mutex_trylock


static inline void (g_mutex_unlock)(CompatGMutex *mutex)
{
    g_mutex_unlock((GMutex *) mutex->once.retval);
}
#undef g_mutex_unlock

static inline gpointer do_g_cond_new(gpointer unused)
{
    return (gpointer) g_cond_new();
}

static inline void g_cond_init(CompatGCond *cond)
{
    cond->once = (GOnce) G_ONCE_INIT;
}

static inline void g_cond_clear(CompatGCond *cond)
{
    assert(cond->once.status != G_ONCE_STATUS_PROGRESS);
    if (cond->once.retval) {
        g_cond_free((GCond *) cond->once.retval);
    }
    cond->once = (GOnce) G_ONCE_INIT;
}

static inline void (g_cond_wait)(CompatGCond *cond, CompatGMutex *mutex)
{
    assert(mutex->once.status != G_ONCE_STATUS_PROGRESS);
    g_once(&cond->once, do_g_cond_new, NULL);
    g_cond_wait((GCond *) cond->once.retval, (GMutex *) mutex->once.retval);
}
#undef g_cond_wait

static inline void (g_cond_broadcast)(CompatGCond *cond)
{
    g_once(&cond->once, do_g_cond_new, NULL);
    g_cond_broadcast((GCond *) cond->once.retval);
}
#undef g_cond_broadcast

static inline void (g_cond_signal)(CompatGCond *cond)
{
    g_once(&cond->once, do_g_cond_new, NULL);
    g_cond_signal((GCond *) cond->once.retval);
}
#undef g_cond_signal


/* before 2.31 there was no g_thread_new() */
static inline GThread *g_thread_new(const char *name,
                                    GThreadFunc func, gpointer data)
{
    GThread *thread = g_thread_create(func, data, TRUE, NULL);
    if (!thread) {
        g_error("creating thread");
    }
    return thread;
}
#else
#define CompatGMutex GMutex
#define CompatGCond GCond
#endif /* glib 2.31 */

#endif
+2 −8
Original line number Diff line number Diff line
@@ -3,13 +3,7 @@ libcacard_includedir=$(includedir)/cacard
TOOLS += vscclient$(EXESUF)

# objects linked into a shared library, built with libtool with -fPIC if required
libcacard-obj-y = $(stub-obj-y) $(libcacard-y)
libcacard-obj-y += util/osdep.o util/cutils.o util/qemu-timer-common.o
libcacard-obj-y += util/error.o util/qemu-error.o
libcacard-obj-$(CONFIG_WIN32) += util/oslib-win32.o util/qemu-thread-win32.o
libcacard-obj-$(CONFIG_POSIX) += util/oslib-posix.o util/qemu-thread-posix.o
libcacard-obj-y += $(filter trace/%, $(util-obj-y))

libcacard-obj-y = $(libcacard-y)
libcacard-lobj-y=$(patsubst %.o,%.lo,$(libcacard-obj-y))

# libtool will build the .o files, too
@@ -24,7 +18,7 @@ vscclient$(EXESUF): libcacard/vscclient.o libcacard.la
# Rules for building libcacard standalone library

libcacard.la: LDFLAGS += -rpath $(libdir) -no-undefined \
	-export-syms $(SRC_PATH)/libcacard/libcacard.syms
	-export-symbols $(SRC_PATH)/libcacard/libcacard.syms
libcacard.la: $(libcacard-lobj-y)
	$(call LINK,$^)

Loading