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"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ebfe/scard"
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
pcsc "github.com/gballet/go-libpcsclite"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scheme is the URI prefix for smartcard wallets.
|
// Scheme is the URI prefix for smartcard wallets.
|
||||||
@ -70,7 +70,7 @@ type smartcardPairing struct {
|
|||||||
type Hub struct {
|
type Hub struct {
|
||||||
scheme string // Protocol scheme prefixing account and wallet URLs.
|
scheme string // Protocol scheme prefixing account and wallet URLs.
|
||||||
|
|
||||||
context *scard.Context
|
context *pcsc.Client
|
||||||
datadir string
|
datadir string
|
||||||
pairings map[string]smartcardPairing
|
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.
|
// NewHub creates a new hardware wallet manager for smartcards.
|
||||||
func NewHub(scheme string, datadir string) (*Hub, error) {
|
func NewHub(scheme string, datadir string) (*Hub, error) {
|
||||||
context, err := scard.EstablishContext()
|
context, err := pcsc.EstablishContext(pcsc.ScopeSystem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -228,7 +228,7 @@ func (hub *Hub) refreshWallets() {
|
|||||||
delete(hub.wallets, reader)
|
delete(hub.wallets, reader)
|
||||||
}
|
}
|
||||||
// New card detected, try to connect to it
|
// 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 {
|
if err != nil {
|
||||||
log.Debug("Failed to open smart card", "reader", reader, "err", err)
|
log.Debug("Failed to open smart card", "reader", reader, "err", err)
|
||||||
continue
|
continue
|
||||||
@ -236,7 +236,7 @@ func (hub *Hub) refreshWallets() {
|
|||||||
wallet := NewWallet(hub, card)
|
wallet := NewWallet(hub, card)
|
||||||
if err = wallet.connect(); err != nil {
|
if err = wallet.connect(); err != nil {
|
||||||
log.Debug("Failed to connect to smart card", "reader", reader, "err", err)
|
log.Debug("Failed to connect to smart card", "reader", reader, "err", err)
|
||||||
card.Disconnect(scard.LeaveCard)
|
card.Disconnect(pcsc.LeaveCard)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Card connected, start tracking in amongs the wallets
|
// Card connected, start tracking in amongs the wallets
|
||||||
|
@ -25,9 +25,11 @@ import (
|
|||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ebfe/scard"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
pcsc "github.com/gballet/go-libpcsclite"
|
||||||
"github.com/wsddn/go-ecdh"
|
"github.com/wsddn/go-ecdh"
|
||||||
|
"golang.org/x/crypto/pbkdf2"
|
||||||
|
"golang.org/x/text/unicode/norm"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -42,22 +44,24 @@ const (
|
|||||||
insMutuallyAuthenticate = 0x11
|
insMutuallyAuthenticate = 0x11
|
||||||
insPair = 0x12
|
insPair = 0x12
|
||||||
insUnpair = 0x13
|
insUnpair = 0x13
|
||||||
|
|
||||||
|
pairingSalt = "Keycard Pairing Password Salt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SecureChannelSession enables secure communication with a hardware wallet.
|
// SecureChannelSession enables secure communication with a hardware wallet.
|
||||||
type SecureChannelSession struct {
|
type SecureChannelSession struct {
|
||||||
card *scard.Card // A handle to the smartcard for communication
|
card *pcsc.Card // A handle to the smartcard for communication
|
||||||
secret []byte // A shared secret generated from our ECDSA keys
|
secret []byte // A shared secret generated from our ECDSA keys
|
||||||
publicKey []byte // Our own ephemeral public key
|
publicKey []byte // Our own ephemeral public key
|
||||||
PairingKey []byte // A permanent shared secret for a pairing, if present
|
PairingKey []byte // A permanent shared secret for a pairing, if present
|
||||||
sessionEncKey []byte // The current session encryption key
|
sessionEncKey []byte // The current session encryption key
|
||||||
sessionMacKey []byte // The current session MAC key
|
sessionMacKey []byte // The current session MAC key
|
||||||
iv []byte // The current IV
|
iv []byte // The current IV
|
||||||
PairingIndex uint8 // The pairing index
|
PairingIndex uint8 // The pairing index
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSecureChannelSession creates a new secure channel for the given card and public key.
|
// 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
|
// Generate an ECDSA keypair for ourselves
|
||||||
gen := ecdh.NewEllipticECDH(crypto.S256())
|
gen := ecdh.NewEllipticECDH(crypto.S256())
|
||||||
private, public, err := gen.GenerateKey(rand.Reader)
|
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.
|
// Pair establishes a new pairing with the smartcard.
|
||||||
func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
|
func (s *SecureChannelSession) Pair(pairingPassword []byte) error {
|
||||||
secretHash := sha256.Sum256(sharedSecret)
|
secretHash := pbkdf2.Key(norm.NFKD.Bytes([]byte(pairingPassword)), norm.NFKD.Bytes([]byte(pairingSalt)), 50000, 32, sha256.New)
|
||||||
|
|
||||||
challenge := make([]byte, 32)
|
challenge := make([]byte, 32)
|
||||||
if _, err := rand.Read(challenge); err != nil {
|
if _, err := rand.Read(challenge); err != nil {
|
||||||
@ -102,10 +106,10 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
|
|||||||
|
|
||||||
expectedCryptogram := md.Sum(nil)
|
expectedCryptogram := md.Sum(nil)
|
||||||
cardCryptogram := response.Data[:32]
|
cardCryptogram := response.Data[:32]
|
||||||
cardChallenge := response.Data[32:]
|
cardChallenge := response.Data[32:64]
|
||||||
|
|
||||||
if !bytes.Equal(expectedCryptogram, cardCryptogram) {
|
if !bytes.Equal(expectedCryptogram, cardCryptogram) {
|
||||||
return fmt.Errorf("Invalid card cryptogram")
|
return fmt.Errorf("Invalid card cryptogram %v != %v", expectedCryptogram, cardCryptogram)
|
||||||
}
|
}
|
||||||
|
|
||||||
md.Reset()
|
md.Reset()
|
||||||
|
@ -32,7 +32,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ebfe/scard"
|
|
||||||
ethereum "github.com/ethereum/go-ethereum"
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -40,12 +39,13 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"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
|
// ErrPairingPasswordNeeded is returned if opening the smart card requires pairing with a pairing
|
||||||
// code. In this case, the calling application should request user input to enter
|
// password. In this case, the calling application should request user input to enter
|
||||||
// the PUK and send it back.
|
// the pairing password and send it back.
|
||||||
var ErrPUKNeeded = errors.New("smartcard: puk needed")
|
var ErrPairingPasswordNeeded = errors.New("smartcard: pairing password needed")
|
||||||
|
|
||||||
// ErrPINNeeded is returned if opening the smart card requires a PIN code. In
|
// 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
|
// 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 ErrPubkeyMismatch = errors.New("smartcard: recovered public key mismatch")
|
||||||
|
|
||||||
var (
|
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"))
|
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.
|
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!)
|
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
|
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.
|
card *pcsc.Card // A handle to the smartcard interface for the wallet.
|
||||||
session *Session // The secure communication session with the card
|
session *Session // The secure communication session with the card
|
||||||
log log.Logger // Contextual logger to tag the base with its id
|
log log.Logger // Contextual logger to tag the base with its id
|
||||||
|
|
||||||
deriveNextPath accounts.DerivationPath // Next derivation path for account auto-discovery
|
deriveNextPath accounts.DerivationPath // Next derivation path for account auto-discovery
|
||||||
deriveNextAddr common.Address // Next derived account address for 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.
|
// 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{
|
wallet := &Wallet{
|
||||||
Hub: hub,
|
Hub: hub,
|
||||||
card: card,
|
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.
|
// 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,
|
// 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.
|
// 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()
|
data, err := command.serialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
responseData, err := card.Transmit(data)
|
responseData, _, err := card.Transmit(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -349,7 +350,7 @@ func (w *Wallet) Open(passphrase string) error {
|
|||||||
} else {
|
} else {
|
||||||
// If no passphrase was supplied, request the PUK from the user
|
// If no passphrase was supplied, request the PUK from the user
|
||||||
if passphrase == "" {
|
if passphrase == "" {
|
||||||
return ErrPUKNeeded
|
return ErrPairingPasswordNeeded
|
||||||
}
|
}
|
||||||
// Attempt to pair the smart card with the user supplied PUK
|
// Attempt to pair the smart card with the user supplied PUK
|
||||||
if err := w.pair([]byte(passphrase)); err != nil {
|
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.
|
// release releases resources associated with the channel.
|
||||||
func (s *Session) release() error {
|
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.
|
// 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())
|
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
|
// 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())
|
throwJSException(err.Error())
|
||||||
} else {
|
} else {
|
||||||
passwd, _ = otto.ToValue(input)
|
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",
|
"revision": "ca190fb6ffbc076ff49197b7168a760f30182d2e",
|
||||||
"revisionTime": "2018-04-18T12:24:29Z"
|
"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=",
|
"checksumSHA1": "gxV/cPPLkByTdY8y172t7v4qcZA=",
|
||||||
"path": "github.com/go-ole/go-ole",
|
"path": "github.com/go-ole/go-ole",
|
||||||
|
Loading…
Reference in New Issue
Block a user