Browse Source

Remove the direct dependency on libpcsclite

Instead, use a go library that communicates with pcscd over a socket.

Also update the changes introduced by @gravityblast since this PR's
inception
Guillaume Ballet 6 năm trước cách đây
mục cha
commit
5617dca1c9

+ 5 - 5
accounts/scwallet/hub.go

@@ -40,11 +40,11 @@ import (
 	"sync"
 	"time"
 
-	"github.com/ebfe/scard"
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/log"
+	pcsc "github.com/gballet/go-libpcsclite"
 )
 
 // Scheme is the URI prefix for smartcard wallets.
@@ -70,7 +70,7 @@ type smartcardPairing struct {
 type Hub struct {
 	scheme string // Protocol scheme prefixing account and wallet URLs.
 
-	context  *scard.Context
+	context  *pcsc.Client
 	datadir  string
 	pairings map[string]smartcardPairing
 
@@ -152,7 +152,7 @@ func (hub *Hub) setPairing(wallet *Wallet, pairing *smartcardPairing) error {
 
 // NewHub creates a new hardware wallet manager for smartcards.
 func NewHub(scheme string, datadir string) (*Hub, error) {
-	context, err := scard.EstablishContext()
+	context, err := pcsc.EstablishContext(pcsc.ScopeSystem)
 	if err != nil {
 		return nil, err
 	}
@@ -228,7 +228,7 @@ func (hub *Hub) refreshWallets() {
 			delete(hub.wallets, reader)
 		}
 		// New card detected, try to connect to it
-		card, err := hub.context.Connect(reader, scard.ShareShared, scard.ProtocolAny)
+		card, err := hub.context.Connect(reader, pcsc.ShareShared, pcsc.ProtocolAny)
 		if err != nil {
 			log.Debug("Failed to open smart card", "reader", reader, "err", err)
 			continue
@@ -236,7 +236,7 @@ func (hub *Hub) refreshWallets() {
 		wallet := NewWallet(hub, card)
 		if err = wallet.connect(); err != nil {
 			log.Debug("Failed to connect to smart card", "reader", reader, "err", err)
-			card.Disconnect(scard.LeaveCard)
+			card.Disconnect(pcsc.LeaveCard)
 			continue
 		}
 		// Card connected, start tracking in amongs the wallets

+ 18 - 14
accounts/scwallet/securechannel.go

@@ -25,9 +25,11 @@ import (
 	"crypto/sha512"
 	"fmt"
 
-	"github.com/ebfe/scard"
 	"github.com/ethereum/go-ethereum/crypto"
+	pcsc "github.com/gballet/go-libpcsclite"
 	"github.com/wsddn/go-ecdh"
+	"golang.org/x/crypto/pbkdf2"
+	"golang.org/x/text/unicode/norm"
 )
 
 const (
@@ -42,22 +44,24 @@ const (
 	insMutuallyAuthenticate = 0x11
 	insPair                 = 0x12
 	insUnpair               = 0x13
+
+	pairingSalt = "Keycard Pairing Password Salt"
 )
 
 // SecureChannelSession enables secure communication with a hardware wallet.
 type SecureChannelSession struct {
-	card          *scard.Card // A handle to the smartcard for communication
-	secret        []byte      // A shared secret generated from our ECDSA keys
-	publicKey     []byte      // Our own ephemeral public key
-	PairingKey    []byte      // A permanent shared secret for a pairing, if present
-	sessionEncKey []byte      // The current session encryption key
-	sessionMacKey []byte      // The current session MAC key
-	iv            []byte      // The current IV
-	PairingIndex  uint8       // The pairing index
+	card          *pcsc.Card // A handle to the smartcard for communication
+	secret        []byte     // A shared secret generated from our ECDSA keys
+	publicKey     []byte     // Our own ephemeral public key
+	PairingKey    []byte     // A permanent shared secret for a pairing, if present
+	sessionEncKey []byte     // The current session encryption key
+	sessionMacKey []byte     // The current session MAC key
+	iv            []byte     // The current IV
+	PairingIndex  uint8      // The pairing index
 }
 
 // NewSecureChannelSession creates a new secure channel for the given card and public key.
-func NewSecureChannelSession(card *scard.Card, keyData []byte) (*SecureChannelSession, error) {
+func NewSecureChannelSession(card *pcsc.Card, keyData []byte) (*SecureChannelSession, error) {
 	// Generate an ECDSA keypair for ourselves
 	gen := ecdh.NewEllipticECDH(crypto.S256())
 	private, public, err := gen.GenerateKey(rand.Reader)
@@ -83,8 +87,8 @@ func NewSecureChannelSession(card *scard.Card, keyData []byte) (*SecureChannelSe
 }
 
 // Pair establishes a new pairing with the smartcard.
-func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
-	secretHash := sha256.Sum256(sharedSecret)
+func (s *SecureChannelSession) Pair(pairingPassword []byte) error {
+	secretHash := pbkdf2.Key(norm.NFKD.Bytes([]byte(pairingPassword)), norm.NFKD.Bytes([]byte(pairingSalt)), 50000, 32, sha256.New)
 
 	challenge := make([]byte, 32)
 	if _, err := rand.Read(challenge); err != nil {
@@ -102,10 +106,10 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
 
 	expectedCryptogram := md.Sum(nil)
 	cardCryptogram := response.Data[:32]
-	cardChallenge := response.Data[32:]
+	cardChallenge := response.Data[32:64]
 
 	if !bytes.Equal(expectedCryptogram, cardCryptogram) {
-		return fmt.Errorf("Invalid card cryptogram")
+		return fmt.Errorf("Invalid card cryptogram %v != %v", expectedCryptogram, cardCryptogram)
 	}
 
 	md.Reset()

+ 16 - 15
accounts/scwallet/wallet.go

@@ -32,7 +32,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/ebfe/scard"
 	ethereum "github.com/ethereum/go-ethereum"
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
@@ -40,12 +39,13 @@ import (
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/crypto/secp256k1"
 	"github.com/ethereum/go-ethereum/log"
+	pcsc "github.com/gballet/go-libpcsclite"
 )
 
-// ErrPUKNeeded is returned if opening the smart card requires pairing with a PUK
-// code. In this case, the calling application should request user input to enter
-// the PUK and send it back.
-var ErrPUKNeeded = errors.New("smartcard: puk needed")
+// ErrPairingPasswordNeeded is returned if opening the smart card requires pairing with a pairing
+// password. In this case, the calling application should request user input to enter
+// the pairing password and send it back.
+var ErrPairingPasswordNeeded = errors.New("smartcard: pairing password needed")
 
 // ErrPINNeeded is returned if opening the smart card requires a PIN code. In
 // this case, the calling application should request user input to enter the PIN
@@ -67,7 +67,8 @@ var ErrAlreadyOpen = errors.New("smartcard: already open")
 var ErrPubkeyMismatch = errors.New("smartcard: recovered public key mismatch")
 
 var (
-	appletAID               = []byte{0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x57, 0x61, 0x6C, 0x6C, 0x65, 0x74, 0x41, 0x70, 0x70}
+	// appletAID               = []byte{0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x57, 0x61, 0x6C, 0x6C, 0x65, 0x74, 0x41, 0x70, 0x70}
+	appletAID               = []byte{0xA0, 0x00, 0x00, 0x08, 0x04, 0x00, 0x01, 0x01, 0x01}
 	DerivationSignatureHash = sha256.Sum256([]byte("STATUS KEY DERIVATION"))
 )
 
@@ -108,10 +109,10 @@ type Wallet struct {
 	Hub       *Hub   // A handle to the Hub that instantiated this wallet.
 	PublicKey []byte // The wallet's public key (used for communication and identification, not signing!)
 
-	lock    sync.Mutex  // Lock that gates access to struct fields and communication with the card
-	card    *scard.Card // A handle to the smartcard interface for the wallet.
-	session *Session    // The secure communication session with the card
-	log     log.Logger  // Contextual logger to tag the base with its id
+	lock    sync.Mutex // Lock that gates access to struct fields and communication with the card
+	card    *pcsc.Card // A handle to the smartcard interface for the wallet.
+	session *Session   // The secure communication session with the card
+	log     log.Logger // Contextual logger to tag the base with its id
 
 	deriveNextPath accounts.DerivationPath   // Next derivation path for account auto-discovery
 	deriveNextAddr common.Address            // Next derived account address for auto-discovery
@@ -121,7 +122,7 @@ type Wallet struct {
 }
 
 // NewWallet constructs and returns a new Wallet instance.
-func NewWallet(hub *Hub, card *scard.Card) *Wallet {
+func NewWallet(hub *Hub, card *pcsc.Card) *Wallet {
 	wallet := &Wallet{
 		Hub:  hub,
 		card: card,
@@ -132,13 +133,13 @@ func NewWallet(hub *Hub, card *scard.Card) *Wallet {
 // transmit sends an APDU to the smartcard and receives and decodes the response.
 // It automatically handles requests by the card to fetch the return data separately,
 // and returns an error if the response status code is not success.
-func transmit(card *scard.Card, command *commandAPDU) (*responseAPDU, error) {
+func transmit(card *pcsc.Card, command *commandAPDU) (*responseAPDU, error) {
 	data, err := command.serialize()
 	if err != nil {
 		return nil, err
 	}
 
-	responseData, err := card.Transmit(data)
+	responseData, _, err := card.Transmit(data)
 	if err != nil {
 		return nil, err
 	}
@@ -349,7 +350,7 @@ func (w *Wallet) Open(passphrase string) error {
 		} else {
 			// If no passphrase was supplied, request the PUK from the user
 			if passphrase == "" {
-				return ErrPUKNeeded
+				return ErrPairingPasswordNeeded
 			}
 			// Attempt to pair the smart card with the user supplied PUK
 			if err := w.pair([]byte(passphrase)); err != nil {
@@ -814,7 +815,7 @@ func (s *Session) unblockPin(pukpin []byte) error {
 
 // release releases resources associated with the channel.
 func (s *Session) release() error {
-	return s.Wallet.card.Disconnect(scard.LeaveCard)
+	return s.Wallet.card.Disconnect(pcsc.LeaveCard)
 }
 
 // paired returns true if a valid pairing exists.

+ 2 - 2
console/bridge.go

@@ -118,9 +118,9 @@ func (b *bridge) OpenWallet(call otto.FunctionCall) (response otto.Value) {
 			throwJSException(err.Error())
 		}
 
-	case strings.HasSuffix(err.Error(), scwallet.ErrPUKNeeded.Error()):
+	case strings.HasSuffix(err.Error(), scwallet.ErrPairingPasswordNeeded.Error()):
 		// PUK input requested, fetch from the user and call open again
-		if input, err := b.prompter.PromptPassword("Please enter current PUK: "); err != nil {
+		if input, err := b.prompter.PromptPassword("Please enter the pairing password: "); err != nil {
 			throwJSException(err.Error())
 		} else {
 			passwd, _ = otto.ToValue(input)

+ 0 - 23
vendor/github.com/ebfe/scard/LICENSE

@@ -1,23 +0,0 @@
-Copyright (c) 2016, Michael Gehring <mg@ebfe.org>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice, this
-  list of conditions and the following disclaimer in the documentation and/or
-  other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 0 - 14
vendor/github.com/ebfe/scard/README.md

@@ -1,14 +0,0 @@
-scard
-=====
-
-[![GoDoc](https://godoc.org/github.com/ebfe/scard?status.svg)](https://godoc.org/github.com/ebfe/scard)
-
-Go bindings to the PC/SC API.
-
-## Installation
-
-	go get github.com/ebfe/scard
-
-## Bugs
-
-	- Memory layouts/GC needs a thorough review.

+ 0 - 283
vendor/github.com/ebfe/scard/scard.go

@@ -1,283 +0,0 @@
-// Package scard provides bindings to the PC/SC API.
-package scard
-
-import (
-	"time"
-	"unsafe"
-)
-
-type CardStatus struct {
-	Reader         string
-	State          State
-	ActiveProtocol Protocol
-	Atr            []byte
-}
-
-type ReaderState struct {
-	Reader       string
-	UserData     interface{}
-	CurrentState StateFlag
-	EventState   StateFlag
-	Atr          []byte
-}
-
-type Context struct {
-	ctx uintptr
-}
-
-type Card struct {
-	handle         uintptr
-	activeProtocol Protocol
-}
-
-// wraps SCardEstablishContext
-func EstablishContext() (*Context, error) {
-	ctx, r := scardEstablishContext(ScopeSystem, 0, 0)
-	if r != ErrSuccess {
-		return nil, r
-	}
-
-	return &Context{ctx: ctx}, nil
-}
-
-// wraps SCardIsValidContext
-func (ctx *Context) IsValid() (bool, error) {
-	r := scardIsValidContext(ctx.ctx)
-	switch r {
-	case ErrSuccess:
-		return true, nil
-	case ErrInvalidHandle:
-		return false, nil
-	default:
-		return false, r
-	}
-}
-
-// wraps SCardCancel
-func (ctx *Context) Cancel() error {
-	r := scardCancel(ctx.ctx)
-	if r != ErrSuccess {
-		return r
-	}
-	return nil
-}
-
-// wraps SCardReleaseContext
-func (ctx *Context) Release() error {
-	r := scardReleaseContext(ctx.ctx)
-	if r != ErrSuccess {
-		return r
-	}
-	return nil
-}
-
-// wraps SCardListReaders
-func (ctx *Context) ListReaders() ([]string, error) {
-	needed, r := scardListReaders(ctx.ctx, nil, nil, 0)
-	if r != ErrSuccess {
-		return nil, r
-	}
-
-	buf := make(strbuf, needed)
-	n, r := scardListReaders(ctx.ctx, nil, buf.ptr(), uint32(len(buf)))
-	if r != ErrSuccess {
-		return nil, r
-	}
-	return decodemstr(buf[:n]), nil
-}
-
-// wraps SCardListReaderGroups
-func (ctx *Context) ListReaderGroups() ([]string, error) {
-	needed, r := scardListReaderGroups(ctx.ctx, nil, 0)
-	if r != ErrSuccess {
-		return nil, r
-	}
-
-	buf := make(strbuf, needed)
-	n, r := scardListReaderGroups(ctx.ctx, buf.ptr(), uint32(len(buf)))
-	if r != ErrSuccess {
-		return nil, r
-	}
-	return decodemstr(buf[:n]), nil
-}
-
-// wraps SCardGetStatusChange
-func (ctx *Context) GetStatusChange(readerStates []ReaderState, timeout time.Duration) error {
-
-	dwTimeout := durationToTimeout(timeout)
-	states := make([]scardReaderState, len(readerStates))
-
-	for i := range readerStates {
-		var err error
-		states[i], err = readerStates[i].toSys()
-		if err != nil {
-			return err
-		}
-	}
-
-	r := scardGetStatusChange(ctx.ctx, dwTimeout, states)
-	if r != ErrSuccess {
-		return r
-	}
-
-	for i := range readerStates {
-		(&readerStates[i]).update(&states[i])
-	}
-
-	return nil
-}
-
-// wraps SCardConnect
-func (ctx *Context) Connect(reader string, mode ShareMode, proto Protocol) (*Card, error) {
-	creader, err := encodestr(reader)
-	if err != nil {
-		return nil, err
-	}
-	handle, activeProtocol, r := scardConnect(ctx.ctx, creader.ptr(), mode, proto)
-	if r != ErrSuccess {
-		return nil, r
-	}
-	return &Card{handle: handle, activeProtocol: activeProtocol}, nil
-}
-
-// wraps SCardDisconnect
-func (card *Card) Disconnect(d Disposition) error {
-	r := scardDisconnect(card.handle, d)
-	if r != ErrSuccess {
-		return r
-	}
-	return nil
-}
-
-// wraps SCardReconnect
-func (card *Card) Reconnect(mode ShareMode, proto Protocol, disp Disposition) error {
-	activeProtocol, r := scardReconnect(card.handle, mode, proto, disp)
-	if r != ErrSuccess {
-		return r
-	}
-	card.activeProtocol = activeProtocol
-	return nil
-}
-
-// wraps SCardBeginTransaction
-func (card *Card) BeginTransaction() error {
-	r := scardBeginTransaction(card.handle)
-	if r != ErrSuccess {
-		return r
-	}
-	return nil
-}
-
-// wraps SCardEndTransaction
-func (card *Card) EndTransaction(disp Disposition) error {
-	r := scardEndTransaction(card.handle, disp)
-	if r != ErrSuccess {
-		return r
-	}
-	return nil
-}
-
-// wraps SCardStatus
-func (card *Card) Status() (*CardStatus, error) {
-	reader, state, proto, atr, err := scardCardStatus(card.handle)
-	if err != ErrSuccess {
-		return nil, err
-	}
-	return &CardStatus{Reader: reader, State: state, ActiveProtocol: proto, Atr: atr}, nil
-}
-
-// wraps SCardTransmit
-func (card *Card) Transmit(cmd []byte) ([]byte, error) {
-	rsp := make([]byte, maxBufferSizeExtended)
-	rspLen, err := scardTransmit(card.handle, card.activeProtocol, cmd, rsp)
-	if err != ErrSuccess {
-		return nil, err
-	}
-	return rsp[:rspLen], nil
-}
-
-// wraps SCardControl
-func (card *Card) Control(ioctl uint32, in []byte) ([]byte, error) {
-	var out [0xffff]byte
-	outLen, err := scardControl(card.handle, ioctl, in, out[:])
-	if err != ErrSuccess {
-		return nil, err
-	}
-	return out[:outLen], nil
-}
-
-// wraps SCardGetAttrib
-func (card *Card) GetAttrib(id Attrib) ([]byte, error) {
-	needed, err := scardGetAttrib(card.handle, id, nil)
-	if err != ErrSuccess {
-		return nil, err
-	}
-
-	var attrib = make([]byte, needed)
-	n, err := scardGetAttrib(card.handle, id, attrib)
-	if err != ErrSuccess {
-		return nil, err
-	}
-	return attrib[:n], nil
-}
-
-// wraps SCardSetAttrib
-func (card *Card) SetAttrib(id Attrib, data []byte) error {
-	err := scardSetAttrib(card.handle, id, data)
-	if err != ErrSuccess {
-		return err
-	}
-	return nil
-}
-
-func durationToTimeout(timeout time.Duration) uint32 {
-	switch {
-	case timeout < 0:
-		return infiniteTimeout
-	case timeout > time.Duration(infiniteTimeout)*time.Millisecond:
-		return infiniteTimeout - 1
-	default:
-		return uint32(timeout / time.Millisecond)
-	}
-}
-
-func (buf strbuf) ptr() unsafe.Pointer {
-	return unsafe.Pointer(&buf[0])
-}
-
-func (buf strbuf) split() []strbuf {
-	var chunks []strbuf
-	for len(buf) > 0 && buf[0] != 0 {
-		i := 0
-		for i = range buf {
-			if buf[i] == 0 {
-				break
-			}
-		}
-		chunks = append(chunks, buf[:i+1])
-		buf = buf[i+1:]
-	}
-
-	return chunks
-}
-
-func encodemstr(strings ...string) (strbuf, error) {
-	var buf strbuf
-	for _, s := range strings {
-		utf16, err := encodestr(s)
-		if err != nil {
-			return nil, err
-		}
-		buf = append(buf, utf16...)
-	}
-	buf = append(buf, 0)
-	return buf, nil
-}
-
-func decodemstr(buf strbuf) []string {
-	var strings []string
-	for _, chunk := range buf.split() {
-		strings = append(strings, decodestr(chunk))
-	}
-	return strings
-}

+ 0 - 219
vendor/github.com/ebfe/scard/scard_darwin.go

@@ -1,219 +0,0 @@
-// +build darwin
-
-package scard
-
-// #cgo LDFLAGS: -framework PCSC
-// #cgo CFLAGS: -I /usr/include
-// #include <stdlib.h>
-// #include <PCSC/winscard.h>
-// #include <PCSC/wintypes.h>
-import "C"
-
-import (
-	"unsafe"
-)
-
-func (e Error) Error() string {
-	return "scard: " + C.GoString(C.pcsc_stringify_error(C.int32_t(e)))
-}
-
-// Version returns the libpcsclite version string
-func Version() string {
-	return C.PCSCLITE_VERSION_NUMBER
-}
-
-func scardEstablishContext(scope Scope, reserved1, reserved2 uintptr) (uintptr, Error) {
-	var ctx C.SCARDCONTEXT
-	r := C.SCardEstablishContext(C.uint32_t(scope), unsafe.Pointer(reserved1), unsafe.Pointer(reserved2), &ctx)
-	return uintptr(ctx), Error(r)
-}
-
-func scardIsValidContext(ctx uintptr) Error {
-	r := C.SCardIsValidContext(C.SCARDCONTEXT(ctx))
-	return Error(r)
-}
-
-func scardCancel(ctx uintptr) Error {
-	r := C.SCardCancel(C.SCARDCONTEXT(ctx))
-	return Error(r)
-}
-
-func scardReleaseContext(ctx uintptr) Error {
-	r := C.SCardReleaseContext(C.SCARDCONTEXT(ctx))
-	return Error(r)
-}
-
-func scardListReaders(ctx uintptr, groups, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
-	dwBufLen := C.uint32_t(bufLen)
-	r := C.SCardListReaders(C.SCARDCONTEXT(ctx), (C.LPCSTR)(groups), (C.LPSTR)(buf), &dwBufLen)
-	return uint32(dwBufLen), Error(r)
-}
-
-func scardListReaderGroups(ctx uintptr, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
-	dwBufLen := C.uint32_t(bufLen)
-	r := C.SCardListReaderGroups(C.SCARDCONTEXT(ctx), (C.LPSTR)(buf), &dwBufLen)
-	return uint32(dwBufLen), Error(r)
-}
-
-func scardGetStatusChange(ctx uintptr, timeout uint32, states []scardReaderState) Error {
-	// In darwin, the LPSCARD_READERSTATE_A has 1 byte alignment and hence
-	// has no trailing padding. Go does add 3 bytes of padding (on both 32
-	// and 64 bits), so we pack an array manually instead.
-	const size = int(unsafe.Sizeof(states[0])) - 3
-	buf := make([]byte, size*len(states))
-	for i, _ := range states {
-		copy(buf[i*size:(i+1)*size], (*(*[size]byte)(unsafe.Pointer(&states[i])))[:])
-	}
-	r := C.SCardGetStatusChange(C.SCARDCONTEXT(ctx), C.uint32_t(timeout), (C.LPSCARD_READERSTATE_A)(unsafe.Pointer(&buf[0])), C.uint32_t(len(states)))
-	for i, _ := range states {
-		copy((*(*[size]byte)(unsafe.Pointer(&states[i])))[:], buf[i*size:(i+1)*size])
-	}
-	return Error(r)
-}
-
-func scardConnect(ctx uintptr, reader unsafe.Pointer, shareMode ShareMode, proto Protocol) (uintptr, Protocol, Error) {
-	var handle C.SCARDHANDLE
-	var activeProto C.uint32_t
-
-	r := C.SCardConnect(C.SCARDCONTEXT(ctx), C.LPCSTR(reader), C.uint32_t(shareMode), C.uint32_t(proto), &handle, &activeProto)
-
-	return uintptr(handle), Protocol(activeProto), Error(r)
-}
-
-func scardDisconnect(card uintptr, d Disposition) Error {
-	r := C.SCardDisconnect(C.SCARDHANDLE(card), C.uint32_t(d))
-	return Error(r)
-}
-
-func scardReconnect(card uintptr, mode ShareMode, proto Protocol, disp Disposition) (Protocol, Error) {
-	var activeProtocol C.uint32_t
-	r := C.SCardReconnect(C.SCARDHANDLE(card), C.uint32_t(mode), C.uint32_t(proto), C.uint32_t(disp), &activeProtocol)
-	return Protocol(activeProtocol), Error(r)
-}
-
-func scardBeginTransaction(card uintptr) Error {
-	r := C.SCardBeginTransaction(C.SCARDHANDLE(card))
-	return Error(r)
-}
-
-func scardEndTransaction(card uintptr, disp Disposition) Error {
-	r := C.SCardEndTransaction(C.SCARDHANDLE(card), C.uint32_t(disp))
-	return Error(r)
-}
-
-func scardCardStatus(card uintptr) (string, State, Protocol, []byte, Error) {
-	var readerBuf [C.MAX_READERNAME + 1]byte
-	var readerLen = C.uint32_t(len(readerBuf))
-	var state, proto C.uint32_t
-	var atr [maxAtrSize]byte
-	var atrLen = C.uint32_t(len(atr))
-
-	r := C.SCardStatus(C.SCARDHANDLE(card), (C.LPSTR)(unsafe.Pointer(&readerBuf[0])), &readerLen, &state, &proto, (*C.uchar)(&atr[0]), &atrLen)
-
-	return decodestr(readerBuf[:readerLen]), State(state), Protocol(proto), atr[:atrLen], Error(r)
-}
-
-func scardTransmit(card uintptr, proto Protocol, cmd []byte, rsp []byte) (uint32, Error) {
-	var sendpci C.SCARD_IO_REQUEST
-	var recvpci C.SCARD_IO_REQUEST
-	var rspLen = C.uint32_t(len(rsp))
-
-	switch proto {
-	case ProtocolT0, ProtocolT1:
-		sendpci.dwProtocol = C.uint32_t(proto)
-	default:
-		panic("unknown protocol")
-	}
-	sendpci.cbPciLength = C.sizeof_SCARD_IO_REQUEST
-
-	r := C.SCardTransmit(C.SCARDHANDLE(card), &sendpci, (*C.uchar)(&cmd[0]), C.uint32_t(len(cmd)), &recvpci, (*C.uchar)(&rsp[0]), &rspLen)
-
-	return uint32(rspLen), Error(r)
-}
-
-func scardControl(card uintptr, ioctl uint32, in, out []byte) (uint32, Error) {
-	var ptrIn unsafe.Pointer
-	var outLen = C.uint32_t(len(out))
-
-	if len(in) != 0 {
-		ptrIn = unsafe.Pointer(&in[0])
-	}
-
-	r := C.SCardControl(C.SCARDHANDLE(card), C.uint32_t(ioctl), ptrIn, C.uint32_t(len(in)), unsafe.Pointer(&out[0]), C.uint32_t(len(out)), &outLen)
-	return uint32(outLen), Error(r)
-}
-
-func scardGetAttrib(card uintptr, id Attrib, buf []byte) (uint32, Error) {
-	var ptr *C.uint8_t
-
-	if len(buf) != 0 {
-		ptr = (*C.uint8_t)(&buf[0])
-	}
-
-	bufLen := C.uint32_t(len(buf))
-	r := C.SCardGetAttrib(C.SCARDHANDLE(card), C.uint32_t(id), ptr, &bufLen)
-
-	return uint32(bufLen), Error(r)
-}
-
-func scardSetAttrib(card uintptr, id Attrib, buf []byte) Error {
-	r := C.SCardSetAttrib(C.SCARDHANDLE(card), C.uint32_t(id), ((*C.uint8_t)(&buf[0])), C.uint32_t(len(buf)))
-	return Error(r)
-}
-
-type strbuf []byte
-
-func encodestr(s string) (strbuf, error) {
-	buf := strbuf(s + "\x00")
-	return buf, nil
-}
-
-func decodestr(buf strbuf) string {
-	if len(buf) == 0 {
-		return ""
-	}
-
-	if buf[len(buf)-1] == 0 {
-		buf = buf[:len(buf)-1]
-	}
-
-	return string(buf)
-}
-
-type scardReaderState struct {
-	szReader       uintptr
-	pvUserData     uintptr
-	dwCurrentState uint32
-	dwEventState   uint32
-	cbAtr          uint32
-	rgbAtr         [33]byte
-}
-
-var pinned = map[string]*strbuf{}
-
-func (rs *ReaderState) toSys() (scardReaderState, error) {
-	var sys scardReaderState
-
-	creader, err := encodestr(rs.Reader)
-	if err != nil {
-		return scardReaderState{}, err
-	}
-	pinned[rs.Reader] = &creader
-	sys.szReader = uintptr(creader.ptr())
-	sys.dwCurrentState = uint32(rs.CurrentState)
-	sys.cbAtr = uint32(len(rs.Atr))
-	for i, v := range rs.Atr {
-		sys.rgbAtr[i] = byte(v)
-	}
-	return sys, nil
-}
-
-func (rs *ReaderState) update(sys *scardReaderState) {
-	rs.EventState = StateFlag(sys.dwEventState)
-	if sys.cbAtr > 0 {
-		rs.Atr = make([]byte, int(sys.cbAtr))
-		for i := 0; i < int(sys.cbAtr); i++ {
-			rs.Atr[i] = byte(sys.rgbAtr[i])
-		}
-	}
-}

+ 0 - 206
vendor/github.com/ebfe/scard/scard_unix.go

@@ -1,206 +0,0 @@
-// +build !windows,!darwin
-
-package scard
-
-// #cgo pkg-config: libpcsclite
-// #include <stdlib.h>
-// #include <winscard.h>
-import "C"
-
-import (
-	"unsafe"
-)
-
-func (e Error) Error() string {
-	return "scard: " + C.GoString(C.pcsc_stringify_error(C.LONG(e)))
-}
-
-// Version returns the libpcsclite version string
-func Version() string {
-	return C.PCSCLITE_VERSION_NUMBER
-}
-
-func scardEstablishContext(scope Scope, reserved1, reserved2 uintptr) (uintptr, Error) {
-	var ctx C.SCARDCONTEXT
-	r := C.SCardEstablishContext(C.DWORD(scope), C.LPCVOID(reserved1), C.LPCVOID(reserved2), &ctx)
-	return uintptr(ctx), Error(r)
-}
-
-func scardIsValidContext(ctx uintptr) Error {
-	r := C.SCardIsValidContext(C.SCARDCONTEXT(ctx))
-	return Error(r)
-}
-
-func scardCancel(ctx uintptr) Error {
-	r := C.SCardCancel(C.SCARDCONTEXT(ctx))
-	return Error(r)
-}
-
-func scardReleaseContext(ctx uintptr) Error {
-	r := C.SCardReleaseContext(C.SCARDCONTEXT(ctx))
-	return Error(r)
-}
-
-func scardListReaders(ctx uintptr, groups, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
-	dwBufLen := C.DWORD(bufLen)
-	r := C.SCardListReaders(C.SCARDCONTEXT(ctx), (C.LPCSTR)(groups), (C.LPSTR)(buf), &dwBufLen)
-	return uint32(dwBufLen), Error(r)
-}
-
-func scardListReaderGroups(ctx uintptr, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
-	dwBufLen := C.DWORD(bufLen)
-	r := C.SCardListReaderGroups(C.SCARDCONTEXT(ctx), (C.LPSTR)(buf), &dwBufLen)
-	return uint32(dwBufLen), Error(r)
-}
-
-func scardGetStatusChange(ctx uintptr, timeout uint32, states []scardReaderState) Error {
-	r := C.SCardGetStatusChange(C.SCARDCONTEXT(ctx), C.DWORD(timeout), (C.LPSCARD_READERSTATE)(unsafe.Pointer(&states[0])), C.DWORD(len(states)))
-	return Error(r)
-}
-
-func scardConnect(ctx uintptr, reader unsafe.Pointer, shareMode ShareMode, proto Protocol) (uintptr, Protocol, Error) {
-	var handle C.SCARDHANDLE
-	var activeProto C.DWORD
-
-	r := C.SCardConnect(C.SCARDCONTEXT(ctx), C.LPCSTR(reader), C.DWORD(shareMode), C.DWORD(proto), &handle, &activeProto)
-
-	return uintptr(handle), Protocol(activeProto), Error(r)
-}
-
-func scardDisconnect(card uintptr, d Disposition) Error {
-	r := C.SCardDisconnect(C.SCARDHANDLE(card), C.DWORD(d))
-	return Error(r)
-}
-
-func scardReconnect(card uintptr, mode ShareMode, proto Protocol, disp Disposition) (Protocol, Error) {
-	var activeProtocol C.DWORD
-	r := C.SCardReconnect(C.SCARDHANDLE(card), C.DWORD(mode), C.DWORD(proto), C.DWORD(disp), &activeProtocol)
-	return Protocol(activeProtocol), Error(r)
-}
-
-func scardBeginTransaction(card uintptr) Error {
-	r := C.SCardBeginTransaction(C.SCARDHANDLE(card))
-	return Error(r)
-}
-
-func scardEndTransaction(card uintptr, disp Disposition) Error {
-	r := C.SCardEndTransaction(C.SCARDHANDLE(card), C.DWORD(disp))
-	return Error(r)
-}
-
-func scardCardStatus(card uintptr) (string, State, Protocol, []byte, Error) {
-	var readerBuf [C.MAX_READERNAME + 1]byte
-	var readerLen = C.DWORD(len(readerBuf))
-	var state, proto C.DWORD
-	var atr [maxAtrSize]byte
-	var atrLen = C.DWORD(len(atr))
-
-	r := C.SCardStatus(C.SCARDHANDLE(card), (C.LPSTR)(unsafe.Pointer(&readerBuf[0])), &readerLen, &state, &proto, (*C.BYTE)(&atr[0]), &atrLen)
-
-	return decodestr(readerBuf[:readerLen]), State(state), Protocol(proto), atr[:atrLen], Error(r)
-}
-
-func scardTransmit(card uintptr, proto Protocol, cmd []byte, rsp []byte) (uint32, Error) {
-	var sendpci C.SCARD_IO_REQUEST
-	var recvpci C.SCARD_IO_REQUEST
-	var rspLen = C.DWORD(len(rsp))
-
-	switch proto {
-	case ProtocolT0, ProtocolT1:
-		sendpci.dwProtocol = C.ulong(proto)
-	default:
-		panic("unknown protocol")
-	}
-	sendpci.cbPciLength = C.sizeof_SCARD_IO_REQUEST
-
-	r := C.SCardTransmit(C.SCARDHANDLE(card), &sendpci, (*C.BYTE)(&cmd[0]), C.DWORD(len(cmd)), &recvpci, (*C.BYTE)(&rsp[0]), &rspLen)
-
-	return uint32(rspLen), Error(r)
-}
-
-func scardControl(card uintptr, ioctl uint32, in, out []byte) (uint32, Error) {
-	var ptrIn C.LPCVOID
-	var outLen = C.DWORD(len(out))
-
-	if len(in) != 0 {
-		ptrIn = C.LPCVOID(unsafe.Pointer(&in[0]))
-	}
-
-	r := C.SCardControl(C.SCARDHANDLE(card), C.DWORD(ioctl), ptrIn, C.DWORD(len(in)), (C.LPVOID)(unsafe.Pointer(&out[0])), C.DWORD(len(out)), &outLen)
-	return uint32(outLen), Error(r)
-}
-
-func scardGetAttrib(card uintptr, id Attrib, buf []byte) (uint32, Error) {
-	var ptr C.LPBYTE
-
-	if len(buf) != 0 {
-		ptr = C.LPBYTE(unsafe.Pointer(&buf[0]))
-	}
-
-	bufLen := C.DWORD(len(buf))
-	r := C.SCardGetAttrib(C.SCARDHANDLE(card), C.DWORD(id), ptr, &bufLen)
-
-	return uint32(bufLen), Error(r)
-}
-
-func scardSetAttrib(card uintptr, id Attrib, buf []byte) Error {
-	r := C.SCardSetAttrib(C.SCARDHANDLE(card), C.DWORD(id), (*C.BYTE)(unsafe.Pointer(&buf[0])), C.DWORD(len(buf)))
-	return Error(r)
-}
-
-type strbuf []byte
-
-func encodestr(s string) (strbuf, error) {
-	buf := strbuf(s + "\x00")
-	return buf, nil
-}
-
-func decodestr(buf strbuf) string {
-	if len(buf) == 0 {
-		return ""
-	}
-
-	if buf[len(buf)-1] == 0 {
-		buf = buf[:len(buf)-1]
-	}
-
-	return string(buf)
-}
-
-type scardReaderState struct {
-	szReader       uintptr
-	pvUserData     uintptr
-	dwCurrentState uintptr
-	dwEventState   uintptr
-	cbAtr          uintptr
-	rgbAtr         [33]byte
-}
-
-var pinned = map[string]*strbuf{}
-
-func (rs *ReaderState) toSys() (scardReaderState, error) {
-	var sys scardReaderState
-
-	creader, err := encodestr(rs.Reader)
-	if err != nil {
-		return scardReaderState{}, err
-	}
-	pinned[rs.Reader] = &creader
-	sys.szReader = uintptr(creader.ptr())
-	sys.dwCurrentState = uintptr(rs.CurrentState)
-	sys.cbAtr = uintptr(len(rs.Atr))
-	for i, v := range rs.Atr {
-		sys.rgbAtr[i] = byte(v)
-	}
-	return sys, nil
-}
-
-func (rs *ReaderState) update(sys *scardReaderState) {
-	rs.EventState = StateFlag(sys.dwEventState)
-	if sys.cbAtr > 0 {
-		rs.Atr = make([]byte, int(sys.cbAtr))
-		for i := 0; i < int(sys.cbAtr); i++ {
-			rs.Atr[i] = byte(sys.rgbAtr[i])
-		}
-	}
-}

+ 0 - 221
vendor/github.com/ebfe/scard/scard_windows.go

@@ -1,221 +0,0 @@
-package scard
-
-import (
-	"fmt"
-	"syscall"
-	"unsafe"
-)
-
-var (
-	modwinscard = syscall.NewLazyDLL("winscard.dll")
-
-	procEstablishContext = modwinscard.NewProc("SCardEstablishContext")
-	procReleaseContext   = modwinscard.NewProc("SCardReleaseContext")
-	procIsValidContext   = modwinscard.NewProc("SCardIsValidContext")
-	procCancel           = modwinscard.NewProc("SCardCancel")
-	procListReaders      = modwinscard.NewProc("SCardListReadersW")
-	procListReaderGroups = modwinscard.NewProc("SCardListReaderGroupsW")
-	procGetStatusChange  = modwinscard.NewProc("SCardGetStatusChangeW")
-	procConnect          = modwinscard.NewProc("SCardConnectW")
-	procDisconnect       = modwinscard.NewProc("SCardDisconnect")
-	procReconnect        = modwinscard.NewProc("SCardReconnect")
-	procBeginTransaction = modwinscard.NewProc("SCardBeginTransaction")
-	procEndTransaction   = modwinscard.NewProc("SCardEndTransaction")
-	procStatus           = modwinscard.NewProc("SCardStatusW")
-	procTransmit         = modwinscard.NewProc("SCardTransmit")
-	procControl          = modwinscard.NewProc("SCardControl")
-	procGetAttrib        = modwinscard.NewProc("SCardGetAttrib")
-	procSetAttrib        = modwinscard.NewProc("SCardSetAttrib")
-
-	dataT0Pci = modwinscard.NewProc("g_rgSCardT0Pci")
-	dataT1Pci = modwinscard.NewProc("g_rgSCardT1Pci")
-)
-
-var scardIoReqT0 uintptr
-var scardIoReqT1 uintptr
-
-func init() {
-	if err := dataT0Pci.Find(); err != nil {
-		panic(err)
-	}
-	scardIoReqT0 = dataT0Pci.Addr()
-	if err := dataT1Pci.Find(); err != nil {
-		panic(err)
-	}
-	scardIoReqT1 = dataT1Pci.Addr()
-}
-
-func (e Error) Error() string {
-	err := syscall.Errno(e)
-	return fmt.Sprintf("scard: error(%x): %s", uintptr(e), err.Error())
-}
-
-func scardEstablishContext(scope Scope, reserved1, reserved2 uintptr) (uintptr, Error) {
-	var ctx uintptr
-	r, _, _ := procEstablishContext.Call(uintptr(scope), reserved1, reserved2, uintptr(unsafe.Pointer(&ctx)))
-	return ctx, Error(r)
-}
-
-func scardIsValidContext(ctx uintptr) Error {
-	r, _, _ := procIsValidContext.Call(ctx)
-	return Error(r)
-}
-
-func scardCancel(ctx uintptr) Error {
-	r, _, _ := procCancel.Call(ctx)
-	return Error(r)
-}
-
-func scardReleaseContext(ctx uintptr) Error {
-	r, _, _ := procReleaseContext.Call(ctx)
-	return Error(r)
-}
-
-func scardListReaders(ctx uintptr, groups, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
-	dwBufLen := uint32(bufLen)
-	r, _, _ := procListReaders.Call(ctx, uintptr(groups), uintptr(buf), uintptr(unsafe.Pointer(&dwBufLen)))
-	return dwBufLen, Error(r)
-}
-
-func scardListReaderGroups(ctx uintptr, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
-	dwBufLen := uint32(bufLen)
-	r, _, _ := procListReaderGroups.Call(ctx, uintptr(buf), uintptr(unsafe.Pointer(&dwBufLen)))
-	return dwBufLen, Error(r)
-}
-
-func scardGetStatusChange(ctx uintptr, timeout uint32, states []scardReaderState) Error {
-	r, _, _ := procGetStatusChange.Call(ctx, uintptr(timeout), uintptr(unsafe.Pointer(&states[0])), uintptr(len(states)))
-	return Error(r)
-}
-
-func scardConnect(ctx uintptr, reader unsafe.Pointer, shareMode ShareMode, proto Protocol) (uintptr, Protocol, Error) {
-	var handle uintptr
-	var activeProto uint32
-
-	r, _, _ := procConnect.Call(ctx, uintptr(reader), uintptr(shareMode), uintptr(proto), uintptr(unsafe.Pointer(&handle)), uintptr(unsafe.Pointer(&activeProto)))
-
-	return handle, Protocol(activeProto), Error(r)
-}
-
-func scardDisconnect(card uintptr, d Disposition) Error {
-	r, _, _ := procDisconnect.Call(card, uintptr(d))
-	return Error(r)
-}
-
-func scardReconnect(card uintptr, mode ShareMode, proto Protocol, disp Disposition) (Protocol, Error) {
-	var activeProtocol uint32
-	r, _, _ := procReconnect.Call(card, uintptr(mode), uintptr(proto), uintptr(disp), uintptr(unsafe.Pointer(&activeProtocol)))
-	return Protocol(activeProtocol), Error(r)
-}
-
-func scardBeginTransaction(card uintptr) Error {
-	r, _, _ := procBeginTransaction.Call(card)
-	return Error(r)
-}
-
-func scardEndTransaction(card uintptr, disp Disposition) Error {
-	r, _, _ := procEndTransaction.Call(card, uintptr(disp))
-	return Error(r)
-}
-
-func scardCardStatus(card uintptr) (string, State, Protocol, []byte, Error) {
-	var state, proto uint32
-	var atr [maxAtrSize]byte
-	var atrLen = uint32(len(atr))
-
-	reader := make(strbuf, maxReadername+1)
-	readerLen := uint32(len(reader))
-
-	r, _, _ := procStatus.Call(card, uintptr(reader.ptr()), uintptr(unsafe.Pointer(&readerLen)), uintptr(unsafe.Pointer(&state)), uintptr(unsafe.Pointer(&proto)), uintptr(unsafe.Pointer(&atr[0])), uintptr(unsafe.Pointer(&atrLen)))
-
-	return decodestr(reader[:readerLen]), State(state), Protocol(proto), atr[:atrLen], Error(r)
-}
-
-func scardTransmit(card uintptr, proto Protocol, cmd []byte, rsp []byte) (uint32, Error) {
-	var sendpci uintptr
-	var rspLen = uint32(len(rsp))
-
-	switch proto {
-	case ProtocolT0:
-		sendpci = scardIoReqT0
-	case ProtocolT1:
-		sendpci = scardIoReqT1
-	default:
-		panic("unknown protocol")
-	}
-
-	r, _, _ := procTransmit.Call(card, sendpci, uintptr(unsafe.Pointer(&cmd[0])), uintptr(len(cmd)), uintptr(0), uintptr(unsafe.Pointer(&rsp[0])), uintptr(unsafe.Pointer(&rspLen)))
-
-	return rspLen, Error(r)
-}
-
-func scardControl(card uintptr, ioctl uint32, in, out []byte) (uint32, Error) {
-	var ptrIn uintptr
-	var outLen = uint32(len(out))
-
-	if len(in) != 0 {
-		ptrIn = uintptr(unsafe.Pointer(&in[0]))
-	}
-
-	r, _, _ := procControl.Call(card, uintptr(ioctl), ptrIn, uintptr(len(in)), uintptr(unsafe.Pointer(&out[0])), uintptr(len(out)), uintptr(unsafe.Pointer(&outLen)))
-	return outLen, Error(r)
-}
-
-func scardGetAttrib(card uintptr, id Attrib, buf []byte) (uint32, Error) {
-	var ptr uintptr
-
-	if len(buf) != 0 {
-		ptr = uintptr(unsafe.Pointer(&buf[0]))
-	}
-
-	bufLen := uint32(len(buf))
-	r, _, _ := procGetAttrib.Call(card, uintptr(id), ptr, uintptr(unsafe.Pointer(&bufLen)))
-
-	return bufLen, Error(r)
-}
-
-func scardSetAttrib(card uintptr, id Attrib, buf []byte) Error {
-	r, _, _ := procSetAttrib.Call(card, uintptr(id), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
-	return Error(r)
-}
-
-type scardReaderState struct {
-	szReader       uintptr
-	pvUserData     uintptr
-	dwCurrentState uint32
-	dwEventState   uint32
-	cbAtr          uint32
-	rgbAtr         [36]byte
-}
-
-func (rs *ReaderState) toSys() (scardReaderState, error) {
-	var sys scardReaderState
-	creader, err := encodestr(rs.Reader)
-	if err != nil {
-		return scardReaderState{}, err
-	}
-	sys.szReader = uintptr(creader.ptr())
-	sys.dwCurrentState = uint32(rs.CurrentState)
-	sys.cbAtr = uint32(len(rs.Atr))
-	copy(sys.rgbAtr[:], rs.Atr)
-	return sys, nil
-}
-
-func (rs *ReaderState) update(sys *scardReaderState) {
-	rs.EventState = StateFlag(sys.dwEventState)
-	if sys.cbAtr > 0 {
-		rs.Atr = make([]byte, int(sys.cbAtr))
-		copy(rs.Atr, sys.rgbAtr[:])
-	}
-}
-
-type strbuf []uint16
-
-func encodestr(s string) (strbuf, error) {
-	utf16, err := syscall.UTF16FromString(s)
-	return strbuf(utf16), err
-}
-
-func decodestr(buf strbuf) string {
-	return syscall.UTF16ToString(buf)
-}

+ 0 - 190
vendor/github.com/ebfe/scard/zconst.go

@@ -1,190 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs -- -I /usr/include/PCSC/ const.go
-
-package scard
-
-type Attrib uint32
-
-const (
-	AttrVendorName           Attrib = 0x10100
-	AttrVendorIfdType        Attrib = 0x10101
-	AttrVendorIfdVersion     Attrib = 0x10102
-	AttrVendorIfdSerialNo    Attrib = 0x10103
-	AttrChannelId            Attrib = 0x20110
-	AttrAsyncProtocolTypes   Attrib = 0x30120
-	AttrDefaultClk           Attrib = 0x30121
-	AttrMaxClk               Attrib = 0x30122
-	AttrDefaultDataRate      Attrib = 0x30123
-	AttrMaxDataRate          Attrib = 0x30124
-	AttrMaxIfsd              Attrib = 0x30125
-	AttrSyncProtocolTypes    Attrib = 0x30126
-	AttrPowerMgmtSupport     Attrib = 0x40131
-	AttrUserToCardAuthDevice Attrib = 0x50140
-	AttrUserAuthInputDevice  Attrib = 0x50142
-	AttrCharacteristics      Attrib = 0x60150
-	AttrCurrentProtocolType  Attrib = 0x80201
-	AttrCurrentClk           Attrib = 0x80202
-	AttrCurrentF             Attrib = 0x80203
-	AttrCurrentD             Attrib = 0x80204
-	AttrCurrentN             Attrib = 0x80205
-	AttrCurrentW             Attrib = 0x80206
-	AttrCurrentIfsc          Attrib = 0x80207
-	AttrCurrentIfsd          Attrib = 0x80208
-	AttrCurrentBwt           Attrib = 0x80209
-	AttrCurrentCwt           Attrib = 0x8020a
-	AttrCurrentEbcEncoding   Attrib = 0x8020b
-	AttrExtendedBwt          Attrib = 0x8020c
-	AttrIccPresence          Attrib = 0x90300
-	AttrIccInterfaceStatus   Attrib = 0x90301
-	AttrCurrentIoState       Attrib = 0x90302
-	AttrAtrString            Attrib = 0x90303
-	AttrIccTypePerAtr        Attrib = 0x90304
-	AttrEscReset             Attrib = 0x7a000
-	AttrEscCancel            Attrib = 0x7a003
-	AttrEscAuthrequest       Attrib = 0x7a005
-	AttrMaxinput             Attrib = 0x7a007
-	AttrDeviceUnit           Attrib = 0x7fff0001
-	AttrDeviceInUse          Attrib = 0x7fff0002
-	AttrDeviceFriendlyName   Attrib = 0x7fff0003
-	AttrDeviceSystemName     Attrib = 0x7fff0004
-	AttrSupressT1IfsRequest  Attrib = 0x7fff0007
-)
-
-type Error uint32
-
-const (
-	ErrSuccess                Error = 0x0
-	ErrInternalError          Error = 0x80100001
-	ErrCancelled              Error = 0x80100002
-	ErrInvalidHandle          Error = 0x80100003
-	ErrInvalidParameter       Error = 0x80100004
-	ErrInvalidTarget          Error = 0x80100005
-	ErrNoMemory               Error = 0x80100006
-	ErrWaitedTooLong          Error = 0x80100007
-	ErrInsufficientBuffer     Error = 0x80100008
-	ErrUnknownReader          Error = 0x80100009
-	ErrTimeout                Error = 0x8010000a
-	ErrSharingViolation       Error = 0x8010000b
-	ErrNoSmartcard            Error = 0x8010000c
-	ErrUnknownCard            Error = 0x8010000d
-	ErrCantDispose            Error = 0x8010000e
-	ErrProtoMismatch          Error = 0x8010000f
-	ErrNotReady               Error = 0x80100010
-	ErrInvalidValue           Error = 0x80100011
-	ErrSystemCancelled        Error = 0x80100012
-	ErrCommError              Error = 0x80100013
-	ErrUnknownError           Error = 0x80100014
-	ErrInvalidAtr             Error = 0x80100015
-	ErrNotTransacted          Error = 0x80100016
-	ErrReaderUnavailable      Error = 0x80100017
-	ErrShutdown               Error = 0x80100018
-	ErrPciTooSmall            Error = 0x80100019
-	ErrReaderUnsupported      Error = 0x8010001a
-	ErrDuplicateReader        Error = 0x8010001b
-	ErrCardUnsupported        Error = 0x8010001c
-	ErrNoService              Error = 0x8010001d
-	ErrServiceStopped         Error = 0x8010001e
-	ErrUnexpected             Error = 0x8010001f
-	ErrUnsupportedFeature     Error = 0x8010001f
-	ErrIccInstallation        Error = 0x80100020
-	ErrIccCreateorder         Error = 0x80100021
-	ErrFileNotFound           Error = 0x80100024
-	ErrNoDir                  Error = 0x80100025
-	ErrNoFile                 Error = 0x80100026
-	ErrNoAccess               Error = 0x80100027
-	ErrWriteTooMany           Error = 0x80100028
-	ErrBadSeek                Error = 0x80100029
-	ErrInvalidChv             Error = 0x8010002a
-	ErrUnknownResMng          Error = 0x8010002b
-	ErrNoSuchCertificate      Error = 0x8010002c
-	ErrCertificateUnavailable Error = 0x8010002d
-	ErrNoReadersAvailable     Error = 0x8010002e
-	ErrCommDataLost           Error = 0x8010002f
-	ErrNoKeyContainer         Error = 0x80100030
-	ErrServerTooBusy          Error = 0x80100031
-	ErrUnsupportedCard        Error = 0x80100065
-	ErrUnresponsiveCard       Error = 0x80100066
-	ErrUnpoweredCard          Error = 0x80100067
-	ErrResetCard              Error = 0x80100068
-	ErrRemovedCard            Error = 0x80100069
-	ErrSecurityViolation      Error = 0x8010006a
-	ErrWrongChv               Error = 0x8010006b
-	ErrChvBlocked             Error = 0x8010006c
-	ErrEof                    Error = 0x8010006d
-	ErrCancelledByUser        Error = 0x8010006e
-	ErrCardNotAuthenticated   Error = 0x8010006f
-)
-
-type Protocol uint32
-
-const (
-	ProtocolUndefined Protocol = 0x0
-	ProtocolT0        Protocol = 0x1
-	ProtocolT1        Protocol = 0x2
-	ProtocolAny       Protocol = ProtocolT0 | ProtocolT1
-)
-
-type ShareMode uint32
-
-const (
-	ShareExclusive ShareMode = 0x1
-	ShareShared    ShareMode = 0x2
-	ShareDirect    ShareMode = 0x3
-)
-
-type Disposition uint32
-
-const (
-	LeaveCard   Disposition = 0x0
-	ResetCard   Disposition = 0x1
-	UnpowerCard Disposition = 0x2
-	EjectCard   Disposition = 0x3
-)
-
-type Scope uint32
-
-const (
-	ScopeUser     Scope = 0x0
-	ScopeTerminal Scope = 0x1
-	ScopeSystem   Scope = 0x2
-)
-
-type State uint32
-
-const (
-	Unknown    State = 0x1
-	Absent     State = 0x2
-	Present    State = 0x4
-	Swallowed  State = 0x8
-	Powered    State = 0x10
-	Negotiable State = 0x20
-	Specific   State = 0x40
-)
-
-type StateFlag uint32
-
-const (
-	StateUnaware     StateFlag = 0x0
-	StateIgnore      StateFlag = 0x1
-	StateChanged     StateFlag = 0x2
-	StateUnknown     StateFlag = 0x4
-	StateUnavailable StateFlag = 0x8
-	StateEmpty       StateFlag = 0x10
-	StatePresent     StateFlag = 0x20
-	StateAtrmatch    StateFlag = 0x40
-	StateExclusive   StateFlag = 0x80
-	StateInuse       StateFlag = 0x100
-	StateMute        StateFlag = 0x200
-	StateUnpowered   StateFlag = 0x400
-)
-
-const (
-	maxBufferSize         = 0x108
-	maxBufferSizeExtended = 0x1000c
-	maxReadername         = 0x80
-	maxAtrSize            = 0x21
-)
-
-const (
-	infiniteTimeout = 0xffffffff
-)

+ 29 - 0
vendor/github.com/gballet/go-libpcsclite/LICENSE

@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2019, Guillaume Ballet
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 53 - 0
vendor/github.com/gballet/go-libpcsclite/README.md

@@ -0,0 +1,53 @@
+# go-libpcsclite
+
+A golang implementation of the [libpcpsclite](http://github.com/LudovicRousseau/PCSC) client. It connects to the `pcscd` daemon over sockets.
+
+## Purpose
+
+The goal is for major open source projects to distribute a single binary that doesn't depend on `libpcsclite`. It provides an extra function `CheckPCSCDaemon` that will tell the user if `pcscd` is running.
+
+## Building
+
+TODO
+
+## Example
+
+TODO
+
+## TODO
+
+  - [ ] Finish this README
+  - [ ] Lock context
+  - [ ] implement missing functions
+
+## License
+
+BSD 3-Clause License
+
+Copyright (c) 2019, Guillaume Ballet
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 99 - 0
vendor/github.com/gballet/go-libpcsclite/doc.go

@@ -0,0 +1,99 @@
+// BSD 3-Clause License
+//
+// Copyright (c) 2019, Guillaume Ballet
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// * Neither the name of the copyright holder nor the names of its
+//   contributors may be used to endorse or promote products derived from
+//   this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package pcsc
+
+const (
+	SCardSuccess                   = 0x00000000 /* No error was encountered. */
+
+	AutoAllocate  = -1     /* see SCardFreeMemory() */
+	ScopeUser     = 0x0000 /* Scope in user space */
+	ScopeTerminal = 0x0001 /* Scope in terminal */
+	ScopeSystem   = 0x0002 /* Scope in system */
+	ScopeGlobal   = 0x0003 /* Scope is global */
+
+	ProtocolUndefined = 0x0000                    /* protocol not set */
+	ProtocolUnSet     = ProtocolUndefined         /* backward compat */
+	ProtocolT0        = 0x0001                    /* T=0 active protocol. */
+	ProtocolT1        = 0x0002                    /* T=1 active protocol. */
+	ProtocolRaw       = 0x0004                    /* Raw active protocol. */
+	ProtocolT15       = 0x0008                    /* T=15 protocol. */
+	ProtocolAny       = (ProtocolT0 | ProtocolT1) /* IFD determines prot. */
+
+	ShareExclusive = 0x0001 /* Exclusive mode only */
+	ShareShared    = 0x0002 /* Shared mode only */
+	ShareDirect    = 0x0003 /* Raw mode only */
+
+	LeaveCard   = 0x0000 /* Do nothing on close */
+	ResetCard   = 0x0001 /* Reset on close */
+	UnpowerCard = 0x0002 /* Power down on close */
+	EjectCard   = 0x0003 /* Eject on close */
+
+	SCardUnknown    = 0x0001 /* Unknown state */
+	SCardAbsent     = 0x0002 /* Card is absent */
+	SCardPresent    = 0x0004 /* Card is present */
+	SCardSwallowed  = 0x0008 /* Card not powered */
+	SCardPowever    = 0x0010 /* Card is powered */
+	SCardNegotiable = 0x0020 /* Ready for PTS */
+	SCardSpecific   = 0x0040 /* PTS has been set */
+
+	PCSCDSockName = "/run/pcscd/pcscd.comm"
+)
+
+// List of commands to send to the daemon
+const (
+	_                                   = iota
+	SCardEstablishContext               /* used by SCardEstablishContext() */
+	SCardReleaseContext                 /* used by SCardReleaseContext() */
+	SCardListReaders                    /* used by SCardListReaders() */
+	SCardConnect                        /* used by SCardConnect() */
+	SCardReConnect                      /* used by SCardReconnect() */
+	SCardDisConnect                     /* used by SCardDisconnect() */
+	SCardBeginTransaction               /* used by SCardBeginTransaction() */
+	SCardEndTransaction                 /* used by SCardEndTransaction() */
+	SCardTransmit                       /* used by SCardTransmit() */
+	SCardControl                        /* used by SCardControl() */
+	SCardStatus                         /* used by SCardStatus() */
+	SCardGetStatusChange                /* not used */
+	SCardCancel                         /* used by SCardCancel() */
+	SCardCancelTransaction              /* not used */
+	SCardGetAttrib                      /* used by SCardGetAttrib() */
+	SCardSetAttrib                      /* used by SCardSetAttrib() */
+	CommandVersion                      /* get the client/server protocol version */
+	CommandGetReaderState               /* get the readers state */
+	CommandWaitReaderStateChange        /* wait for a reader state change */
+	CommandStopWaitingReaderStateChange /* stop waiting for a reader state change */
+)
+
+// Protocol information
+const (
+	ProtocolVersionMajor = 4 /* IPC major */
+	ProtocolVersionMinor = 3 /* IPC minor */
+)

+ 1 - 0
vendor/github.com/gballet/go-libpcsclite/go.mod

@@ -0,0 +1 @@
+module github.com/gballet/go-libpcsclite

+ 78 - 0
vendor/github.com/gballet/go-libpcsclite/msg.go

@@ -0,0 +1,78 @@
+// BSD 3-Clause License
+//
+// Copyright (c) 2019, Guillaume Ballet
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// * Neither the name of the copyright holder nor the names of its
+//   contributors may be used to endorse or promote products derived from
+//   this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package pcsc
+
+import (
+	"encoding/binary"
+	"net"
+)
+
+/**
+ * @brief Wrapper for the MessageSend() function.
+ *
+ * Called by clients to send messages to the server.
+ * The parameters \p command and \p data are set in the \c sharedSegmentMsg
+ * struct in order to be sent.
+ *
+ * @param[in] command Command to be sent.
+ * @param[in] dwClientID Client socket handle.
+ * @param[in] size Size of the message (\p data).
+ * @param[in] data_void Data to be sent.
+ *
+ * @return Same error codes as MessageSend().
+ */
+func messageSendWithHeader(command uint32, conn net.Conn, data []byte) error {
+	/* Translate header into bytes */
+	msgData := make([]byte, 8+len(data))
+	binary.LittleEndian.PutUint32(msgData[4:], command)
+	binary.LittleEndian.PutUint32(msgData, uint32(len(data)))
+
+	/* Copy payload */
+	copy(msgData[8:], data)
+
+	_, err := conn.Write(msgData)
+	return err
+}
+
+// ClientSetupSession prepares a communication channel for the client to talk to the server.
+// This is called by the application to create a socket for local IPC with the
+// server. The socket is associated to the file \c PCSCLITE_CSOCK_NAME.
+/*
+ * @param[out] pdwClientID Client Connection ID.
+ *
+ * @retval 0 Success.
+ * @retval -1 Can not create the socket.
+ * @retval -1 The socket can not open a connection.
+ * @retval -1 Can not set the socket to non-blocking.
+ */
+func clientSetupSession() (net.Conn, error) {
+	return net.Dial("unix", PCSCDSockName)
+}

+ 371 - 0
vendor/github.com/gballet/go-libpcsclite/winscard.go

@@ -0,0 +1,371 @@
+// BSD 3-Clause License
+//
+// Copyright (c) 2019, Guillaume Ballet
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// * Neither the name of the copyright holder nor the names of its
+//   contributors may be used to endorse or promote products derived from
+//   this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package pcsc
+
+import (
+	"encoding/binary"
+	"fmt"
+	"net"
+	"unsafe"
+)
+
+// Client contains all the information needed to establish
+// and maintain a connection to the deamon/card.
+type Client struct {
+	conn net.Conn
+
+	minor uint32
+	major uint32
+
+	ctx uint32
+
+	readerStateDescriptors [MaxReaderStateDescriptors]ReaderState
+}
+
+// EstablishContext asks the PCSC daemon to create a context
+// handle for further communication with connected cards and
+// readers.
+func EstablishContext(scope uint32) (*Client, error) {
+	client := &Client{}
+
+	conn, err := clientSetupSession()
+	if err != nil {
+		return nil, err
+	}
+	client.conn = conn
+
+	/* Exchange version information */
+	payload := make([]byte, 12)
+	binary.LittleEndian.PutUint32(payload, ProtocolVersionMajor)
+	binary.LittleEndian.PutUint32(payload[4:], ProtocolVersionMinor)
+	binary.LittleEndian.PutUint32(payload[8:], SCardSuccess)
+	err = messageSendWithHeader(CommandVersion, conn, payload)
+	if err != nil {
+		return nil, err
+	}
+	response := make([]byte, 12)
+	n, err := conn.Read(response)
+	if err != nil {
+		return nil, err
+	}
+	if n != len(response) {
+		return nil, fmt.Errorf("invalid response length: expected %d, got %d", len(response), n)
+	}
+	code := binary.LittleEndian.Uint32(response[8:])
+	if code != SCardSuccess {
+		return nil, fmt.Errorf("invalid response code: expected %d, got %d", SCardSuccess, code)
+	}
+	client.major = binary.LittleEndian.Uint32(response)
+	client.minor = binary.LittleEndian.Uint32(response[4:])
+	if client.major != ProtocolVersionMajor || client.minor != ProtocolVersionMinor {
+		return nil, fmt.Errorf("invalid version found: expected %d.%d, got %d.%d", ProtocolVersionMajor, ProtocolVersionMinor, client.major, client.minor)
+	}
+
+	/* Establish the context proper */
+	binary.LittleEndian.PutUint32(payload, scope)
+	binary.LittleEndian.PutUint32(payload[4:], 0)
+	binary.LittleEndian.PutUint32(payload[8:], SCardSuccess)
+	err = messageSendWithHeader(SCardEstablishContext, conn, payload)
+	if err != nil {
+		return nil, err
+	}
+	response = make([]byte, 12)
+	n, err = conn.Read(response)
+	if err != nil {
+		return nil, err
+	}
+	if n != len(response) {
+		return nil, fmt.Errorf("invalid response length: expected %d, got %d", len(response), n)
+	}
+	code = binary.LittleEndian.Uint32(response[8:])
+	if code != SCardSuccess {
+		return nil, fmt.Errorf("invalid response code: expected %d, got %d", SCardSuccess, code)
+	}
+	client.ctx = binary.LittleEndian.Uint32(response[4:])
+
+	return client, nil
+}
+
+// ReleaseContext tells the daemon that the client will no longer
+// need the context.
+func (client *Client) ReleaseContext() error {
+	data := [8]byte{}
+	binary.LittleEndian.PutUint32(data[:], client.ctx)
+	binary.LittleEndian.PutUint32(data[4:], SCardSuccess)
+	err := messageSendWithHeader(SCardReleaseContext, client.conn, data[:])
+	if err != nil {
+		return err
+	}
+	total := 0
+	for total < len(data) {
+		n, err := client.conn.Read(data[total:])
+		if err != nil {
+			return err
+		}
+		total += n
+	}
+	code := binary.LittleEndian.Uint32(data[4:])
+	if code != SCardSuccess {
+		return fmt.Errorf("invalid return code: %x", code)
+	}
+
+	return nil
+}
+
+// Constants related to the reader state structure
+const (
+	ReaderStateNameLength       = 128
+	ReaderStateMaxAtrSizeLength = 33
+	// NOTE: ATR is 32-byte aligned in the C version, which means it's
+	// actually 36 byte long and not 33.
+	ReaderStateDescriptorLength = ReaderStateNameLength + ReaderStateMaxAtrSizeLength + 5*4 + 3
+
+	MaxReaderStateDescriptors = 16
+)
+
+// ReaderState represent the state of a single reader, as reported
+// by the PCSC daemon.
+type ReaderState struct {
+	Name          string /* reader name */
+	eventCounter  uint32 /* number of card events */
+	readerState   uint32 /* SCARD_* bit field */
+	readerSharing uint32 /* PCSCLITE_SHARING_* sharing status */
+
+	cardAtr       [ReaderStateMaxAtrSizeLength]byte /* ATR */
+	cardAtrLength uint32                            /* ATR length */
+	cardProtocol  uint32                            /* SCARD_PROTOCOL_* value */
+}
+
+func getReaderState(data []byte) (ReaderState, error) {
+	ret := ReaderState{}
+	if len(data) < ReaderStateDescriptorLength {
+		return ret, fmt.Errorf("could not unmarshall data of length %d < %d", len(data), ReaderStateDescriptorLength)
+	}
+
+	ret.Name = string(data[:ReaderStateNameLength])
+	ret.eventCounter = binary.LittleEndian.Uint32(data[unsafe.Offsetof(ret.eventCounter):])
+	ret.readerState = binary.LittleEndian.Uint32(data[unsafe.Offsetof(ret.readerState):])
+	ret.readerSharing = binary.LittleEndian.Uint32(data[unsafe.Offsetof(ret.readerSharing):])
+	copy(ret.cardAtr[:], data[unsafe.Offsetof(ret.cardAtr):unsafe.Offsetof(ret.cardAtr)+ReaderStateMaxAtrSizeLength])
+	ret.cardAtrLength = binary.LittleEndian.Uint32(data[unsafe.Offsetof(ret.cardAtrLength):])
+	ret.cardProtocol = binary.LittleEndian.Uint32(data[unsafe.Offsetof(ret.cardProtocol):])
+
+	return ret, nil
+}
+
+// ListReaders gets the list of readers from the daemon
+func (client *Client) ListReaders() ([]string, error) {
+	err := messageSendWithHeader(CommandGetReaderState, client.conn, []byte{})
+	if err != nil {
+		return nil, err
+	}
+	response := make([]byte, ReaderStateDescriptorLength*MaxReaderStateDescriptors)
+	total := 0
+	for total < len(response) {
+		n, err := client.conn.Read(response[total:])
+		if err != nil {
+			return nil, err
+		}
+		total += n
+	}
+
+	var names []string
+	for i := range client.readerStateDescriptors {
+		desc, err := getReaderState(response[i*ReaderStateDescriptorLength:])
+		if err != nil {
+			return nil, err
+		}
+		client.readerStateDescriptors[i] = desc
+		if desc.Name[0] == 0 {
+			break
+		}
+		names = append(names, desc.Name)
+	}
+
+	return names, nil
+}
+
+// Offsets into the Connect request/response packet
+const (
+	SCardConnectReaderNameOffset        = 4
+	SCardConnectShareModeOffset         = SCardConnectReaderNameOffset + ReaderStateNameLength
+	SCardConnectPreferredProtocolOffset = SCardConnectShareModeOffset + 4
+	SCardConnectReturnValueOffset       = SCardConnectPreferredProtocolOffset + 12
+)
+
+// Card represents the connection to a card
+type Card struct {
+	handle      uint32
+	activeProto uint32
+	client      *Client
+}
+
+// Connect asks the daemon to connect to the card
+func (client *Client) Connect(name string, shareMode uint32, preferredProtocol uint32) (*Card, error) {
+	request := make([]byte, ReaderStateNameLength+4*6)
+	binary.LittleEndian.PutUint32(request, client.ctx)
+	copy(request[SCardConnectReaderNameOffset:], []byte(name))
+	binary.LittleEndian.PutUint32(request[SCardConnectShareModeOffset:], shareMode)
+	binary.LittleEndian.PutUint32(request[SCardConnectPreferredProtocolOffset:], preferredProtocol)
+	binary.LittleEndian.PutUint32(request[SCardConnectReturnValueOffset:], SCardSuccess)
+
+	err := messageSendWithHeader(SCardConnect, client.conn, request)
+	if err != nil {
+		return nil, err
+	}
+	response := make([]byte, ReaderStateNameLength+4*6)
+	total := 0
+	for total < len(response) {
+		n, err := client.conn.Read(response[total:])
+		if err != nil {
+			return nil, err
+		}
+		fmt.Println("total, n", total, n, response)
+		total += n
+	}
+	code := binary.LittleEndian.Uint32(response[148:])
+	if code != SCardSuccess {
+		return nil, fmt.Errorf("invalid return code: %x", code)
+	}
+	handle := binary.LittleEndian.Uint32(response[140:])
+	active := binary.LittleEndian.Uint32(response[SCardConnectPreferredProtocolOffset:])
+
+	return &Card{handle: handle, activeProto: active, client: client}, nil
+}
+
+/**
+* @brief contained in \ref SCARD_TRANSMIT Messages.
+*
+* These data are passed throw the field \c sharedSegmentMsg.data.
+ */
+type transmit struct {
+	hCard             uint32
+	ioSendPciProtocol uint32
+	ioSendPciLength   uint32
+	cbSendLength      uint32
+	ioRecvPciProtocol uint32
+	ioRecvPciLength   uint32
+	pcbRecvLength     uint32
+	rv                uint32
+}
+
+// SCardIoRequest contains the info needed for performing an IO request
+type SCardIoRequest struct {
+	proto  uint32
+	length uint32
+}
+
+const (
+	TransmitRequestLength = 32
+)
+
+// Transmit sends request data to a card and returns the response
+func (card *Card) Transmit(adpu []byte) ([]byte, *SCardIoRequest, error) {
+	request := [TransmitRequestLength]byte{}
+	binary.LittleEndian.PutUint32(request[:], card.handle)
+	binary.LittleEndian.PutUint32(request[4:] /*card.activeProto*/, 2)
+	binary.LittleEndian.PutUint32(request[8:], 8)
+	binary.LittleEndian.PutUint32(request[12:], uint32(len(adpu)))
+	binary.LittleEndian.PutUint32(request[16:], 0)
+	binary.LittleEndian.PutUint32(request[20:], 0)
+	binary.LittleEndian.PutUint32(request[24:], 0x10000)
+	binary.LittleEndian.PutUint32(request[28:], SCardSuccess)
+	err := messageSendWithHeader(SCardTransmit, card.client.conn, request[:])
+	if err != nil {
+		return nil, nil, err
+	}
+	// Add the ADPU payload after the transmit descriptor
+	n, err := card.client.conn.Write(adpu)
+	if err != nil {
+		return nil, nil, err
+	}
+	if n != len(adpu) {
+		return nil, nil, fmt.Errorf("Invalid number of bytes written: expected %d, got %d", len(adpu), n)
+	}
+	response := [TransmitRequestLength]byte{}
+	total := 0
+	for total < len(response) {
+		n, err = card.client.conn.Read(response[total:])
+		if err != nil {
+			return nil, nil, err
+		}
+		total += n
+	}
+
+	code := binary.LittleEndian.Uint32(response[28:])
+	if code != SCardSuccess {
+		return nil, nil, fmt.Errorf("invalid return code: %x", code)
+	}
+
+	// Recover the response data
+	recvProto := binary.LittleEndian.Uint32(response[16:])
+	recvLength := binary.LittleEndian.Uint32(response[20:])
+	recv := &SCardIoRequest{proto: recvProto, length: recvLength}
+	recvLength = binary.LittleEndian.Uint32(response[24:])
+	recvData := make([]byte, recvLength)
+	total = 0
+	for uint32(total) < recvLength {
+		n, err := card.client.conn.Read(recvData[total:])
+		if err != nil {
+			return nil, nil, err
+		}
+		total += n
+	}
+
+	return recvData, recv, nil
+}
+
+// Disconnect tells the PCSC daemon that the client is no longer
+// interested in communicating with the card.
+func (card *Card) Disconnect(disposition uint32) error {
+	data := [12]byte{}
+	binary.LittleEndian.PutUint32(data[:], card.handle)
+	binary.LittleEndian.PutUint32(data[4:], disposition)
+	binary.LittleEndian.PutUint32(data[8:], SCardSuccess)
+	err := messageSendWithHeader(SCardDisConnect, card.client.conn, data[:])
+	if err != nil {
+		return err
+	}
+	total := 0
+	for total < len(data) {
+		n, err := card.client.conn.Read(data[total:])
+		if err != nil {
+			return err
+		}
+		total += n
+	}
+	code := binary.LittleEndian.Uint32(data[8:])
+	if code != SCardSuccess {
+		return fmt.Errorf("invalid return code: %x", code)
+	}
+
+	return nil
+}

+ 6 - 0
vendor/vendor.json

@@ -145,6 +145,12 @@
 			"revision": "ca190fb6ffbc076ff49197b7168a760f30182d2e",
 			"revisionTime": "2018-04-18T12:24:29Z"
 		},
+		{
+			"checksumSHA1": "GnNfMrYs/4m+HCtDBF7HpPUFFVw=",
+			"path": "github.com/gballet/go-libpcsclite",
+			"revision": "95b81846253cd854b8bb8f2fd9cc6056d0681ac4",
+			"revisionTime": "2019-03-13T11:40:44Z"
+		},
 		{
 			"checksumSHA1": "gxV/cPPLkByTdY8y172t7v4qcZA=",
 			"path": "github.com/go-ole/go-ole",