Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding Shared access to multiple processes #100

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
74 changes: 56 additions & 18 deletions piv/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,12 @@ func (yk *YubiKey) AttestationCertificate() (*x509.Certificate, error) {
//
// If the slot doesn't have a key, the returned error wraps ErrNotFound.
func (yk *YubiKey) Attest(slot Slot) (*x509.Certificate, error) {
cert, err := ykAttest(yk.tx, slot)
var cert *x509.Certificate
err := yk.withTx(func(tx *scTx) error {
var err error
cert, err = ykAttest(tx, slot)
return err
})
if err == nil {
return cert, nil
}
Expand Down Expand Up @@ -562,10 +567,17 @@ func (yk *YubiKey) Certificate(slot Slot) (*x509.Certificate, error) {
byte(slot.Object),
},
}
resp, err := yk.tx.Transmit(cmd)

var resp []byte
err := yk.withTx(func(tx *scTx) error {
var err error
resp, err = tx.Transmit(cmd)
return err
})
if err != nil {
return nil, fmt.Errorf("command failed: %w", err)
}

// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=85
obj, _, err := unmarshalASN1(resp, 1, 0x13) // tag 0x53
if err != nil {
Expand Down Expand Up @@ -609,10 +621,13 @@ func marshalASN1(tag byte, data []byte) []byte {
// certificate isn't required to use the associated key for signing or
// decryption.
func (yk *YubiKey) SetCertificate(key [24]byte, slot Slot, cert *x509.Certificate) error {
if err := ykAuthenticate(yk.tx, key, yk.rand); err != nil {
return fmt.Errorf("authenticating with management key: %w", err)
}
return ykStoreCertificate(yk.tx, slot, cert)
return yk.withTx(func(tx *scTx) error {
err := ykAuthenticate(tx, key, yk.rand)
if err != nil {
return fmt.Errorf("authenticating with management key: %w", err)
}
return ykStoreCertificate(tx, slot, cert)
})
}

func ykStoreCertificate(tx *scTx, slot Slot, cert *x509.Certificate) error {
Expand Down Expand Up @@ -663,10 +678,16 @@ type Key struct {
// GenerateKey generates an asymmetric key on the card, returning the key's
// public key.
func (yk *YubiKey) GenerateKey(key [24]byte, slot Slot, opts Key) (crypto.PublicKey, error) {
if err := ykAuthenticate(yk.tx, key, yk.rand); err != nil {
return nil, fmt.Errorf("authenticating with management key: %w", err)
}
return ykGenerateKey(yk.tx, slot, opts)
var pk crypto.PublicKey
err := yk.withTx(func(tx *scTx) error {
err := ykAuthenticate(tx, key, yk.rand)
if err != nil {
return fmt.Errorf("authenticating with management key: %w", err)
}
pk, err = ykGenerateKey(tx, slot, opts)
return err
})
return pk, err
}

func ykGenerateKey(tx *scTx, slot Slot, o Key) (crypto.PublicKey, error) {
Expand Down Expand Up @@ -764,7 +785,15 @@ func (k KeyAuth) authTx(yk *YubiKey, pp PINPolicy) error {
// PINPolicyAlways should always prompt a PIN even if the key says that
// login isn't needed.
// https://github.com/go-piv/piv-go/issues/49
if pp != PINPolicyAlways && !ykLoginNeeded(yk.tx) {

var flag bool

yk.withTx(func(tx *scTx) error {
rajnikant12345 marked this conversation as resolved.
Show resolved Hide resolved
flag = !ykLoginNeeded(tx)
return nil
})

if pp != PINPolicyAlways && flag {
return nil
}

Expand All @@ -779,14 +808,22 @@ func (k KeyAuth) authTx(yk *YubiKey, pp PINPolicy) error {
if pin == "" {
return fmt.Errorf("pin required but wasn't provided")
}
return ykLogin(yk.tx, pin)
return yk.withTx(func(tx *scTx) error {
return ykLogin(tx, pin)
})
}

func (k KeyAuth) do(yk *YubiKey, pp PINPolicy, f func(tx *scTx) ([]byte, error)) ([]byte, error) {
if err := k.authTx(yk, pp); err != nil {
return nil, err
}
return f(yk.tx)
var res []byte
err := yk.withTx(func(tx *scTx) error {
rajnikant12345 marked this conversation as resolved.
Show resolved Hide resolved
var err error
res, err = f(tx)
return err
})
return res, err
}

func pinPolicy(yk *YubiKey, slot Slot) (PINPolicy, error) {
Expand Down Expand Up @@ -931,11 +968,12 @@ func (yk *YubiKey) SetPrivateKeyInsecure(key [24]byte, slot Slot, private crypto
tags = append(tags, param...)
}

if err := ykAuthenticate(yk.tx, key, yk.rand); err != nil {
return fmt.Errorf("authenticating with management key: %w", err)
}

return ykImportKey(yk.tx, tags, slot, policy)
return yk.withTx(func(tx *scTx) error {
if err := ykAuthenticate(tx, key, yk.rand); err != nil {
return fmt.Errorf("authenticating with management key: %w", err)
}
return ykImportKey(tx, tags, slot, policy)
})
}

func ykImportKey(tx *scTx, tags []byte, slot Slot, o Key) error {
Expand Down
26 changes: 26 additions & 0 deletions piv/pcsc_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@

package piv

// #cgo darwin LDFLAGS: -framework PCSC
// #cgo linux pkg-config: libpcsclite
// #cgo freebsd CFLAGS: -I/usr/local/include/
// #cgo freebsd CFLAGS: -I/usr/local/include/PCSC
// #cgo freebsd LDFLAGS: -L/usr/local/lib/
// #cgo freebsd LDFLAGS: -lpcsclite
// #include <PCSC/winscard.h>
// #include <PCSC/wintypes.h>
import "C"

func scCheck(rc C.int) error {
Expand All @@ -36,3 +44,21 @@ func isRCNoReaders(rc C.int) bool {
// are available.
return false
}

func (c *scContext) Connect(reader string) (*scHandle, error) {
rajnikant12345 marked this conversation as resolved.
Show resolved Hide resolved
var (
handle C.SCARDHANDLE
activeProtocol C.DWORD
)
opt := C.SCARD_SHARE_EXCLUSIVE
if c.shared {
opt = C.SCARD_SHARE_SHARED
}
rc := C.SCardConnect(c.ctx, C.CString(reader),
C.uint(opt), C.SCARD_PROTOCOL_T1,
&handle, &activeProtocol)
if err := scCheck(rc); err != nil {
return nil, err
}
return &scHandle{handle}, nil
}
26 changes: 26 additions & 0 deletions piv/pcsc_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@

package piv

// #cgo darwin LDFLAGS: -framework PCSC
// #cgo linux pkg-config: libpcsclite
// #cgo freebsd CFLAGS: -I/usr/local/include/
// #cgo freebsd CFLAGS: -I/usr/local/include/PCSC
// #cgo freebsd LDFLAGS: -L/usr/local/lib/
// #cgo freebsd LDFLAGS: -lpcsclite
// #include <PCSC/winscard.h>
// #include <PCSC/wintypes.h>
import "C"

// Return codes for PCSC are different on different platforms (int vs. long).
Expand All @@ -28,3 +36,21 @@ func scCheck(rc C.long) error {
func isRCNoReaders(rc C.long) bool {
return C.ulong(rc) == 0x8010002E
}

func (c *scContext) Connect(reader string) (*scHandle, error) {
rajnikant12345 marked this conversation as resolved.
Show resolved Hide resolved
var (
handle C.SCARDHANDLE
activeProtocol C.DWORD
)
opt := C.SCARD_SHARE_EXCLUSIVE
if c.shared {
opt = C.SCARD_SHARE_SHARED
}
rc := C.SCardConnect(c.ctx, C.CString(reader),
C.ulong(opt), C.SCARD_PROTOCOL_T1,
&handle, &activeProtocol)
if err := scCheck(rc); err != nil {
return nil, err
}
return &scHandle{handle}, nil
}
2 changes: 1 addition & 1 deletion piv/pcsc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
)

func runContextTest(t *testing.T, f func(t *testing.T, c *scContext)) {
ctx, err := newSCContext()
ctx, err := newSCContext(true)
if err != nil {
t.Fatalf("creating context: %v", err)
}
Expand Down
17 changes: 11 additions & 6 deletions piv/pcsc_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,17 @@ import (
const rcSuccess = C.SCARD_S_SUCCESS

type scContext struct {
ctx C.SCARDCONTEXT
ctx C.SCARDCONTEXT
shared bool
}

func newSCContext() (*scContext, error) {
func newSCContext(shared bool) (*scContext, error) {
var ctx C.SCARDCONTEXT
rc := C.SCardEstablishContext(C.SCARD_SCOPE_SYSTEM, nil, nil, &ctx)
if err := scCheck(rc); err != nil {
return nil, err
}
return &scContext{ctx: ctx}, nil
return &scContext{ctx: ctx, shared: shared}, nil
}

func (c *scContext) Close() error {
Expand Down Expand Up @@ -87,20 +88,24 @@ func (c *scContext) ListReaders() ([]string, error) {
type scHandle struct {
h C.SCARDHANDLE
}

/*
rajnikant12345 marked this conversation as resolved.
Show resolved Hide resolved
func (c *scContext) Connect(reader string) (*scHandle, error) {
var (
handle C.SCARDHANDLE
activeProtocol C.DWORD
)
opt := C.SCARD_SHARE_EXCLUSIVE
if c.shared {
opt = C.SCARD_SHARE_SHARED
}
rc := C.SCardConnect(c.ctx, C.CString(reader),
C.SCARD_SHARE_EXCLUSIVE, C.SCARD_PROTOCOL_T1,
C.uint(opt), C.SCARD_PROTOCOL_T1,
&handle, &activeProtocol)
if err := scCheck(rc); err != nil {
return nil, err
}
return &scHandle{handle}, nil
}
}*/

func (h *scHandle) Close() error {
return scCheck(C.SCardDisconnect(h.h, C.SCARD_LEAVE_CARD))
Expand Down
15 changes: 11 additions & 4 deletions piv/pcsc_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package piv

import (
"C"
"fmt"
"syscall"
"unsafe"
Expand All @@ -35,6 +36,7 @@ var (
const (
scardScopeSystem = 2
scardShareExclusive = 1
scardShareShared = 2
scardLeaveCard = 0
scardProtocolT1 = 2
scardPCIT1 = 0
Expand All @@ -54,10 +56,11 @@ func isRCNoReaders(rc uintptr) bool {
}

type scContext struct {
ctx syscall.Handle
ctx syscall.Handle
shared bool
}

func newSCContext() (*scContext, error) {
func newSCContext(shared bool) (*scContext, error) {
var ctx syscall.Handle

r0, _, _ := procSCardEstablishContext.Call(
Expand All @@ -69,7 +72,7 @@ func newSCContext() (*scContext, error) {
if err := scCheck(r0); err != nil {
return nil, err
}
return &scContext{ctx: ctx}, nil
return &scContext{ctx: ctx, shared: shared}, nil
}

func (c *scContext) Close() error {
Expand Down Expand Up @@ -127,10 +130,14 @@ func (c *scContext) Connect(reader string) (*scHandle, error) {
handle syscall.Handle
activeProtocol uint16
)
opt := scardShareExclusive
if c.shared {
opt = scardShareShared
}
r0, _, _ := procSCardConnectW.Call(
uintptr(c.ctx),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(reader))),
scardShareExclusive,
C.DWORD(opt),
scardProtocolT1,
uintptr(unsafe.Pointer(&handle)),
uintptr(activeProtocol),
Expand Down
Loading