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