[libvirt] adding smartcard support to libvirt

Eric Blake eblake at redhat.com
Mon Jan 3 18:50:18 UTC 2011


[adding the public list for feedback on new XML. Background: Alon is
working on adding some new command line arguments to qemu to make it
possible to share smartcard access between a host and its virtual
guests; while this is not upstream yet, libvirt should be prepared to
handle the new command line options]

[lengthy email; skip to the tail end for a high-level summary of
proposed XML changes]

On 12/22/2010 03:00 AM, Alon Levy wrote:
> On Mon, Dec 20, 2010 at 12:19:42PM -0700, Eric Blake wrote:
>> I also found the following which also served as a good overview for what
>> you are proposing to add to qemu:
>>
>> http://cgit.freedesktop.org/~alon/qemu/commit/?h=usb_ccid.v9&id=d5484a05
> 
> Of course, sorry, should have pointed you to that initially. I wrote the
> ccid.txt one, the other is Robert Relyea's (the author of the libcacard
> library).
> 
>>
>> Right now, I'm thinking of adding a new <smartcard> element under
>> <devices>.  Let me know if this makes sense or needs tweaking; once the
>> XML is in place, I can then figure out how to map to qemu command lines
>> pretty easily.

> 
> Ok, so to make a little order: There are three devices being added to qemu,
> they are:
>  * usb-ccid - this is both a usb device and a ccid bus. The rest of the devices
>   attach to this bus (so they don't care that the bus is actually a usb device
>   itself, same as a PCI device exposing an IDE bus).
>  * ccid-card-emulated - this device uses NSS directly, so it can work in two modes:
>   * no arguments at all - in this case it will look for whatever hardware NSS can
>    access by default. This will depend on the specific host setup, and on the user
>    credentials qemu is running under.
>   * cert1, cert2, cert3 arguments - in this case NSS will look for three certs
>    with the names supplied, and use them instead of any physical hardware. In this case qemu
>    just needs to have those certificates available, and no physical hardware is required.
>  * ccid-card-passthru - this device doesn't rely on NSS at all. Instead it uses a chardevice,
>   and implements the VSCard protocol over it, which is just a simple protocol for remoting
>   the CCID requests (actually it works in the APDU level, so it doesn't care for CCID specifically,
>   but then again if you read the CCID you'll notice the main messages are XferBlock which just passes
>   an APDU along too).
>   Here there are also two basic options, depending on which char device we want to use. Of course you
>   are not limited to these two, you can use any chardevice, but I've been using only these two and
>   I can't think of a use for any other right now:
>   * tcp socket char device - in this case you can use the accompanying libcacard/vscclient program
>    running on another (or the same) machine, it uses NSS in exactly the same ways (certs/hw) as described
>    above for the emulated card (which is of course natural since it is using the same library to do
>    that, libcacard).
>   * spice chardevice - this is a chardevice that uses libspice, which is linked with qemu. spice in
>    turn will use a channel to the client which links with libcacard. This device is available here:
>     http://lists.gnu.org/archive/html/qemu-devel/2010-12/msg01442.html
>    as you can see from that thread, it isn't accepted yet, but anthony told me he wants to schedule
>    vdagent (and by extension, spice chardevice, i.e. spicevmc chardev) talk to qemu community meeting
>    after new years.
> 
>
> So I hope you understand that you do in fact need some device, in this
case
> the usb-ccid device, it's only the card emulated that uses the
certificates,
> not the bus device. The bus device remains the same for all of the various
> configurations.
>

Just to restate (to make sure I'm understanding you correctly),
smartcard support in qemu requires that you enable two things: the
usb-ccid device, and your choice of the ccid-card-emulated device or the
ccid-card-passthru device.  The ccid-card-emulated device operates in
two modes, and the ccid-card-passthru device uses a protocol to talk
through a required associated chardev (where the other end of the
chardev can operate in two modes, but that's outside of what the guest
can see; and where two particular chardevs make the most sense).

> So after this lengthy summary, you see that actually the mode tag is good, I guess also the names
> you set are good.

Picking the right mode names is probably the hardest part of writing new
XML in a way that can be reused across other hypervisor technologies if
similar approaches are adopted there, as well as allowing reasonable XML
additions in the future, which is why I'm opening the feedback to make
sure it all looks good.

>>>  * passthrough from a host attached smartcard reader. (despite
passthrough in the use
>>>   case name, this is actually done using the ccid-card-emulated device)
>>
>> <domain...>
>>   <devices>
>>     <smartcard mode='host'>
>>        <source path='usb-ccid'/>
>>     </smartcard>
>>   </devices>
>> </domain>
>>
>> maps to qemu -usb -device usb-ccid -device ccid-card-emulated

> I don't really grok the "source path='usb-ccid'", unless you just want
to ensure
> that this can be replaced with other devices in the future, which in
this case sounds good to me.
>

Then <source> isn't quite the right terminology for this.  If we ever do
come up with a future qemu device that can replace usb-ccid while still
providing everything needed for the ccid-card-emulated device to work,
then we can augment the XML at that point for choosing how to replace
the usb-ccid device, but I don't think we need to tie it to <source> for
the current proposal.

So, this mode can be simplified.  In other words, requesting mode='host'
implies turning on anything in the hypervisor necessary to let the
hypervisor use NSS access to the host's smartcard support (in qemu's
case, turning on both the usb-ccid device and the ccid-card-emulated
device with no arguments).  Therefore, mode='host' wouldn't need any
sub-elements for now.

<domain...>
  <devices>
    <smartcard mode='host'/>
  </devices>
</domain>

>>>  * passthrough from a client via vscclient program (this is done using ccid-card-passthrough
>>>   but with a standard tcp chardevice)
>>
>> <domain...>
>>   <devices>
>>     <smartcard mode='certificates'>
>>       <source path='usb-ccid'/>
>>       <certificate id='1' path='cert1'/>
>>       <certificate id='2' path='cert2'/>
>>       <certificate id='3' path='cert3'/>
>>     </smartcard>
>>  </devices>
>> </domain>
>>
>> maps to qemu -usb -device usb-ccid -device
>>
ccid-card-emulated,backend=certificates,cert1=cert1,cert2=cert2,cert3=cert3
>>
>> Libvirt will have to ensure that the qemu user has access rights to read
>> the three certificate files on the host.  My idea here is that
>> mode='certificates' requires an element for the host source, as well as
>> paths to the three host certificates.

> Also, maybe call certificates mode host-certificates, just to make it
obvious?

So, here's the updated proposal (again, dropping a <source> element, and
picking a better mode name):

<domain...>
  <devices>
    <smartcard mode='host-certificates'>
      <certificate id='1' path='cert1'/>
      <certificate id='2' path='cert2'/>
      <certificate id='3' path='cert3'/>
    </smartcard>
 </devices>
</domain>

>>>  * passthrough with spice ('my' use case, -chardev spicevmc,id=smartcard,name=smartcard -device ccid-card-passthru,chardev=smartcard)
>>
>> <domain...>
>>   <devices>
>>     <smartcard mode='passthrough' name='smartcard'>
>>       <serial type='smartcard'>
>>         <source path='spicevmc'/>
>>       </serial>
>>     </smartcard>
>>   </devices>
>> </domain
>>
>> maps to qemu -chardev spicevmc,id=smartcard,name=smartcard -device
>> ccid-card-passthru,chardev=smartcard

>> My idea here is that mode='passthrough' requires a name, which then gets
>> used to create both the smartcard passthrough device and the backing
>> chardev device.  Then, as a child element, <smartcard> contains any
>> other valid element that could serve as a top-level device, such as
>> <serial type='tcp'>.

>>
> 
> Ok, so this is wrong - there are actually two source paths, if I understand
> the idea - you would still want to explicitly specify usb-ccid (again, assuming this
> is a future proofing for changing the underlying device), and the other would be
> the spicevmc, and it would translate to the following command line:
> 
> qemu -chardev spicevmc,id=smartcard,name=smartcard -usb -device usb-ccid
> -device ccud-card-passthru,chardev=smartcard
> 
> I guess something like:
> 
> <smartcard mode='passthrough' name='smartcard'>
>  <source path='usb-ccid'/>
>  <serial type='smartcard'>
>   <source path='spicevmc'/>
>  </serial>
> </smartcard>

So the key point here is that use of the ccid-card-passthru device
requires a chardev=xyz argument that maps to another existing -chardev
device.  And given that the chardev device in use is essential to the
smartcard support, I'm proposing that the <smartcard> element require
the paired chardev device as a sub-element, rather than as a sibling
element.

Right now, the XML for <devices> allows the following <serial> types:
dev, file, pipe, unix, tcp, udp, null, stdio, vc, pty

so there's no notion of a type='smartcard'.  It looks more like the new
serial type is 'spicevmc'.  And back to my idea of omitting mention of
usb-ccid in the XML, and refactoring things to avoid dupicate use of
strings (to make it a bit more obvious which XML aspects impact which
command-line aspects), that leaves us with:

<domain...>
  <devices>
    <smartcard mode='passthrough' name='xyz'>
      <serial type='spicevmc'/>
    </smartcard>
  </devices>
</domain>

maps to qemu -chardev spicevmc,id=smartcard,name=xyz -usb -device
usb-ccid -device ccid-card-passthru,chardev=xyz

Am I correct that a spicevmc -chardev has to use a fixed id=smartcard
but an arbitrary name, and that ccid-card-passthru has to have a
chardev=name that maps to the same name= used for a -chardev?  Or is it
that ccid-card-passthru has to have a chardev=name that maps to the same
name as a -chardev id=name?

And, given the goal that <smartcard mode='passthrough'> then has a child
element that describes the passthrough device, it also means that I
would be adding support for a top-level spicevmc chardev device,
unrelated to smartcards; would this need any additional XML parameters?

<domain...>
  <devices>
    <serial type='spicevmc'>
      <!-- anything else needed for a top-level spicevmc chardev? -->
    </serial>
  </devices>
</domain>

> 
>> <domain...>
>>   <devices>
>>     <smartcard mode='passthrough' name='ccid'>
>>       <serial type='tcp'>
>>         <source host='0.0.0.0' port='2001'/>
>>         <protocol type='tcp'/>
>>       </serial>
>>     </smartcard>
>>   </devices>
>> </domain>
>>
>> maps to qemu -chardev
>> socket,server,host=0.0.0.0,port=2001,id=ccid,nowait -usb -device
>> usb-ccid -device ccid-card-passthru,chardev=ccid
>>
> 
> So actually here you got the command line correctly (again, no difference
> between both ccid-card-passthru uses except for the -chardev created), and
> I guess I would just add the same usb-ccid specification to your element:
> 
> <smartcard mode='passthrough' name='ccid'>
>   <source path='usb-ccid'/>
>   <serial type='tcp'>
>     <source host='0.0.0.0' port='2001'/>
>     <protocol type='tcp'/>
>   </serial>
> </smartcard>
> 
> btw, I'm guessing the name attribute on the top level (smartcard) element is
> just a descriptor, like id? or is it something else? does libvirt have
> id and name, or just name?

My thoughts were that the name attribute of the <smartcard> element
becomes the string that get reused twice in the qemu command line (once
in the -chardev name, once I figure out whether that is by the id= or
the name= field, and once in the -ccid-card-passthru chardev= field).
This one is a bit easier, since top-level <serial type='tcp'> already
exists, so I think this one remains:

<domain...>
  <devices>
    <smartcard mode='passthrough' name='ccid'>
      <serial type='tcp'>
        <source host='0.0.0.0' port='2001'/>
        <protocol type='tcp'/>
      </serial>
    </smartcard>
  </devices>
</domain>


>>
> 
> Ok, so I don't understand exactly what you wanted the name to mean. Unless
> you meant for it to do exactly what I thought adding a source element side by
> side with the serial element would do, namely specifying the device (devices)
> to use, what I called future proofing.
> 
>>>  * emulated with certificates (ccid-card-emulated with proper parameters to use user provided file certificates)
>>
>> Since the certificates live in the guest and do not pass through the
>> qemu command line, my understanding is that libvirt does not see this as
>> any different from mode='passthrough' above.
> 
> Yes, I just specified this for completness sake.
> 

In summary, this is my proposal for the new XML; feedback welcome to
correct anything:

<devices> modifies one existing sub-element (<serial> learns a new
type='spicevmc' to match qemu's new spicevmc chardev), and adds a new
sub-element <smartcard>.  The new <smartcard> element has a required
mode attribute, that takes on one of three strings:

<smartcard mode='host'/>
no other attributes, no sub-elements. Implies that the hypervisor
exposes whatever devices necessary to the guest to see a smartcard, and
feeds the smartcard implementation by communicating natively with the
host smartcard for all needed information (maps to qemu -usb -device
usb-ccid -device ccid-card-emulated)

<smartcard mode='host-certificates'>
  <certificate id='1' path='cert1'/>
  <certificate id='2' path='cert2'/>
  <certificate id='3' path='cert3'/>
</smartcard>
no other attributes, but requires three <certificate> sub-elements.
Implies that the hypervisor exposes whatever devices necessary to the
guest to see a smartcard, and that it feeds the smartcard implementation
with three certificate files living in the host rather than trying to
talk to a host smartcard (maps to qemu -usb -device usb-ccid -device
ccid-card-emulated,backend=certificates,cert1=cert1,cert2=cert2,cert3=cert3)

<smartcard mode='passthrough' name='xyz'>
  <serial .../>
</smartcard>
name attribute is optional but recommended (assuming libvirt can create
a unique name if none is provided).  <serial> sub-element is required,
with the same form as a normal <serial> sub-element of <devices>, but
the common uses will be <serial type='tcp'> (existing) or <serial
type='spicevmc'> (new).  Implies that the hypervisor exposes whatever
devices necessary to the guest to see a smartcard, and that it feeds the
smartcard implementation via the associated char device (maps to qemu
-chardev ...,name=xyz -usb -device usb-ccid -device
ccid-card-passthru,chardev-xyz)

-- 
Eric Blake   eblake at redhat.com    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 619 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20110103/f5a19dc4/attachment-0001.sig>


More information about the libvir-list mailing list