keycard-go/globalplatform/session.go

88 lines
2.2 KiB
Go
Raw Normal View History

2018-09-27 13:29:07 +00:00
package globalplatform
import (
"errors"
"fmt"
2019-03-01 17:44:07 +00:00
"github.com/status-im/keycard-go/apdu"
"github.com/status-im/keycard-go/globalplatform/crypto"
2018-09-27 13:29:07 +00:00
)
2019-03-06 12:39:24 +00:00
const supportedSCPVersion = 2
2018-10-05 14:40:32 +00:00
// Session is a struct containing the keys and challenges used in the current communication with a card.
2018-09-27 13:29:07 +00:00
type Session struct {
2019-03-06 09:43:37 +00:00
keys *SCP02Keys
2018-09-27 13:29:07 +00:00
cardChallenge []byte
2018-10-04 14:06:55 +00:00
hostChallenge []byte
2018-09-27 13:29:07 +00:00
}
var errBadCryptogram = errors.New("bad card cryptogram")
2018-10-05 14:40:32 +00:00
// NewSession returns a new session after validating the cryptogram received from the card.
2019-03-06 09:43:37 +00:00
func NewSession(cardKeys *SCP02Keys, resp *apdu.Response, hostChallenge []byte) (*Session, error) {
if resp.Sw == SwSecurityConditionNotSatisfied {
2018-09-27 13:29:07 +00:00
return nil, apdu.NewErrBadResponse(resp.Sw, "security condition not satisfied")
}
if resp.Sw == SwAuthenticationMethodBlocked {
2018-09-27 13:29:07 +00:00
return nil, apdu.NewErrBadResponse(resp.Sw, "authentication method blocked")
}
if len(resp.Data) != 28 {
return nil, apdu.NewErrBadResponse(resp.Sw, fmt.Sprintf("bad data length, expected 28, got %d", len(resp.Data)))
}
2019-03-06 12:39:24 +00:00
scpMajorVersion := resp.Data[11]
if scpMajorVersion != supportedSCPVersion {
return nil, fmt.Errorf("scp version %d not supported", scpMajorVersion)
}
2018-09-27 13:29:07 +00:00
cardChallenge := resp.Data[12:20]
cardCryptogram := resp.Data[20:28]
seq := resp.Data[12:14]
sessionEncKey, err := crypto.DeriveKey(cardKeys.Enc(), seq, crypto.DerivationPurposeEnc)
if err != nil {
return nil, err
}
sessionMacKey, err := crypto.DeriveKey(cardKeys.Enc(), seq, crypto.DerivationPurposeMac)
if err != nil {
return nil, err
}
2019-03-06 09:43:37 +00:00
sessionKeys := NewSCP02Keys(sessionEncKey, sessionMacKey)
2018-09-27 13:29:07 +00:00
verified, err := crypto.VerifyCryptogram(sessionKeys.Enc(), hostChallenge, cardChallenge, cardCryptogram)
if err != nil {
return nil, err
}
if !verified {
return nil, errBadCryptogram
}
s := &Session{
2019-03-06 09:43:37 +00:00
keys: sessionKeys,
2018-09-27 13:29:07 +00:00
cardChallenge: cardChallenge,
2018-10-04 14:06:55 +00:00
hostChallenge: hostChallenge,
2018-09-27 13:29:07 +00:00
}
return s, nil
}
2018-10-02 11:24:13 +00:00
2019-03-06 09:43:37 +00:00
// Keys return the current SCP02Keys.
func (s *Session) Keys() *SCP02Keys {
return s.keys
2018-10-02 11:24:13 +00:00
}
2018-10-05 14:40:32 +00:00
// CardChallenge returns the current card challenge.
2018-10-02 11:24:13 +00:00
func (s *Session) CardChallenge() []byte {
return s.cardChallenge
}
2018-10-04 14:06:55 +00:00
2018-10-05 14:40:32 +00:00
// HostChallenge returns the current host challenge.
2018-10-04 14:06:55 +00:00
func (s *Session) HostChallenge() []byte {
return s.hostChallenge
}