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,11 +44,13 @@ 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
 | ||||||
| @ -57,7 +61,7 @@ type SecureChannelSession struct { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // 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")) | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -109,7 +110,7 @@ type Wallet struct { | |||||||
| 	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
 | ||||||
| 
 | 
 | ||||||
| @ -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 |  | ||||||
| ===== |  | ||||||
| 
 |  | ||||||
| [](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