From 5617dca1c9275d7e00b27b9525a1a757fb60c203 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Thu, 14 Mar 2019 23:03:13 +0100 Subject: 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 --- accounts/scwallet/hub.go | 10 +- accounts/scwallet/securechannel.go | 32 +- accounts/scwallet/wallet.go | 31 +- console/bridge.go | 4 +- vendor/github.com/ebfe/scard/LICENSE | 23 -- vendor/github.com/ebfe/scard/README.md | 14 - vendor/github.com/ebfe/scard/scard.go | 283 ---------------- vendor/github.com/ebfe/scard/scard_darwin.go | 219 ------------ vendor/github.com/ebfe/scard/scard_unix.go | 206 ------------ vendor/github.com/ebfe/scard/scard_windows.go | 221 ------------ vendor/github.com/ebfe/scard/zconst.go | 190 ----------- vendor/github.com/gballet/go-libpcsclite/LICENSE | 29 ++ vendor/github.com/gballet/go-libpcsclite/README.md | 53 +++ vendor/github.com/gballet/go-libpcsclite/doc.go | 99 ++++++ vendor/github.com/gballet/go-libpcsclite/go.mod | 1 + vendor/github.com/gballet/go-libpcsclite/msg.go | 78 +++++ .../github.com/gballet/go-libpcsclite/winscard.go | 371 +++++++++++++++++++++ vendor/vendor.json | 6 + 18 files changed, 678 insertions(+), 1192 deletions(-) delete mode 100644 vendor/github.com/ebfe/scard/LICENSE delete mode 100644 vendor/github.com/ebfe/scard/README.md delete mode 100644 vendor/github.com/ebfe/scard/scard.go delete mode 100644 vendor/github.com/ebfe/scard/scard_darwin.go delete mode 100644 vendor/github.com/ebfe/scard/scard_unix.go delete mode 100644 vendor/github.com/ebfe/scard/scard_windows.go delete mode 100644 vendor/github.com/ebfe/scard/zconst.go create mode 100644 vendor/github.com/gballet/go-libpcsclite/LICENSE create mode 100644 vendor/github.com/gballet/go-libpcsclite/README.md create mode 100644 vendor/github.com/gballet/go-libpcsclite/doc.go create mode 100644 vendor/github.com/gballet/go-libpcsclite/go.mod create mode 100644 vendor/github.com/gballet/go-libpcsclite/msg.go create mode 100644 vendor/github.com/gballet/go-libpcsclite/winscard.go diff --git a/accounts/scwallet/hub.go b/accounts/scwallet/hub.go index d265458b9..bdc546d54 100644 --- a/accounts/scwallet/hub.go +++ b/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 diff --git a/accounts/scwallet/securechannel.go b/accounts/scwallet/securechannel.go index 1650dfbe5..39db89a8c 100644 --- a/accounts/scwallet/securechannel.go +++ b/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() diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index 39e80eb3b..c734da6b2 100644 --- a/accounts/scwallet/wallet.go +++ b/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. diff --git a/console/bridge.go b/console/bridge.go index b022a465d..bb14abca2 100644 --- a/console/bridge.go +++ b/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) diff --git a/vendor/github.com/ebfe/scard/LICENSE b/vendor/github.com/ebfe/scard/LICENSE deleted file mode 100644 index 0d220e7ae..000000000 --- a/vendor/github.com/ebfe/scard/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2016, Michael Gehring -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. diff --git a/vendor/github.com/ebfe/scard/README.md b/vendor/github.com/ebfe/scard/README.md deleted file mode 100644 index cdafb2c7b..000000000 --- a/vendor/github.com/ebfe/scard/README.md +++ /dev/null @@ -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. diff --git a/vendor/github.com/ebfe/scard/scard.go b/vendor/github.com/ebfe/scard/scard.go deleted file mode 100644 index a5f0ae16b..000000000 --- a/vendor/github.com/ebfe/scard/scard.go +++ /dev/null @@ -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 -} diff --git a/vendor/github.com/ebfe/scard/scard_darwin.go b/vendor/github.com/ebfe/scard/scard_darwin.go deleted file mode 100644 index 83a1597b3..000000000 --- a/vendor/github.com/ebfe/scard/scard_darwin.go +++ /dev/null @@ -1,219 +0,0 @@ -// +build darwin - -package scard - -// #cgo LDFLAGS: -framework PCSC -// #cgo CFLAGS: -I /usr/include -// #include -// #include -// #include -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]) - } - } -} diff --git a/vendor/github.com/ebfe/scard/scard_unix.go b/vendor/github.com/ebfe/scard/scard_unix.go deleted file mode 100644 index 21910318f..000000000 --- a/vendor/github.com/ebfe/scard/scard_unix.go +++ /dev/null @@ -1,206 +0,0 @@ -// +build !windows,!darwin - -package scard - -// #cgo pkg-config: libpcsclite -// #include -// #include -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]) - } - } -} diff --git a/vendor/github.com/ebfe/scard/scard_windows.go b/vendor/github.com/ebfe/scard/scard_windows.go deleted file mode 100644 index bc852da04..000000000 --- a/vendor/github.com/ebfe/scard/scard_windows.go +++ /dev/null @@ -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) -} diff --git a/vendor/github.com/ebfe/scard/zconst.go b/vendor/github.com/ebfe/scard/zconst.go deleted file mode 100644 index 675db21dc..000000000 --- a/vendor/github.com/ebfe/scard/zconst.go +++ /dev/null @@ -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 -) diff --git a/vendor/github.com/gballet/go-libpcsclite/LICENSE b/vendor/github.com/gballet/go-libpcsclite/LICENSE new file mode 100644 index 000000000..52d9e62b0 --- /dev/null +++ b/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. diff --git a/vendor/github.com/gballet/go-libpcsclite/README.md b/vendor/github.com/gballet/go-libpcsclite/README.md new file mode 100644 index 000000000..baca30ff8 --- /dev/null +++ b/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. \ No newline at end of file diff --git a/vendor/github.com/gballet/go-libpcsclite/doc.go b/vendor/github.com/gballet/go-libpcsclite/doc.go new file mode 100644 index 000000000..394957909 --- /dev/null +++ b/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 */ +) diff --git a/vendor/github.com/gballet/go-libpcsclite/go.mod b/vendor/github.com/gballet/go-libpcsclite/go.mod new file mode 100644 index 000000000..e97f46b7f --- /dev/null +++ b/vendor/github.com/gballet/go-libpcsclite/go.mod @@ -0,0 +1 @@ +module github.com/gballet/go-libpcsclite diff --git a/vendor/github.com/gballet/go-libpcsclite/msg.go b/vendor/github.com/gballet/go-libpcsclite/msg.go new file mode 100644 index 000000000..53f543530 --- /dev/null +++ b/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) +} diff --git a/vendor/github.com/gballet/go-libpcsclite/winscard.go b/vendor/github.com/gballet/go-libpcsclite/winscard.go new file mode 100644 index 000000000..5eb9ce430 --- /dev/null +++ b/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 +} diff --git a/vendor/vendor.json b/vendor/vendor.json index f222d95dc..a23750f9b 100644 --- a/vendor/vendor.json +++ b/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", -- cgit v1.2.3