add normal and secure channel and installer
This commit is contained in:
parent
5ddbdb3386
commit
02fb9f848c
|
@ -0,0 +1,7 @@
|
|||
package smartcard
|
||||
|
||||
import "github.com/status-im/status-go/smartcard/apdu"
|
||||
|
||||
type Channel interface {
|
||||
Send(*apdu.Command) (*apdu.Response, error)
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue