mirror of https://github.com/ethereum/go-ethereum
Instead, use a go library that communicates with pcscd over a socket. Also update the changes introduced by @gravityblast since this PR's inceptionpull/19273/head
parent
ae82c58631
commit
5617dca1c9
@ -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. |
|
@ -1,14 +0,0 @@ |
|||||||
scard |
|
||||||
===== |
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/ebfe/scard?status.svg)](https://godoc.org/github.com/ebfe/scard) |
|
||||||
|
|
||||||
Go bindings to the PC/SC API. |
|
||||||
|
|
||||||
## Installation |
|
||||||
|
|
||||||
go get github.com/ebfe/scard |
|
||||||
|
|
||||||
## Bugs |
|
||||||
|
|
||||||
- Memory layouts/GC needs a thorough review. |
|
@ -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 |
|
||||||
} |
|
@ -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]) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -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]) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -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) |
|
||||||
} |
|
@ -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 |
|
||||||
) |
|
@ -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. |
@ -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. |
@ -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 */ |
||||||
|
) |
@ -0,0 +1 @@ |
|||||||
|
module github.com/gballet/go-libpcsclite |
@ -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) |
||||||
|
} |
@ -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 |
||||||
|
} |
Loading…
Reference in new issue