accounts, internal: Changes in response to review

This commit is contained in:
Nick Johnson
2018-02-22 13:27:41 +00:00
committed by Guillaume Ballet
parent f7027dd68c
commit 78375608a4
6 changed files with 137 additions and 118 deletions

View File

@ -32,15 +32,15 @@ import (
)
const (
MAX_PAYLOAD_SIZE = 223
PAIR_P1_FIRST_STEP = 0
PAIR_P1_LAST_STEP = 1
maxPayloadSize = 223
pairP1FirstStep = 0
pairP1LastStep = 1
SC_SECRET_LENGTH = 32
SC_BLOCK_SIZE = 16
scSecretLength = 32
scBlockSize = 16
)
// SecureChannelSession enables secure communication with a hardware wallet
// SecureChannelSession enables secure communication with a hardware wallet.
type SecureChannelSession struct {
card *scard.Card // A handle to the smartcard for communication
secret []byte // A shared secret generated from our ECDSA keys
@ -52,7 +52,7 @@ type SecureChannelSession struct {
PairingIndex uint8 // The pairing index
}
// NewSecureChannelSession creates a new secure channel for the given card and public key
// NewSecureChannelSession creates a new secure channel for the given card and public key.
func NewSecureChannelSession(card *scard.Card, keyData []byte) (*SecureChannelSession, error) {
// Generate an ECDSA keypair for ourselves
gen := ecdh.NewEllipticECDH(crypto.S256())
@ -78,7 +78,7 @@ func NewSecureChannelSession(card *scard.Card, keyData []byte) (*SecureChannelSe
}, nil
}
// Pair establishes a new pairing with the smartcard
// Pair establishes a new pairing with the smartcard.
func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
secretHash := sha256.Sum256(sharedSecret)
@ -87,7 +87,7 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
return err
}
response, err := s.pair(PAIR_P1_FIRST_STEP, challenge)
response, err := s.pair(pairP1FirstStep, challenge)
if err != nil {
return err
}
@ -107,7 +107,7 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
md.Reset()
md.Write(secretHash[:])
md.Write(cardChallenge)
response, err = s.pair(PAIR_P1_LAST_STEP, md.Sum(nil))
response, err = s.pair(pairP1LastStep, md.Sum(nil))
if err != nil {
return err
}
@ -121,13 +121,13 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
return nil
}
// Unpair disestablishes an existing pairing
// Unpair disestablishes an existing pairing.
func (s *SecureChannelSession) Unpair() error {
if s.PairingKey == nil {
return fmt.Errorf("Cannot unpair: not paired")
}
_, err := s.TransmitEncrypted(CLA_SCWALLET, INS_UNPAIR, s.PairingIndex, 0, []byte{})
_, err := s.TransmitEncrypted(claSCWallet, insUnpair, s.PairingIndex, 0, []byte{})
if err != nil {
return err
}
@ -137,7 +137,7 @@ func (s *SecureChannelSession) Unpair() error {
return nil
}
// Open initializes the secure channel
// Open initializes the secure channel.
func (s *SecureChannelSession) Open() error {
if s.iv != nil {
return fmt.Errorf("Session already opened")
@ -153,13 +153,13 @@ func (s *SecureChannelSession) Open() error {
md := sha512.New()
md.Write(s.secret)
md.Write(s.PairingKey)
md.Write(response.Data[:SC_SECRET_LENGTH])
md.Write(response.Data[:scSecretLength])
keyData := md.Sum(nil)
s.sessionEncKey = keyData[:SC_SECRET_LENGTH]
s.sessionMacKey = keyData[SC_SECRET_LENGTH : SC_SECRET_LENGTH*2]
s.sessionEncKey = keyData[:scSecretLength]
s.sessionMacKey = keyData[scSecretLength : scSecretLength*2]
// The IV is the last bytes returned from the Open APDU.
s.iv = response.Data[SC_SECRET_LENGTH:]
s.iv = response.Data[scSecretLength:]
if err := s.mutuallyAuthenticate(); err != nil {
return err
@ -171,12 +171,12 @@ func (s *SecureChannelSession) Open() error {
// mutuallyAuthenticate is an internal method to authenticate both ends of the
// connection.
func (s *SecureChannelSession) mutuallyAuthenticate() error {
data := make([]byte, SC_SECRET_LENGTH)
data := make([]byte, scSecretLength)
if _, err := rand.Read(data); err != nil {
return err
}
response, err := s.TransmitEncrypted(CLA_SCWALLET, INS_MUTUALLY_AUTHENTICATE, 0, 0, data)
response, err := s.TransmitEncrypted(claSCWallet, insMutuallyAuthenticate, 0, 0, data)
if err != nil {
return err
}
@ -184,18 +184,18 @@ func (s *SecureChannelSession) mutuallyAuthenticate() error {
return fmt.Errorf("Got unexpected response from MUTUALLY_AUTHENTICATE: 0x%x%x", response.Sw1, response.Sw2)
}
if len(response.Data) != SC_SECRET_LENGTH {
return fmt.Errorf("Response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d", len(response.Data), SC_SECRET_LENGTH)
if len(response.Data) != scSecretLength {
return fmt.Errorf("Response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d", len(response.Data), scSecretLength)
}
return nil
}
// open is an internal method that sends an open APDU
// open is an internal method that sends an open APDU.
func (s *SecureChannelSession) open() (*ResponseAPDU, error) {
return transmit(s.card, &CommandAPDU{
Cla: CLA_SCWALLET,
Ins: INS_OPEN_SECURE_CHANNEL,
Cla: claSCWallet,
Ins: insOpenSecureChannel,
P1: s.PairingIndex,
P2: 0,
Data: s.publicKey,
@ -203,11 +203,11 @@ func (s *SecureChannelSession) open() (*ResponseAPDU, error) {
})
}
// pair is an internal method that sends a pair APDU
// pair is an internal method that sends a pair APDU.
func (s *SecureChannelSession) pair(p1 uint8, data []byte) (*ResponseAPDU, error) {
return transmit(s.card, &CommandAPDU{
Cla: CLA_SCWALLET,
Ins: INS_PAIR,
Cla: claSCWallet,
Ins: insPair,
P1: p1,
P2: 0,
Data: data,
@ -215,7 +215,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) {
if s.iv == nil {
return nil, fmt.Errorf("Channel not open")
@ -225,7 +225,7 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b
if err != nil {
return nil, err
}
meta := []byte{cla, ins, p1, p2, byte(len(data) + SC_BLOCK_SIZE), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
meta := []byte{cla, ins, p1, p2, byte(len(data) + scBlockSize), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
if err = s.updateIV(meta, data); err != nil {
return nil, err
}
@ -263,17 +263,17 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b
rapdu := &ResponseAPDU{}
rapdu.deserialize(plainData)
if rapdu.Sw1 != SW1_OK {
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 rapdu, nil
}
// 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) {
if len(data) > MAX_PAYLOAD_SIZE {
return nil, fmt.Errorf("Payload of %d bytes exceeds maximum of %d", len(data), MAX_PAYLOAD_SIZE)
if len(data) > maxPayloadSize {
return nil, fmt.Errorf("Payload of %d bytes exceeds maximum of %d", len(data), maxPayloadSize)
}
data = pad(data, 0x80)
@ -288,7 +288,7 @@ func (s *SecureChannelSession) encryptAPDU(data []byte) ([]byte, error) {
return ret, nil
}
// pad applies message padding to a 16 byte boundary
// pad applies message padding to a 16 byte boundary.
func pad(data []byte, terminator byte) []byte {
padded := make([]byte, (len(data)/16+1)*16)
copy(padded, data)
@ -296,7 +296,7 @@ func pad(data []byte, terminator byte) []byte {
return padded
}
// decryptAPDU is an internal method that decrypts and deserializes an APDU
// decryptAPDU is an internal method that decrypts and deserializes an APDU.
func (s *SecureChannelSession) decryptAPDU(data []byte) ([]byte, error) {
a, err := aes.NewCipher(s.sessionEncKey)
if err != nil {
@ -310,7 +310,7 @@ func (s *SecureChannelSession) decryptAPDU(data []byte) ([]byte, error) {
return unpad(ret, 0x80)
}
// unpad strips padding from a message
// unpad strips padding from a message.
func unpad(data []byte, terminator byte) ([]byte, error) {
for i := 1; i <= 16; i++ {
switch data[len(data)-i] {