Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 550b517

Browse files
committedOct 8, 2023
pcsc: Replace custom code with github/com/ebfe/scard
This uses the ebfe/scard package to replace custom code for interfacing with the PIV token on various platforms.
1 parent 8c3a0ff commit 550b517

15 files changed

+70
-837
lines changed
 

‎go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/go-piv/piv-go
22

33
go 1.16
4+
5+
require github.com/ebfe/scard v0.0.0-20230420082256-7db3f9b7c8a7

‎go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/ebfe/scard v0.0.0-20230420082256-7db3f9b7c8a7 h1:HYAhfGa9dEemCZgGZWL5AvVsctBCsHxl2CI0HUXzHQE=
2+
github.com/ebfe/scard v0.0.0-20230420082256-7db3f9b7c8a7/go.mod h1:BkYEeWL6FbT4Ek+TcOBnPzEKnL7kOq2g19tTQXkorHY=

‎piv/pcsc.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,9 @@ package piv
1717
import (
1818
"errors"
1919
"fmt"
20-
)
21-
22-
type scErr struct {
23-
// rc holds the return code for a given call.
24-
rc int64
25-
}
2620

27-
func (e *scErr) Error() string {
28-
if msg, ok := pcscErrMsgs[e.rc]; ok {
29-
return msg
30-
}
31-
return fmt.Sprintf("unknown pcsc return code 0x%08x", e.rc)
32-
}
21+
"github.com/ebfe/scard"
22+
)
3323

3424
// AuthErr is an error indicating an authentication error occurred (wrong PIN or blocked).
3525
type AuthErr struct {
@@ -134,6 +124,42 @@ type apdu struct {
134124
data []byte
135125
}
136126

127+
type scTx struct {
128+
*scard.Card
129+
}
130+
131+
func newTx(h *scard.Card) (*scTx, error) {
132+
if err := h.BeginTransaction(); err != nil {
133+
return nil, err
134+
}
135+
136+
return &scTx{
137+
Card: h,
138+
}, nil
139+
}
140+
141+
func (t *scTx) Close() error {
142+
return t.Card.EndTransaction(scard.LeaveCard)
143+
}
144+
145+
func (t *scTx) transmit(req []byte) (more bool, b []byte, err error) {
146+
resp, err := t.Card.Transmit(req)
147+
if err != nil {
148+
return false, nil, fmt.Errorf("transmitting request: %w", err)
149+
} else if len(resp) < 2 {
150+
return false, nil, fmt.Errorf("scard response too short: %d", len(resp))
151+
}
152+
sw1 := resp[len(resp)-2]
153+
sw2 := resp[len(resp)-1]
154+
if sw1 == 0x90 && sw2 == 0x00 {
155+
return false, resp[:len(resp)-2], nil
156+
}
157+
if sw1 == 0x61 {
158+
return true, resp[:len(resp)-2], nil
159+
}
160+
return false, nil, &apduErr{sw1, sw2}
161+
}
162+
137163
func (t *scTx) Transmit(d apdu) ([]byte, error) {
138164
data := d.data
139165
var resp []byte

‎piv/pcsc_darwin.go

Lines changed: 0 additions & 38 deletions
This file was deleted.

‎piv/pcsc_errors

Lines changed: 0 additions & 179 deletions
This file was deleted.

‎piv/pcsc_errors.go

Lines changed: 0 additions & 82 deletions
This file was deleted.

‎piv/pcsc_errors.py

Lines changed: 0 additions & 59 deletions
This file was deleted.

‎piv/pcsc_freebsd.go

Lines changed: 0 additions & 30 deletions
This file was deleted.

‎piv/pcsc_linux.go

Lines changed: 0 additions & 30 deletions
This file was deleted.

‎piv/pcsc_openbsd.go

Lines changed: 0 additions & 30 deletions
This file was deleted.

‎piv/pcsc_test.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,39 @@ import (
1818
"errors"
1919
"strings"
2020
"testing"
21+
22+
"github.com/ebfe/scard"
2123
)
2224

23-
func runContextTest(t *testing.T, f func(t *testing.T, c *scContext)) {
24-
ctx, err := newSCContext()
25+
func runContextTest(t *testing.T, f func(t *testing.T, c *scard.Context)) {
26+
ctx, err := scard.EstablishContext()
2527
if err != nil {
2628
t.Fatalf("creating context: %v", err)
2729
}
2830
defer func() {
29-
if err := ctx.Close(); err != nil {
31+
if err := ctx.Release(); err != nil {
3032
t.Errorf("closing context: %v", err)
3133
}
3234
}()
3335
f(t, ctx)
3436
}
3537

3638
func TestContextClose(t *testing.T) {
37-
runContextTest(t, func(t *testing.T, c *scContext) {})
39+
runContextTest(t, func(t *testing.T, c *scard.Context) {})
3840
}
3941

4042
func TestContextListReaders(t *testing.T) {
4143
runContextTest(t, testContextListReaders)
4244
}
4345

44-
func testContextListReaders(t *testing.T, c *scContext) {
46+
func testContextListReaders(t *testing.T, c *scard.Context) {
4547
if _, err := c.ListReaders(); err != nil {
4648
t.Errorf("listing readers: %v", err)
4749
}
4850
}
4951

50-
func runHandleTest(t *testing.T, f func(t *testing.T, h *scHandle)) {
51-
runContextTest(t, func(t *testing.T, c *scContext) {
52+
func runHandleTest(t *testing.T, f func(t *testing.T, h *scard.Card)) {
53+
runContextTest(t, func(t *testing.T, c *scard.Context) {
5254
readers, err := c.ListReaders()
5355
if err != nil {
5456
t.Fatalf("listing smartcard readers: %v", err)
@@ -63,12 +65,12 @@ func runHandleTest(t *testing.T, f func(t *testing.T, h *scHandle)) {
6365
if reader == "" {
6466
t.Skip("could not find yubikey, skipping testing")
6567
}
66-
h, err := c.Connect(reader)
68+
h, err := c.Connect(reader, scard.ShareExclusive, scard.ProtocolT1)
6769
if err != nil {
6870
t.Fatalf("connecting to %s: %v", reader, err)
6971
}
7072
defer func() {
71-
if err := h.Close(); err != nil {
73+
if err := h.Disconnect(scard.LeaveCard); err != nil {
7274
t.Errorf("disconnecting from handle: %v", err)
7375
}
7476
}()
@@ -77,12 +79,12 @@ func runHandleTest(t *testing.T, f func(t *testing.T, h *scHandle)) {
7779
}
7880

7981
func TestHandle(t *testing.T) {
80-
runHandleTest(t, func(t *testing.T, h *scHandle) {})
82+
runHandleTest(t, func(t *testing.T, h *scard.Card) {})
8183
}
8284

8385
func TestTransaction(t *testing.T) {
84-
runHandleTest(t, func(t *testing.T, h *scHandle) {
85-
tx, err := h.Begin()
86+
runHandleTest(t, func(t *testing.T, h *scard.Card) {
87+
tx, err := newTx(h)
8688
if err != nil {
8789
t.Fatalf("beginning transaction: %v", err)
8890
}

‎piv/pcsc_unix.go

Lines changed: 0 additions & 152 deletions
This file was deleted.

‎piv/pcsc_windows.go

Lines changed: 0 additions & 203 deletions
This file was deleted.

‎piv/piv.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"fmt"
2525
"io"
2626
"math/big"
27+
28+
"github.com/ebfe/scard"
2729
)
2830

2931
var (
@@ -101,8 +103,8 @@ const (
101103
//
102104
// To release the connection, call the Close method.
103105
type YubiKey struct {
104-
ctx *scContext
105-
h *scHandle
106+
ctx *scard.Context
107+
h *scard.Card
106108
tx *scTx
107109

108110
rand io.Reader
@@ -117,8 +119,8 @@ type YubiKey struct {
117119

118120
// Close releases the connection to the smart card.
119121
func (yk *YubiKey) Close() error {
120-
err1 := yk.h.Close()
121-
err2 := yk.ctx.Close()
122+
err1 := yk.h.Disconnect(scard.LeaveCard)
123+
err2 := yk.ctx.Release()
122124
if err1 == nil {
123125
return err2
124126
}
@@ -141,26 +143,26 @@ type client struct {
141143
}
142144

143145
func (c *client) Cards() ([]string, error) {
144-
ctx, err := newSCContext()
146+
ctx, err := scard.EstablishContext()
145147
if err != nil {
146148
return nil, fmt.Errorf("connecting to pcsc: %w", err)
147149
}
148-
defer ctx.Close()
150+
defer ctx.Release()
149151
return ctx.ListReaders()
150152
}
151153

152154
func (c *client) Open(card string) (*YubiKey, error) {
153-
ctx, err := newSCContext()
155+
ctx, err := scard.EstablishContext()
154156
if err != nil {
155157
return nil, fmt.Errorf("connecting to smart card daemon: %w", err)
156158
}
157159

158-
h, err := ctx.Connect(card)
160+
h, err := ctx.Connect(card, scard.ShareExclusive, scard.ProtocolT1)
159161
if err != nil {
160-
ctx.Close()
162+
ctx.Release()
161163
return nil, fmt.Errorf("connecting to smart card: %w", err)
162164
}
163-
tx, err := h.Begin()
165+
tx, err := newTx(h)
164166
if err != nil {
165167
return nil, fmt.Errorf("beginning smart card transaction: %w", err)
166168
}

‎piv/piv_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"math/bits"
2525
"strings"
2626
"testing"
27+
28+
"github.com/ebfe/scard"
2729
)
2830

2931
// canModifyYubiKey indicates whether the test running has constented to

0 commit comments

Comments
 (0)
Please sign in to comment.