2018-09-27 13:29:07 +00:00
|
|
|
package globalplatform
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/status-im/status-go/smartcard/apdu"
|
|
|
|
"github.com/status-im/status-go/smartcard/globalplatform/crypto"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Session struct {
|
|
|
|
keyProvider *KeyProvider
|
|
|
|
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")
|
|
|
|
|
|
|
|
func NewSession(cardKeys *KeyProvider, resp *apdu.Response, hostChallenge []byte) (*Session, error) {
|
2018-10-02 14:52:50 +00:00
|
|
|
if resp.Sw == SwSecurityConditionNotSatisfied {
|
2018-09-27 13:29:07 +00:00
|
|
|
return nil, apdu.NewErrBadResponse(resp.Sw, "security condition not satisfied")
|
|
|
|
}
|
|
|
|
|
2018-10-02 14:52:50 +00:00
|
|
|
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)))
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
sessionKeys := NewKeyProvider(sessionEncKey, sessionMacKey)
|
|
|
|
verified, err := crypto.VerifyCryptogram(sessionKeys.Enc(), hostChallenge, cardChallenge, cardCryptogram)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !verified {
|
|
|
|
return nil, errBadCryptogram
|
|
|
|
}
|
|
|
|
|
|
|
|
s := &Session{
|
|
|
|
keyProvider: sessionKeys,
|
|
|
|
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
|
|
|
|
|
|
|
func (s *Session) KeyProvider() *KeyProvider {
|
|
|
|
return s.keyProvider
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) CardChallenge() []byte {
|
|
|
|
return s.cardChallenge
|
|
|
|
}
|
2018-10-04 14:06:55 +00:00
|
|
|
|
|
|
|
func (s *Session) HostChallenge() []byte {
|
|
|
|
return s.hostChallenge
|
|
|
|
}
|