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
This commit is contained in:
parent
ae82c58631
commit
5617dca1c9
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
23
vendor/github.com/ebfe/scard/LICENSE
generated
vendored
23
vendor/github.com/ebfe/scard/LICENSE
generated
vendored
@ -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.
|
14
vendor/github.com/ebfe/scard/README.md
generated
vendored
14
vendor/github.com/ebfe/scard/README.md
generated
vendored
@ -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.
|
283
vendor/github.com/ebfe/scard/scard.go
generated
vendored
283
vendor/github.com/ebfe/scard/scard.go
generated
vendored
@ -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
|
||||
}
|
219
vendor/github.com/ebfe/scard/scard_darwin.go
generated
vendored
219
vendor/github.com/ebfe/scard/scard_darwin.go
generated
vendored
@ -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])
|
||||
}
|
||||
}
|
||||
}
|
206
vendor/github.com/ebfe/scard/scard_unix.go
generated
vendored
206
vendor/github.com/ebfe/scard/scard_unix.go
generated
vendored
@ -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])
|
||||
}
|
||||
}
|
||||
}
|
221
vendor/github.com/ebfe/scard/scard_windows.go
generated
vendored
221
vendor/github.com/ebfe/scard/scard_windows.go
generated
vendored
@ -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)
|
||||
}
|
190
vendor/github.com/ebfe/scard/zconst.go
generated
vendored
190
vendor/github.com/ebfe/scard/zconst.go
generated
vendored
@ -1,190 +0,0 @@
|
||||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs -- -I /usr/include/PCSC/ const.go
|
||||
|
||||
package scard
|
||||
|
||||
type Attrib uint32
|
||||
|
||||
const (
|
||||
AttrVendorName Attrib = 0x10100
|
||||
AttrVendorIfdType Attrib = 0x10101
|
||||
AttrVendorIfdVersion Attrib = 0x10102
|
||||
AttrVendorIfdSerialNo Attrib = 0x10103
|
||||
AttrChannelId Attrib = 0x20110
|
||||
AttrAsyncProtocolTypes Attrib = 0x30120
|
||||
AttrDefaultClk Attrib = 0x30121
|
||||
AttrMaxClk Attrib = 0x30122
|
||||
AttrDefaultDataRate Attrib = 0x30123
|
||||
AttrMaxDataRate Attrib = 0x30124
|
||||
AttrMaxIfsd Attrib = 0x30125
|
||||
AttrSyncProtocolTypes Attrib = 0x30126
|
||||
AttrPowerMgmtSupport Attrib = 0x40131
|
||||
AttrUserToCardAuthDevice Attrib = 0x50140
|
||||
AttrUserAuthInputDevice Attrib = 0x50142
|
||||
AttrCharacteristics Attrib = 0x60150
|
||||
AttrCurrentProtocolType Attrib = 0x80201
|
||||
AttrCurrentClk Attrib = 0x80202
|
||||
AttrCurrentF Attrib = 0x80203
|
||||
AttrCurrentD Attrib = 0x80204
|
||||
AttrCurrentN Attrib = 0x80205
|
||||
AttrCurrentW Attrib = 0x80206
|
||||
AttrCurrentIfsc Attrib = 0x80207
|
||||
AttrCurrentIfsd Attrib = 0x80208
|
||||
AttrCurrentBwt Attrib = 0x80209
|
||||
AttrCurrentCwt Attrib = 0x8020a
|
||||
AttrCurrentEbcEncoding Attrib = 0x8020b
|
||||
AttrExtendedBwt Attrib = 0x8020c
|
||||
AttrIccPresence Attrib = 0x90300
|
||||
AttrIccInterfaceStatus Attrib = 0x90301
|
||||
AttrCurrentIoState Attrib = 0x90302
|
||||
AttrAtrString Attrib = 0x90303
|
||||
AttrIccTypePerAtr Attrib = 0x90304
|
||||
AttrEscReset Attrib = 0x7a000
|
||||
AttrEscCancel Attrib = 0x7a003
|
||||
AttrEscAuthrequest Attrib = 0x7a005
|
||||
AttrMaxinput Attrib = 0x7a007
|
||||
AttrDeviceUnit Attrib = 0x7fff0001
|
||||
AttrDeviceInUse Attrib = 0x7fff0002
|
||||
AttrDeviceFriendlyName Attrib = 0x7fff0003
|
||||
AttrDeviceSystemName Attrib = 0x7fff0004
|
||||
AttrSupressT1IfsRequest Attrib = 0x7fff0007
|
||||
)
|
||||
|
||||
type Error uint32
|
||||
|
||||
const (
|
||||
ErrSuccess Error = 0x0
|
||||
ErrInternalError Error = 0x80100001
|
||||
ErrCancelled Error = 0x80100002
|
||||
ErrInvalidHandle Error = 0x80100003
|
||||
ErrInvalidParameter Error = 0x80100004
|
||||
ErrInvalidTarget Error = 0x80100005
|
||||
ErrNoMemory Error = 0x80100006
|
||||
ErrWaitedTooLong Error = 0x80100007
|
||||
ErrInsufficientBuffer Error = 0x80100008
|
||||
ErrUnknownReader Error = 0x80100009
|
||||
ErrTimeout Error = 0x8010000a
|
||||
ErrSharingViolation Error = 0x8010000b
|
||||
ErrNoSmartcard Error = 0x8010000c
|
||||
ErrUnknownCard Error = 0x8010000d
|
||||
ErrCantDispose Error = 0x8010000e
|
||||
ErrProtoMismatch Error = 0x8010000f
|
||||
ErrNotReady Error = 0x80100010
|
||||
ErrInvalidValue Error = 0x80100011
|
||||
ErrSystemCancelled Error = 0x80100012
|
||||
ErrCommError Error = 0x80100013
|
||||
ErrUnknownError Error = 0x80100014
|
||||
ErrInvalidAtr Error = 0x80100015
|
||||
ErrNotTransacted Error = 0x80100016
|
||||
ErrReaderUnavailable Error = 0x80100017
|
||||
ErrShutdown Error = 0x80100018
|
||||
ErrPciTooSmall Error = 0x80100019
|
||||
ErrReaderUnsupported Error = 0x8010001a
|
||||
ErrDuplicateReader Error = 0x8010001b
|
||||
ErrCardUnsupported Error = 0x8010001c
|
||||
ErrNoService Error = 0x8010001d
|
||||
ErrServiceStopped Error = 0x8010001e
|
||||
ErrUnexpected Error = 0x8010001f
|
||||
ErrUnsupportedFeature Error = 0x8010001f
|
||||
ErrIccInstallation Error = 0x80100020
|
||||
ErrIccCreateorder Error = 0x80100021
|
||||
ErrFileNotFound Error = 0x80100024
|
||||
ErrNoDir Error = 0x80100025
|
||||
ErrNoFile Error = 0x80100026
|
||||
ErrNoAccess Error = 0x80100027
|
||||
ErrWriteTooMany Error = 0x80100028
|
||||
ErrBadSeek Error = 0x80100029
|
||||
ErrInvalidChv Error = 0x8010002a
|
||||
ErrUnknownResMng Error = 0x8010002b
|
||||
ErrNoSuchCertificate Error = 0x8010002c
|
||||
ErrCertificateUnavailable Error = 0x8010002d
|
||||
ErrNoReadersAvailable Error = 0x8010002e
|
||||
ErrCommDataLost Error = 0x8010002f
|
||||
ErrNoKeyContainer Error = 0x80100030
|
||||
ErrServerTooBusy Error = 0x80100031
|
||||
ErrUnsupportedCard Error = 0x80100065
|
||||
ErrUnresponsiveCard Error = 0x80100066
|
||||
ErrUnpoweredCard Error = 0x80100067
|
||||
ErrResetCard Error = 0x80100068
|
||||
ErrRemovedCard Error = 0x80100069
|
||||
ErrSecurityViolation Error = 0x8010006a
|
||||
ErrWrongChv Error = 0x8010006b
|
||||
ErrChvBlocked Error = 0x8010006c
|
||||
ErrEof Error = 0x8010006d
|
||||
ErrCancelledByUser Error = 0x8010006e
|
||||
ErrCardNotAuthenticated Error = 0x8010006f
|
||||
)
|
||||
|
||||
type Protocol uint32
|
||||
|
||||
const (
|
||||
ProtocolUndefined Protocol = 0x0
|
||||
ProtocolT0 Protocol = 0x1
|
||||
ProtocolT1 Protocol = 0x2
|
||||
ProtocolAny Protocol = ProtocolT0 | ProtocolT1
|
||||
)
|
||||
|
||||
type ShareMode uint32
|
||||
|
||||
const (
|
||||
ShareExclusive ShareMode = 0x1
|
||||
ShareShared ShareMode = 0x2
|
||||
ShareDirect ShareMode = 0x3
|
||||
)
|
||||
|
||||
type Disposition uint32
|
||||
|
||||
const (
|
||||
LeaveCard Disposition = 0x0
|
||||
ResetCard Disposition = 0x1
|
||||
UnpowerCard Disposition = 0x2
|
||||
EjectCard Disposition = 0x3
|
||||
)
|
||||
|
||||
type Scope uint32
|
||||
|
||||
const (
|
||||
ScopeUser Scope = 0x0
|
||||
ScopeTerminal Scope = 0x1
|
||||
ScopeSystem Scope = 0x2
|
||||
)
|
||||
|
||||
type State uint32
|
||||
|
||||
const (
|
||||
Unknown State = 0x1
|
||||
Absent State = 0x2
|
||||
Present State = 0x4
|
||||
Swallowed State = 0x8
|
||||
Powered State = 0x10
|
||||
Negotiable State = 0x20
|
||||
Specific State = 0x40
|
||||
)
|
||||
|
||||
type StateFlag uint32
|
||||
|
||||
const (
|
||||
StateUnaware StateFlag = 0x0
|
||||
StateIgnore StateFlag = 0x1
|
||||
StateChanged StateFlag = 0x2
|
||||
StateUnknown StateFlag = 0x4
|
||||
StateUnavailable StateFlag = 0x8
|
||||
StateEmpty StateFlag = 0x10
|
||||
StatePresent StateFlag = 0x20
|
||||
StateAtrmatch StateFlag = 0x40
|
||||
StateExclusive StateFlag = 0x80
|
||||
StateInuse StateFlag = 0x100
|
||||
StateMute StateFlag = 0x200
|
||||
StateUnpowered StateFlag = 0x400
|
||||
)
|
||||
|
||||
const (
|
||||
maxBufferSize = 0x108
|
||||
maxBufferSizeExtended = 0x1000c
|
||||
maxReadername = 0x80
|
||||
maxAtrSize = 0x21
|
||||
)
|
||||
|
||||
const (
|
||||
infiniteTimeout = 0xffffffff
|
||||
)
|
29
vendor/github.com/gballet/go-libpcsclite/LICENSE
generated
vendored
Normal file
29
vendor/github.com/gballet/go-libpcsclite/LICENSE
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2019, Guillaume Ballet
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
53
vendor/github.com/gballet/go-libpcsclite/README.md
generated
vendored
Normal file
53
vendor/github.com/gballet/go-libpcsclite/README.md
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
# go-libpcsclite
|
||||
|
||||
A golang implementation of the [libpcpsclite](http://github.com/LudovicRousseau/PCSC) client. It connects to the `pcscd` daemon over sockets.
|
||||
|
||||
## Purpose
|
||||
|
||||
The goal is for major open source projects to distribute a single binary that doesn't depend on `libpcsclite`. It provides an extra function `CheckPCSCDaemon` that will tell the user if `pcscd` is running.
|
||||
|
||||
## Building
|
||||
|
||||
TODO
|
||||
|
||||
## Example
|
||||
|
||||
TODO
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] Finish this README
|
||||
- [ ] Lock context
|
||||
- [ ] implement missing functions
|
||||
|
||||
## License
|
||||
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2019, Guillaume Ballet
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
99
vendor/github.com/gballet/go-libpcsclite/doc.go
generated
vendored
Normal file
99
vendor/github.com/gballet/go-libpcsclite/doc.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
// BSD 3-Clause License
|
||||
//
|
||||
// Copyright (c) 2019, Guillaume Ballet
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package pcsc
|
||||
|
||||
const (
|
||||
SCardSuccess = 0x00000000 /* No error was encountered. */
|
||||
|
||||
AutoAllocate = -1 /* see SCardFreeMemory() */
|
||||
ScopeUser = 0x0000 /* Scope in user space */
|
||||
ScopeTerminal = 0x0001 /* Scope in terminal */
|
||||
ScopeSystem = 0x0002 /* Scope in system */
|
||||
ScopeGlobal = 0x0003 /* Scope is global */
|
||||
|
||||
ProtocolUndefined = 0x0000 /* protocol not set */
|
||||
ProtocolUnSet = ProtocolUndefined /* backward compat */
|
||||
ProtocolT0 = 0x0001 /* T=0 active protocol. */
|
||||
ProtocolT1 = 0x0002 /* T=1 active protocol. */
|
||||
ProtocolRaw = 0x0004 /* Raw active protocol. */
|
||||
ProtocolT15 = 0x0008 /* T=15 protocol. */
|
||||
ProtocolAny = (ProtocolT0 | ProtocolT1) /* IFD determines prot. */
|
||||
|
||||
ShareExclusive = 0x0001 /* Exclusive mode only */
|
||||
ShareShared = 0x0002 /* Shared mode only */
|
||||
ShareDirect = 0x0003 /* Raw mode only */
|
||||
|
||||
LeaveCard = 0x0000 /* Do nothing on close */
|
||||
ResetCard = 0x0001 /* Reset on close */
|
||||
UnpowerCard = 0x0002 /* Power down on close */
|
||||
EjectCard = 0x0003 /* Eject on close */
|
||||
|
||||
SCardUnknown = 0x0001 /* Unknown state */
|
||||
SCardAbsent = 0x0002 /* Card is absent */
|
||||
SCardPresent = 0x0004 /* Card is present */
|
||||
SCardSwallowed = 0x0008 /* Card not powered */
|
||||
SCardPowever = 0x0010 /* Card is powered */
|
||||
SCardNegotiable = 0x0020 /* Ready for PTS */
|
||||
SCardSpecific = 0x0040 /* PTS has been set */
|
||||
|
||||
PCSCDSockName = "/run/pcscd/pcscd.comm"
|
||||
)
|
||||
|
||||
// List of commands to send to the daemon
|
||||
const (
|
||||
_ = iota
|
||||
SCardEstablishContext /* used by SCardEstablishContext() */
|
||||
SCardReleaseContext /* used by SCardReleaseContext() */
|
||||
SCardListReaders /* used by SCardListReaders() */
|
||||
SCardConnect /* used by SCardConnect() */
|
||||
SCardReConnect /* used by SCardReconnect() */
|
||||
SCardDisConnect /* used by SCardDisconnect() */
|
||||
SCardBeginTransaction /* used by SCardBeginTransaction() */
|
||||
SCardEndTransaction /* used by SCardEndTransaction() */
|
||||
SCardTransmit /* used by SCardTransmit() */
|
||||
SCardControl /* used by SCardControl() */
|
||||
SCardStatus /* used by SCardStatus() */
|
||||
SCardGetStatusChange /* not used */
|
||||
SCardCancel /* used by SCardCancel() */
|
||||
SCardCancelTransaction /* not used */
|
||||
SCardGetAttrib /* used by SCardGetAttrib() */
|
||||
SCardSetAttrib /* used by SCardSetAttrib() */
|
||||
CommandVersion /* get the client/server protocol version */
|
||||
CommandGetReaderState /* get the readers state */
|
||||
CommandWaitReaderStateChange /* wait for a reader state change */
|
||||
CommandStopWaitingReaderStateChange /* stop waiting for a reader state change */
|
||||
)
|
||||
|
||||
// Protocol information
|
||||
const (
|
||||
ProtocolVersionMajor = 4 /* IPC major */
|
||||
ProtocolVersionMinor = 3 /* IPC minor */
|
||||
)
|
1
vendor/github.com/gballet/go-libpcsclite/go.mod
generated
vendored
Normal file
1
vendor/github.com/gballet/go-libpcsclite/go.mod
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
module github.com/gballet/go-libpcsclite
|
78
vendor/github.com/gballet/go-libpcsclite/msg.go
generated
vendored
Normal file
78
vendor/github.com/gballet/go-libpcsclite/msg.go
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
// BSD 3-Clause License
|
||||
//
|
||||
// Copyright (c) 2019, Guillaume Ballet
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package pcsc
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
)
|
||||
|
||||
/**
|
||||
* @brief Wrapper for the MessageSend() function.
|
||||
*
|
||||
* Called by clients to send messages to the server.
|
||||
* The parameters \p command and \p data are set in the \c sharedSegmentMsg
|
||||
* struct in order to be sent.
|
||||
*
|
||||
* @param[in] command Command to be sent.
|
||||
* @param[in] dwClientID Client socket handle.
|
||||
* @param[in] size Size of the message (\p data).
|
||||
* @param[in] data_void Data to be sent.
|
||||
*
|
||||
* @return Same error codes as MessageSend().
|
||||
*/
|
||||
func messageSendWithHeader(command uint32, conn net.Conn, data []byte) error {
|
||||
/* Translate header into bytes */
|
||||
msgData := make([]byte, 8+len(data))
|
||||
binary.LittleEndian.PutUint32(msgData[4:], command)
|
||||
binary.LittleEndian.PutUint32(msgData, uint32(len(data)))
|
||||
|
||||
/* Copy payload */
|
||||
copy(msgData[8:], data)
|
||||
|
||||
_, err := conn.Write(msgData)
|
||||
return err
|
||||
}
|
||||
|
||||
// ClientSetupSession prepares a communication channel for the client to talk to the server.
|
||||
// This is called by the application to create a socket for local IPC with the
|
||||
// server. The socket is associated to the file \c PCSCLITE_CSOCK_NAME.
|
||||
/*
|
||||
* @param[out] pdwClientID Client Connection ID.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -1 Can not create the socket.
|
||||
* @retval -1 The socket can not open a connection.
|
||||
* @retval -1 Can not set the socket to non-blocking.
|
||||
*/
|
||||
func clientSetupSession() (net.Conn, error) {
|
||||
return net.Dial("unix", PCSCDSockName)
|
||||
}
|
371
vendor/github.com/gballet/go-libpcsclite/winscard.go
generated
vendored
Normal file
371
vendor/github.com/gballet/go-libpcsclite/winscard.go
generated
vendored
Normal file
@ -0,0 +1,371 @@
|
||||
// BSD 3-Clause License
|
||||
//
|
||||
// Copyright (c) 2019, Guillaume Ballet
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package pcsc
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Client contains all the information needed to establish
|
||||
// and maintain a connection to the deamon/card.
|
||||
type Client struct {
|
||||
conn net.Conn
|
||||
|
||||
minor uint32
|
||||
major uint32
|
||||
|
||||
ctx uint32
|
||||
|
||||
readerStateDescriptors [MaxReaderStateDescriptors]ReaderState
|
||||
}
|
||||
|
||||
// EstablishContext asks the PCSC daemon to create a context
|
||||
// handle for further communication with connected cards and
|
||||
// readers.
|
||||
func EstablishContext(scope uint32) (*Client, error) {
|
||||
client := &Client{}
|
||||
|
||||
conn, err := clientSetupSession()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.conn = conn
|
||||
|
||||
/* Exchange version information */
|
||||
payload := make([]byte, 12)
|
||||
binary.LittleEndian.PutUint32(payload, ProtocolVersionMajor)
|
||||
binary.LittleEndian.PutUint32(payload[4:], ProtocolVersionMinor)
|
||||
binary.LittleEndian.PutUint32(payload[8:], SCardSuccess)
|
||||
err = messageSendWithHeader(CommandVersion, conn, payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response := make([]byte, 12)
|
||||
n, err := conn.Read(response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n != len(response) {
|
||||
return nil, fmt.Errorf("invalid response length: expected %d, got %d", len(response), n)
|
||||
}
|
||||
code := binary.LittleEndian.Uint32(response[8:])
|
||||
if code != SCardSuccess {
|
||||
return nil, fmt.Errorf("invalid response code: expected %d, got %d", SCardSuccess, code)
|
||||
}
|
||||
client.major = binary.LittleEndian.Uint32(response)
|
||||
client.minor = binary.LittleEndian.Uint32(response[4:])
|
||||
if client.major != ProtocolVersionMajor || client.minor != ProtocolVersionMinor {
|
||||
return nil, fmt.Errorf("invalid version found: expected %d.%d, got %d.%d", ProtocolVersionMajor, ProtocolVersionMinor, client.major, client.minor)
|
||||
}
|
||||
|
||||
/* Establish the context proper */
|
||||
binary.LittleEndian.PutUint32(payload, scope)
|
||||
binary.LittleEndian.PutUint32(payload[4:], 0)
|
||||
binary.LittleEndian.PutUint32(payload[8:], SCardSuccess)
|
||||
err = messageSendWithHeader(SCardEstablishContext, conn, payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response = make([]byte, 12)
|
||||
n, err = conn.Read(response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n != len(response) {
|
||||
return nil, fmt.Errorf("invalid response length: expected %d, got %d", len(response), n)
|
||||
}
|
||||
code = binary.LittleEndian.Uint32(response[8:])
|
||||
if code != SCardSuccess {
|
||||
return nil, fmt.Errorf("invalid response code: expected %d, got %d", SCardSuccess, code)
|
||||
}
|
||||
client.ctx = binary.LittleEndian.Uint32(response[4:])
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// ReleaseContext tells the daemon that the client will no longer
|
||||
// need the context.
|
||||
func (client *Client) ReleaseContext() error {
|
||||
data := [8]byte{}
|
||||
binary.LittleEndian.PutUint32(data[:], client.ctx)
|
||||
binary.LittleEndian.PutUint32(data[4:], SCardSuccess)
|
||||
err := messageSendWithHeader(SCardReleaseContext, client.conn, data[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
total := 0
|
||||
for total < len(data) {
|
||||
n, err := client.conn.Read(data[total:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
total += n
|
||||
}
|
||||
code := binary.LittleEndian.Uint32(data[4:])
|
||||
if code != SCardSuccess {
|
||||
return fmt.Errorf("invalid return code: %x", code)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Constants related to the reader state structure
|
||||
const (
|
||||
ReaderStateNameLength = 128
|
||||
ReaderStateMaxAtrSizeLength = 33
|
||||
// NOTE: ATR is 32-byte aligned in the C version, which means it's
|
||||
// actually 36 byte long and not 33.
|
||||
ReaderStateDescriptorLength = ReaderStateNameLength + ReaderStateMaxAtrSizeLength + 5*4 + 3
|
||||
|
||||
MaxReaderStateDescriptors = 16
|
||||
)
|
||||
|
||||
// ReaderState represent the state of a single reader, as reported
|
||||
// by the PCSC daemon.
|
||||
type ReaderState struct {
|
||||
Name string /* reader name */
|
||||
eventCounter uint32 /* number of card events */
|
||||
readerState uint32 /* SCARD_* bit field */
|
||||
readerSharing uint32 /* PCSCLITE_SHARING_* sharing status */
|
||||
|
||||
cardAtr [ReaderStateMaxAtrSizeLength]byte /* ATR */
|
||||
cardAtrLength uint32 /* ATR length */
|
||||
cardProtocol uint32 /* SCARD_PROTOCOL_* value */
|
||||
}
|
||||
|
||||
func getReaderState(data []byte) (ReaderState, error) {
|
||||
ret := ReaderState{}
|
||||
if len(data) < ReaderStateDescriptorLength {
|
||||
return ret, fmt.Errorf("could not unmarshall data of length %d < %d", len(data), ReaderStateDescriptorLength)
|
||||
}
|
||||
|
||||
ret.Name = string(data[:ReaderStateNameLength])
|
||||
ret.eventCounter = binary.LittleEndian.Uint32(data[unsafe.Offsetof(ret.eventCounter):])
|
||||
ret.readerState = binary.LittleEndian.Uint32(data[unsafe.Offsetof(ret.readerState):])
|
||||
ret.readerSharing = binary.LittleEndian.Uint32(data[unsafe.Offsetof(ret.readerSharing):])
|
||||
copy(ret.cardAtr[:], data[unsafe.Offsetof(ret.cardAtr):unsafe.Offsetof(ret.cardAtr)+ReaderStateMaxAtrSizeLength])
|
||||
ret.cardAtrLength = binary.LittleEndian.Uint32(data[unsafe.Offsetof(ret.cardAtrLength):])
|
||||
ret.cardProtocol = binary.LittleEndian.Uint32(data[unsafe.Offsetof(ret.cardProtocol):])
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// ListReaders gets the list of readers from the daemon
|
||||
func (client *Client) ListReaders() ([]string, error) {
|
||||
err := messageSendWithHeader(CommandGetReaderState, client.conn, []byte{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response := make([]byte, ReaderStateDescriptorLength*MaxReaderStateDescriptors)
|
||||
total := 0
|
||||
for total < len(response) {
|
||||
n, err := client.conn.Read(response[total:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
total += n
|
||||
}
|
||||
|
||||
var names []string
|
||||
for i := range client.readerStateDescriptors {
|
||||
desc, err := getReaderState(response[i*ReaderStateDescriptorLength:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.readerStateDescriptors[i] = desc
|
||||
if desc.Name[0] == 0 {
|
||||
break
|
||||
}
|
||||
names = append(names, desc.Name)
|
||||
}
|
||||
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// Offsets into the Connect request/response packet
|
||||
const (
|
||||
SCardConnectReaderNameOffset = 4
|
||||
SCardConnectShareModeOffset = SCardConnectReaderNameOffset + ReaderStateNameLength
|
||||
SCardConnectPreferredProtocolOffset = SCardConnectShareModeOffset + 4
|
||||
SCardConnectReturnValueOffset = SCardConnectPreferredProtocolOffset + 12
|
||||
)
|
||||
|
||||
// Card represents the connection to a card
|
||||
type Card struct {
|
||||
handle uint32
|
||||
activeProto uint32
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Connect asks the daemon to connect to the card
|
||||
func (client *Client) Connect(name string, shareMode uint32, preferredProtocol uint32) (*Card, error) {
|
||||
request := make([]byte, ReaderStateNameLength+4*6)
|
||||
binary.LittleEndian.PutUint32(request, client.ctx)
|
||||
copy(request[SCardConnectReaderNameOffset:], []byte(name))
|
||||
binary.LittleEndian.PutUint32(request[SCardConnectShareModeOffset:], shareMode)
|
||||
binary.LittleEndian.PutUint32(request[SCardConnectPreferredProtocolOffset:], preferredProtocol)
|
||||
binary.LittleEndian.PutUint32(request[SCardConnectReturnValueOffset:], SCardSuccess)
|
||||
|
||||
err := messageSendWithHeader(SCardConnect, client.conn, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response := make([]byte, ReaderStateNameLength+4*6)
|
||||
total := 0
|
||||
for total < len(response) {
|
||||
n, err := client.conn.Read(response[total:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println("total, n", total, n, response)
|
||||
total += n
|
||||
}
|
||||
code := binary.LittleEndian.Uint32(response[148:])
|
||||
if code != SCardSuccess {
|
||||
return nil, fmt.Errorf("invalid return code: %x", code)
|
||||
}
|
||||
handle := binary.LittleEndian.Uint32(response[140:])
|
||||
active := binary.LittleEndian.Uint32(response[SCardConnectPreferredProtocolOffset:])
|
||||
|
||||
return &Card{handle: handle, activeProto: active, client: client}, nil
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief contained in \ref SCARD_TRANSMIT Messages.
|
||||
*
|
||||
* These data are passed throw the field \c sharedSegmentMsg.data.
|
||||
*/
|
||||
type transmit struct {
|
||||
hCard uint32
|
||||
ioSendPciProtocol uint32
|
||||
ioSendPciLength uint32
|
||||
cbSendLength uint32
|
||||
ioRecvPciProtocol uint32
|
||||
ioRecvPciLength uint32
|
||||
pcbRecvLength uint32
|
||||
rv uint32
|
||||
}
|
||||
|
||||
// SCardIoRequest contains the info needed for performing an IO request
|
||||
type SCardIoRequest struct {
|
||||
proto uint32
|
||||
length uint32
|
||||
}
|
||||
|
||||
const (
|
||||
TransmitRequestLength = 32
|
||||
)
|
||||
|
||||
// Transmit sends request data to a card and returns the response
|
||||
func (card *Card) Transmit(adpu []byte) ([]byte, *SCardIoRequest, error) {
|
||||
request := [TransmitRequestLength]byte{}
|
||||
binary.LittleEndian.PutUint32(request[:], card.handle)
|
||||
binary.LittleEndian.PutUint32(request[4:] /*card.activeProto*/, 2)
|
||||
binary.LittleEndian.PutUint32(request[8:], 8)
|
||||
binary.LittleEndian.PutUint32(request[12:], uint32(len(adpu)))
|
||||
binary.LittleEndian.PutUint32(request[16:], 0)
|
||||
binary.LittleEndian.PutUint32(request[20:], 0)
|
||||
binary.LittleEndian.PutUint32(request[24:], 0x10000)
|
||||
binary.LittleEndian.PutUint32(request[28:], SCardSuccess)
|
||||
err := messageSendWithHeader(SCardTransmit, card.client.conn, request[:])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Add the ADPU payload after the transmit descriptor
|
||||
n, err := card.client.conn.Write(adpu)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if n != len(adpu) {
|
||||
return nil, nil, fmt.Errorf("Invalid number of bytes written: expected %d, got %d", len(adpu), n)
|
||||
}
|
||||
response := [TransmitRequestLength]byte{}
|
||||
total := 0
|
||||
for total < len(response) {
|
||||
n, err = card.client.conn.Read(response[total:])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
total += n
|
||||
}
|
||||
|
||||
code := binary.LittleEndian.Uint32(response[28:])
|
||||
if code != SCardSuccess {
|
||||
return nil, nil, fmt.Errorf("invalid return code: %x", code)
|
||||
}
|
||||
|
||||
// Recover the response data
|
||||
recvProto := binary.LittleEndian.Uint32(response[16:])
|
||||
recvLength := binary.LittleEndian.Uint32(response[20:])
|
||||
recv := &SCardIoRequest{proto: recvProto, length: recvLength}
|
||||
recvLength = binary.LittleEndian.Uint32(response[24:])
|
||||
recvData := make([]byte, recvLength)
|
||||
total = 0
|
||||
for uint32(total) < recvLength {
|
||||
n, err := card.client.conn.Read(recvData[total:])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
total += n
|
||||
}
|
||||
|
||||
return recvData, recv, nil
|
||||
}
|
||||
|
||||
// Disconnect tells the PCSC daemon that the client is no longer
|
||||
// interested in communicating with the card.
|
||||
func (card *Card) Disconnect(disposition uint32) error {
|
||||
data := [12]byte{}
|
||||
binary.LittleEndian.PutUint32(data[:], card.handle)
|
||||
binary.LittleEndian.PutUint32(data[4:], disposition)
|
||||
binary.LittleEndian.PutUint32(data[8:], SCardSuccess)
|
||||
err := messageSendWithHeader(SCardDisConnect, card.client.conn, data[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
total := 0
|
||||
for total < len(data) {
|
||||
n, err := card.client.conn.Read(data[total:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
total += n
|
||||
}
|
||||
code := binary.LittleEndian.Uint32(data[8:])
|
||||
if code != SCardSuccess {
|
||||
return fmt.Errorf("invalid return code: %x", code)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user