add normal and secure channel and installer

This commit is contained in:
Andrea Franz 2018-10-02 13:25:04 +02:00
parent 5ddbdb3386
commit 02fb9f848c
No known key found for this signature in database
GPG Key ID: 4F0D2F2D9DE7F29D
4 changed files with 202 additions and 0 deletions

7
channel.go Normal file
View File

@ -0,0 +1,7 @@
package smartcard
import "github.com/status-im/status-go/smartcard/apdu"
type Channel interface {
Send(*apdu.Command) (*apdu.Response, error)
}

103
installer.go Normal file
View File

@ -0,0 +1,103 @@
package smartcard
import (
"crypto/rand"
"errors"
"fmt"
"github.com/status-im/status-go/smartcard/apdu"
"github.com/status-im/status-go/smartcard/globalplatform"
"github.com/status-im/status-go/smartcard/hexutils"
)
var (
sdaid = []byte{0xa0, 0x00, 0x00, 0x01, 0x51, 0x00, 0x00, 0x00}
testKey = []byte{0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f}
)
type Installer struct {
c Channel
}
func NewInstaller(t Transmitter) *Installer {
return &Installer{
c: NewNormalChannel(t),
}
}
func (i *Installer) Install() error {
// select / discover
l("sending select", nil)
sel := globalplatform.NewCommandSelect(sdaid)
resp, err := i.send("select", sel)
if err != nil {
return err
}
// initialize update
l("initialize update", nil)
hostChallenge, err := generateHostChallenge()
if err != nil {
return err
}
init := globalplatform.NewCommandInitializeUpdate(hostChallenge)
resp, err = i.send("initialize update", init)
if err != nil {
return err
}
// verify cryptogram and initialize session keys
keys := globalplatform.NewKeyProvider(testKey, testKey)
session, err := globalplatform.NewSession(keys, resp, hostChallenge)
if err != nil {
return err
}
i.c = NewSecureChannel(session, i.c)
// external authenticate
encKey := session.KeyProvider().Enc()
extAuth, err := globalplatform.NewCommandExternalAuthenticate(encKey, session.CardChallenge(), hostChallenge)
if err != nil {
return err
}
resp, err = i.send("external authenticate", extAuth)
if err != nil {
return err
}
return nil
}
func (i *Installer) send(description string, cmd *apdu.Command, allowedResponses ...uint16) (*apdu.Response, error) {
resp, err := i.c.Send(cmd)
if err != nil {
return nil, err
}
if len(allowedResponses) == 0 {
allowedResponses = []uint16{apdu.SwOK}
}
for _, code := range allowedResponses {
if code == resp.Sw {
return resp, nil
}
}
err = errors.New(fmt.Sprintf("unexpected response from command %s: %x", description, resp.Sw))
return nil, err
}
func generateHostChallenge() ([]byte, error) {
c := make([]byte, 8)
_, err := rand.Read(c)
return c, err
}
func l(message string, raw []byte) {
fmt.Printf("%s %s\n", message, hexutils.BytesToHexWithSpaces(raw))
}

47
normal_channel.go Normal file
View File

@ -0,0 +1,47 @@
package smartcard
import (
"fmt"
"github.com/status-im/status-go/smartcard/apdu"
"github.com/status-im/status-go/smartcard/globalplatform"
"github.com/status-im/status-go/smartcard/hexutils"
)
type Transmitter interface {
Transmit([]byte) ([]byte, error)
}
type NormalChannel struct {
t Transmitter
}
func NewNormalChannel(t Transmitter) *NormalChannel {
return &NormalChannel{t}
}
func (c *NormalChannel) Send(cmd *apdu.Command) (*apdu.Response, error) {
rawCmd, err := cmd.Serialize()
if err != nil {
return nil, err
}
fmt.Printf("COMMAND %s\n", hexutils.BytesToHexWithSpaces(rawCmd))
rawResp, err := c.t.Transmit(rawCmd)
if err != nil {
return nil, err
}
fmt.Printf("RESPONSE %s\n", hexutils.BytesToHexWithSpaces(rawResp))
resp, err := apdu.ParseResponse(rawResp)
if err != nil {
return nil, err
}
if resp.Sw1 == globalplatform.Sw1ResponseDataIncomplete && (cmd.Cla != globalplatform.ClaISO7816 || cmd.Ins != globalplatform.InsGetResponse) {
getResponse := globalplatform.NewCommandGetResponse(resp.Sw2)
return c.Send(getResponse)
}
return apdu.ParseResponse(rawResp)
}

45
secure_channel.go Normal file
View File

@ -0,0 +1,45 @@
package smartcard
import (
"fmt"
"github.com/status-im/status-go/smartcard/apdu"
"github.com/status-im/status-go/smartcard/globalplatform"
"github.com/status-im/status-go/smartcard/hexutils"
)
type SecureChannel struct {
session *globalplatform.Session
c Channel
w *globalplatform.APDUWrapper
}
func NewSecureChannel(session *globalplatform.Session, c Channel) *SecureChannel {
return &SecureChannel{
session: session,
c: c,
w: globalplatform.NewAPDUWrapper(session.KeyProvider().Mac()),
}
}
func (c *SecureChannel) Send(cmd *apdu.Command) (*apdu.Response, error) {
rawCmd, err := cmd.Serialize()
if err != nil {
return nil, err
}
fmt.Printf("WRAPPING %s\n", hexutils.BytesToHexWithSpaces(rawCmd))
wrappedCmd, err := c.w.Wrap(cmd)
if err != nil {
return nil, err
}
rawWrappedCmd, err := wrappedCmd.Serialize()
if err != nil {
return nil, err
}
fmt.Printf("WRAPPED %s\n", hexutils.BytesToHexWithSpaces(rawWrappedCmd))
return c.c.Send(wrappedCmd)
}