|
|
@ -71,7 +71,7 @@ func NewSecureChannelSession(card *pcsc.Card, keyData []byte) (*SecureChannelSes |
|
|
|
|
|
|
|
|
|
|
|
cardPublic, ok := gen.Unmarshal(keyData) |
|
|
|
cardPublic, ok := gen.Unmarshal(keyData) |
|
|
|
if !ok { |
|
|
|
if !ok { |
|
|
|
return nil, fmt.Errorf("Could not unmarshal public key from card") |
|
|
|
return nil, fmt.Errorf("could not unmarshal public key from card") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
secret, err := gen.GenerateSharedSecret(private, cardPublic) |
|
|
|
secret, err := gen.GenerateSharedSecret(private, cardPublic) |
|
|
@ -109,7 +109,7 @@ func (s *SecureChannelSession) Pair(pairingPassword []byte) error { |
|
|
|
cardChallenge := response.Data[32:64] |
|
|
|
cardChallenge := response.Data[32:64] |
|
|
|
|
|
|
|
|
|
|
|
if !bytes.Equal(expectedCryptogram, cardCryptogram) { |
|
|
|
if !bytes.Equal(expectedCryptogram, cardCryptogram) { |
|
|
|
return fmt.Errorf("Invalid card cryptogram %v != %v", expectedCryptogram, cardCryptogram) |
|
|
|
return fmt.Errorf("invalid card cryptogram %v != %v", expectedCryptogram, cardCryptogram) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
md.Reset() |
|
|
|
md.Reset() |
|
|
@ -132,7 +132,7 @@ func (s *SecureChannelSession) Pair(pairingPassword []byte) error { |
|
|
|
// Unpair disestablishes an existing pairing.
|
|
|
|
// Unpair disestablishes an existing pairing.
|
|
|
|
func (s *SecureChannelSession) Unpair() error { |
|
|
|
func (s *SecureChannelSession) Unpair() error { |
|
|
|
if s.PairingKey == nil { |
|
|
|
if s.PairingKey == nil { |
|
|
|
return fmt.Errorf("Cannot unpair: not paired") |
|
|
|
return fmt.Errorf("cannot unpair: not paired") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_, err := s.transmitEncrypted(claSCWallet, insUnpair, s.PairingIndex, 0, []byte{}) |
|
|
|
_, err := s.transmitEncrypted(claSCWallet, insUnpair, s.PairingIndex, 0, []byte{}) |
|
|
@ -148,7 +148,7 @@ func (s *SecureChannelSession) Unpair() error { |
|
|
|
// Open initializes the secure channel.
|
|
|
|
// Open initializes the secure channel.
|
|
|
|
func (s *SecureChannelSession) Open() error { |
|
|
|
func (s *SecureChannelSession) Open() error { |
|
|
|
if s.iv != nil { |
|
|
|
if s.iv != nil { |
|
|
|
return fmt.Errorf("Session already opened") |
|
|
|
return fmt.Errorf("session already opened") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
response, err := s.open() |
|
|
|
response, err := s.open() |
|
|
@ -185,11 +185,11 @@ func (s *SecureChannelSession) mutuallyAuthenticate() error { |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
if response.Sw1 != 0x90 || response.Sw2 != 0x00 { |
|
|
|
if response.Sw1 != 0x90 || response.Sw2 != 0x00 { |
|
|
|
return fmt.Errorf("Got unexpected response from MUTUALLY_AUTHENTICATE: 0x%x%x", response.Sw1, response.Sw2) |
|
|
|
return fmt.Errorf("got unexpected response from MUTUALLY_AUTHENTICATE: 0x%x%x", response.Sw1, response.Sw2) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if len(response.Data) != scSecretLength { |
|
|
|
if len(response.Data) != scSecretLength { |
|
|
|
return fmt.Errorf("Response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d", len(response.Data), scSecretLength) |
|
|
|
return fmt.Errorf("response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d", len(response.Data), scSecretLength) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
return nil |
|
|
@ -222,7 +222,7 @@ func (s *SecureChannelSession) pair(p1 uint8, data []byte) (*responseAPDU, error |
|
|
|
// transmitEncrypted sends an encrypted message, and decrypts and returns the response.
|
|
|
|
// transmitEncrypted sends an encrypted message, and decrypts and returns the response.
|
|
|
|
func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []byte) (*responseAPDU, error) { |
|
|
|
func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []byte) (*responseAPDU, error) { |
|
|
|
if s.iv == nil { |
|
|
|
if s.iv == nil { |
|
|
|
return nil, fmt.Errorf("Channel not open") |
|
|
|
return nil, fmt.Errorf("channel not open") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
data, err := s.encryptAPDU(data) |
|
|
|
data, err := s.encryptAPDU(data) |
|
|
@ -261,14 +261,14 @@ func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []b |
|
|
|
return nil, err |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
} |
|
|
|
if !bytes.Equal(s.iv, rmac) { |
|
|
|
if !bytes.Equal(s.iv, rmac) { |
|
|
|
return nil, fmt.Errorf("Invalid MAC in response") |
|
|
|
return nil, fmt.Errorf("invalid MAC in response") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
rapdu := &responseAPDU{} |
|
|
|
rapdu := &responseAPDU{} |
|
|
|
rapdu.deserialize(plainData) |
|
|
|
rapdu.deserialize(plainData) |
|
|
|
|
|
|
|
|
|
|
|
if rapdu.Sw1 != sw1Ok { |
|
|
|
if rapdu.Sw1 != sw1Ok { |
|
|
|
return nil, fmt.Errorf("Unexpected response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", cla, ins, rapdu.Sw1, rapdu.Sw2) |
|
|
|
return nil, fmt.Errorf("unexpected response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", cla, ins, rapdu.Sw1, rapdu.Sw2) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return rapdu, nil |
|
|
|
return rapdu, nil |
|
|
@ -277,7 +277,7 @@ func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []b |
|
|
|
// encryptAPDU is an internal method that serializes and encrypts an APDU.
|
|
|
|
// encryptAPDU is an internal method that serializes and encrypts an APDU.
|
|
|
|
func (s *SecureChannelSession) encryptAPDU(data []byte) ([]byte, error) { |
|
|
|
func (s *SecureChannelSession) encryptAPDU(data []byte) ([]byte, error) { |
|
|
|
if len(data) > maxPayloadSize { |
|
|
|
if len(data) > maxPayloadSize { |
|
|
|
return nil, fmt.Errorf("Payload of %d bytes exceeds maximum of %d", len(data), maxPayloadSize) |
|
|
|
return nil, fmt.Errorf("payload of %d bytes exceeds maximum of %d", len(data), maxPayloadSize) |
|
|
|
} |
|
|
|
} |
|
|
|
data = pad(data, 0x80) |
|
|
|
data = pad(data, 0x80) |
|
|
|
|
|
|
|
|
|
|
@ -323,10 +323,10 @@ func unpad(data []byte, terminator byte) ([]byte, error) { |
|
|
|
case terminator: |
|
|
|
case terminator: |
|
|
|
return data[:len(data)-i], nil |
|
|
|
return data[:len(data)-i], nil |
|
|
|
default: |
|
|
|
default: |
|
|
|
return nil, fmt.Errorf("Expected end of padding, got %d", data[len(data)-i]) |
|
|
|
return nil, fmt.Errorf("expected end of padding, got %d", data[len(data)-i]) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return nil, fmt.Errorf("Expected end of padding, got 0") |
|
|
|
return nil, fmt.Errorf("expected end of padding, got 0") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// updateIV is an internal method that updates the initialization vector after
|
|
|
|
// updateIV is an internal method that updates the initialization vector after
|
|
|
|