aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillaume Ballet <gballet@gmail.com>2019-03-15 06:03:13 +0800
committerGuillaume Ballet <gballet@gmail.com>2019-04-08 19:21:22 +0800
commit5617dca1c9275d7e00b27b9525a1a757fb60c203 (patch)
tree1d36ebbe66ad4c6092f308774be7310b40fca6fe
parentae82c58631c05bebdb064ffabf2ce8c974585b34 (diff)
downloadgo-tangerine-5617dca1c9275d7e00b27b9525a1a757fb60c203.tar
go-tangerine-5617dca1c9275d7e00b27b9525a1a757fb60c203.tar.gz
go-tangerine-5617dca1c9275d7e00b27b9525a1a757fb60c203.tar.bz2
go-tangerine-5617dca1c9275d7e00b27b9525a1a757fb60c203.tar.lz
go-tangerine-5617dca1c9275d7e00b27b9525a1a757fb60c203.tar.xz
go-tangerine-5617dca1c9275d7e00b27b9525a1a757fb60c203.tar.zst
go-tangerine-5617dca1c9275d7e00b27b9525a1a757fb60c203.zip
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
-rw-r--r--accounts/scwallet/hub.go10
-rw-r--r--accounts/scwallet/securechannel.go32
-rw-r--r--accounts/scwallet/wallet.go31
-rw-r--r--console/bridge.go4
-rw-r--r--vendor/github.com/ebfe/scard/LICENSE23
-rw-r--r--vendor/github.com/ebfe/scard/README.md14
-rw-r--r--vendor/github.com/ebfe/scard/scard.go283
-rw-r--r--vendor/github.com/ebfe/scard/scard_darwin.go219
-rw-r--r--vendor/github.com/ebfe/scard/scard_unix.go206
-rw-r--r--vendor/github.com/ebfe/scard/scard_windows.go221
-rw-r--r--vendor/github.com/ebfe/scard/zconst.go190
-rw-r--r--vendor/github.com/gballet/go-libpcsclite/LICENSE29
-rw-r--r--vendor/github.com/gballet/go-libpcsclite/README.md53
-rw-r--r--vendor/github.com/gballet/go-libpcsclite/doc.go99
-rw-r--r--vendor/github.com/gballet/go-libpcsclite/go.mod1
-rw-r--r--vendor/github.com/gballet/go-libpcsclite/msg.go78
-rw-r--r--vendor/github.com/gballet/go-libpcsclite/winscard.go371
-rw-r--r--vendor/vendor.json6
18 files changed, 678 insertions, 1192 deletions
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 <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.
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 <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])
- }
- }
-}
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 <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])
- }
- }
-}
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
@@ -146,6 +146,12 @@
"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",
"revision": "a41e3c4b706f6ae8dfbff342b06e40fa4d2d0506",