Skip to content

Commit

Permalink
Finalize WebAuthN support in eos-go
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthieu Vachon committed Jan 22, 2020
1 parent 4985cf2 commit 7f5a661
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 84 deletions.
6 changes: 4 additions & 2 deletions abidecoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -714,15 +714,17 @@ func TestABI_Read(t *testing.T) {
{"caseName": "checksum256", "typeName": "checksum256", "value": `"0000000000000000000000000000000000000000000000000000000000000000"`, "encode": Checksum256(make([]byte, TypeSize.Checksum256)), "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "checksum512", "typeName": "checksum512", "value": `"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"`, "encode": Checksum512(make([]byte, TypeSize.Checksum512)), "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "public_key", "typeName": "public_key", "value": `"EOS1111111111111111111111111111111114T1Anm"`, "encode": ecc.MustNewPublicKey("EOS1111111111111111111111111111111114T1Anm"), "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "signature", "typeName": "signature", "value": `"SIG_K1_K96L1au4xFJg5edn6qBK6UDbSsC2RKsMs4cXCA2LoCPZxBDMXehdZFWPh1GeRhzGoQjBwNK2eBmUXf4L8SBApL69pGdUJm"`, "encode": ecc.Signature{Curve: ecc.CurveK1, Content: signatureBuffer[1:]}, "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "public_key_wa", "typeName": "public_key", "value": `"PUB_WA_5hyixc7vkMbKiThWi1TnFtXw7HTDcHfjREj2SzxCtgw3jQGepa5T9VHEy1Tunjzzj"`, "encode": ecc.MustNewPublicKey("PUB_WA_5hyixc7vkMbKiThWi1TnFtXw7HTDcHfjREj2SzxCtgw3jQGepa5T9VHEy1Tunjzzj"), "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "signature", "typeName": "signature", "value": `"SIG_K1_K96L1au4xFJg5edn6qBK6UDbSsC2RKsMs4cXCA2LoCPZxBDMXehdZFWPh1GeRhzGoQjBwNK2eBmUXf4L8SBApL69pGdUJm"`, "encode": ecc.MustNewSignatureFromData(signatureBuffer), "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "signature_wa", "typeName": "signature", "value": `"SIG_WA_28AzYsRYSSA85Q4Jjp4zkiyBA8G85AcPsHU3HUuqLkY3LooYcFiSMGGxhEQcCzAhaZJqdaUXG16p8t63sDhqh9L4xc24CDxbf81D6FW4SXGjxQSM2D7FAJSSQCogjbqJanTP5CbSF8FWyaD4pVVAs4Z9ubqNhHCkiLDesEukwGYu6ujgwQkFqczow5cSwTqTirdgqCBjkGQLMT3KV2JwjN7b2qPAyDa2vvjsGWFP8HVTw2tctD6FBPHU9nFgtfcztkc3eqxVU9UbvUbKayU62dLZBwNCwHxmyPymH5YfoJLhBkS8s"`, "encode": ecc.MustNewSignature("SIG_WA_28AzYsRYSSA85Q4Jjp4zkiyBA8G85AcPsHU3HUuqLkY3LooYcFiSMGGxhEQcCzAhaZJqdaUXG16p8t63sDhqh9L4xc24CDxbf81D6FW4SXGjxQSM2D7FAJSSQCogjbqJanTP5CbSF8FWyaD4pVVAs4Z9ubqNhHCkiLDesEukwGYu6ujgwQkFqczow5cSwTqTirdgqCBjkGQLMT3KV2JwjN7b2qPAyDa2vvjsGWFP8HVTw2tctD6FBPHU9nFgtfcztkc3eqxVU9UbvUbKayU62dLZBwNCwHxmyPymH5YfoJLhBkS8s"), "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "symbol", "typeName": "symbol", "value": `"4,EOS"`, "encode": EOSSymbol, "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "symbol_code", "typeName": "symbol_code", "value": `"BNTDAPP"`, "encode": SymbolCode(22606239386324546), "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "asset", "typeName": "asset", "value": `"10.0000 EOS"`, "encode": Asset{Amount: 100000, Symbol: EOSSymbol}, "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "extended_asset", "typeName": "extended_asset", "value": "{\"asset\":\"0.0010 EOS\",\"Contract\":\"eoscanadacom\"}", "encode": ExtendedAsset{Asset: Asset{Amount: 10, Symbol: EOSSymbol}, Contract: "eoscanadacom"}, "expectedError": nil, "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "bad type", "typeName": "bad.type.1", "value": nil, "encode": nil, "expectedError": fmt.Errorf("decoding field [testedField] of type [bad.type.1]: read field of type [bad.type.1]: unknown type"), "isOptional": false, "isArray": false, "fieldName": "testedField"},
{"caseName": "optional present", "typeName": "string", "value": `"value.1"`, "encode": optional, "expectedError": nil, "isOptional": true, "isArray": false, "fieldName": "testedField"},
{"caseName": "optional not present", "typeName": "string", "value": "", "encode": optionalNotPresent, "expectedError": nil, "isOptional": true, "isArray": false, "fieldName": "testedField"},
{"caseName": "optional missing flag", "typeName": "string", "value": nil, "encode": optionalMissingFlag, "expectedError": fmt.Errorf("decoding field [testedField] optional flag: byte required [1] byte, remaining [0]"), "isOptional": true, "isArray": false, "fieldName": "testedField"},
{"caseName": "optional missing flag", "typeName": "string", "value": nil, "encode": optionalMissingFlag, "expectedError": fmt.Errorf("decoding field [testedField] optional flag: required [1] byte, remaining [0]"), "isOptional": true, "isArray": false, "fieldName": "testedField"},
{"caseName": "array", "typeName": "string", "value": "[\"value.1\",\"value.2\"]", "encode": []string{"value.1", "value.2"}, "expectedError": nil, "isOptional": false, "isArray": true, "fieldName": "testedField"},
{"caseName": "array empty", "typeName": "string", "value": "[]", "encode": []string{}, "expectedError": nil, "isOptional": false, "isArray": true, "fieldName": "testedField"},
{"caseName": "missing array", "typeName": "string", "value": nil, "encode": nil, "expectedError": fmt.Errorf("reading field [testedField] array length: varint: invalid buffer size"), "isOptional": false, "isArray": true, "fieldName": "testedField"},
Expand Down
90 changes: 80 additions & 10 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ func (d *Decoder) ReadByteArray() (out []byte, err error) {

func (d *Decoder) ReadByte() (out byte, err error) {
if d.remaining() < TypeSize.Byte {
err = fmt.Errorf("byte required [1] byte, remaining [%d]", d.remaining())
err = fmt.Errorf("required [1] byte, remaining [%d]", d.remaining())
return
}

Expand Down Expand Up @@ -751,7 +751,7 @@ func (d *Decoder) ReadPublicKey() (out ecc.PublicKey, err error) {
} else if curveID == ecc.CurveWA {
keyMaterial, err = d.readWAPublicKeyMaterial()
} else {
err = fmt.Errorf("unsupported curve ID")
err = fmt.Errorf("unsupported curve ID: %s", curveID)
}

if err != nil {
Expand Down Expand Up @@ -786,7 +786,6 @@ func (d *Decoder) readPublicKeyMaterial(curveID ecc.CurveID, keyMaterialSize int

func (d *Decoder) readWAPublicKeyMaterial() (out []byte, err error) {
begin := d.pos
fmt.Println("begin", d.pos)
if d.remaining() < 35 {
err = fmt.Errorf("publicKey WA key material requires at least [35] bytes, remaining [%d]", d.remaining())
return
Expand All @@ -813,23 +812,94 @@ func (d *Decoder) readWAPublicKeyMaterial() (out []byte, err error) {
}

func (d *Decoder) ReadSignature() (out ecc.Signature, err error) {
if d.remaining() < TypeSize.Signature {
err = fmt.Errorf("signature required [%d] bytes, remaining [%d]", TypeSize.Signature, d.remaining())
return
typeID, err := d.ReadUInt8()
if err != nil {
return out, fmt.Errorf("unable to read signature type: %s", err)
}

sigContent := make([]byte, 66)
copy(sigContent, d.data[d.pos:d.pos+TypeSize.Signature])
curveID := ecc.CurveID(typeID)
var data []byte

if curveID == ecc.CurveK1 || curveID == ecc.CurveR1 {
// Minus 1 because we already read the curveID which is 1 out of the 34 bytes of a full "legacy" PublicKey
if d.remaining() < TypeSize.Signature-1 {
return out, fmt.Errorf("signature required [%d] bytes, remaining [%d]", TypeSize.Signature-1, d.remaining())
}

out, err = ecc.NewSignatureFromData(sigContent)
data = make([]byte, 66)
data[0] = byte(curveID)
copy(data[1:], d.data[d.pos:d.pos+TypeSize.Signature-1])
d.pos += TypeSize.Signature - 1
} else if curveID == ecc.CurveWA {
data, err = d.readWASignatureData()
if err != nil {
return out, fmt.Errorf("unable to read WA signature: %s", err)
}
} else {
return out, fmt.Errorf("unsupported curve ID: %s", curveID)
}

out, err = ecc.NewSignatureFromData(data)
if err != nil {
return out, fmt.Errorf("new signature: %s", err)
}

d.pos += TypeSize.Signature
if loggingEnabled {
decoderLog.Debug("read signature", zap.Stringer("sig", out))
}

// sigContent := make([]byte, 66)
// copy(sigContent, d.data[d.pos:d.pos+TypeSize.Signature])

// out, err = ecc.NewSignatureFromData(sigContent)
// if err != nil {
// return out, fmt.Errorf("new signature: %s", err)
// }

// d.pos += TypeSize.Signature
// if loggingEnabled {
// decoderLog.Debug("read signature", zap.Stringer("sig", out))
// }
return
}

func (d *Decoder) readWASignatureData() (out []byte, err error) {
begin := d.pos
if d.remaining() < 66 {
err = fmt.Errorf("signature WA key material requires at least [66] bytes, remaining [%d]", d.remaining())
return
}

// Skip key recover param id (1 byte), R value (32 bytes) and S value (32 bytes)
d.pos += 65
authenticatorDataSize, err := d.ReadUvarint32()
if err != nil {
return out, fmt.Errorf("unable to read signature WA authenticator data size: %s", err)
}

if d.remaining() < int(authenticatorDataSize) {
err = fmt.Errorf("signature WA authenticator data requires [%d] bytes, remaining [%d]", authenticatorDataSize, d.remaining())
return
}
d.pos += int(authenticatorDataSize)

clientDataJSONSize, err := d.ReadUvarint32()
if err != nil {
return out, fmt.Errorf("unable to read signature WA client data JSON size: %s", err)
}

if d.remaining() < int(clientDataJSONSize) {
err = fmt.Errorf("signature WA client data JSON requires [%d] bytes, remaining [%d]", clientDataJSONSize, d.remaining())
return
}
d.pos += int(clientDataJSONSize)

signatureMaterialSize := d.pos - begin

out = make([]byte, signatureMaterialSize+1)
out[0] = byte(ecc.CurveWA)
copy(out[1:], d.data[begin:begin+signatureMaterialSize])

return
}

Expand Down
35 changes: 22 additions & 13 deletions decoder_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package eos

import (
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"testing"

"bytes"

"time"

"github.com/eoscanada/eos-go/ecc"
Expand Down Expand Up @@ -310,14 +307,9 @@ func TestDecoder_PublicKey_WA(t *testing.T) {
enc := NewEncoder(buf)
assert.NoError(t, enc.writePublicKey(pk))

fmt.Println(hex.EncodeToString(buf.Bytes()))

d := NewDecoder(buf.Bytes())

rpk, err := d.ReadPublicKey()
fmt.Println(hex.EncodeToString([]byte{byte(rpk.Curve)}))
fmt.Println(hex.EncodeToString(rpk.Content))

require.NoError(t, err)

assert.Equal(t, pk, rpk)
Expand Down Expand Up @@ -348,6 +340,23 @@ func TestDecoder_Signature(t *testing.T) {
assert.Equal(t, 0, d.remaining())
}

func TestDecoder_Signature_WA(t *testing.T) {
sig := ecc.MustNewSignature("SIG_WA_28AzYsRYSSA85Q4Jjp4zkiyBA8G85AcPsHU3HUuqLkY3LooYcFiSMGGxhEQcCzAhaZJqdaUXG16p8t63sDhqh9L4xc24CDxbf81D6FW4SXGjxQSM2D7FAJSSQCogjbqJanTP5CbSF8FWyaD4pVVAs4Z9ubqNhHCkiLDesEukwGYu6ujgwQkFqczow5cSwTqTirdgqCBjkGQLMT3KV2JwjN7b2qPAyDa2vvjsGWFP8HVTw2tctD6FBPHU9nFgtfcztkc3eqxVU9UbvUbKayU62dLZBwNCwHxmyPymH5YfoJLhBkS8s")

buf := new(bytes.Buffer)
enc := NewEncoder(buf)
assert.NoError(t, enc.writeSignature(sig))

d := NewDecoder(buf.Bytes())

rsig, err := d.ReadSignature()

require.NoError(t, err)

assert.Equal(t, sig, rsig)
assert.Equal(t, 0, d.remaining())
}

func TestDecoder_Empty_Signature(t *testing.T) {

sig := ecc.Signature{Content: []byte{}}
Expand Down Expand Up @@ -436,7 +445,7 @@ func TestDecoder_Encode(t *testing.T) {
// maps don't serialize deterministically.. we no want that.
// F8: map[string]string{"foo": "bar", "hello": "you"},
F9: ecc.MustNewPublicKey("EOS1111111111111111111111111111111114T1Anm"),
F10: ecc.Signature{Curve: ecc.CurveK1, Content: make([]byte, 65)},
F10: ecc.MustNewSignatureFromData(make([]byte, 66)),
F11: byte(1),
F12: uint64(87),
F13: []byte{1, 2, 3, 4, 5},
Expand Down Expand Up @@ -670,7 +679,7 @@ func TestDecoder_Decode_struct_tag_BinaryExtension_AllAtStart(t *testing.T) {
func TestDecoder_readUint16_missing_data(t *testing.T) {

_, err := NewDecoder([]byte{}).ReadByte()
assert.EqualError(t, err, "byte required [1] byte, remaining [0]")
assert.EqualError(t, err, "required [1] byte, remaining [0]")

_, err = NewDecoder([]byte{}).ReadUint16()
assert.EqualError(t, err, "uint16 required [2] bytes, remaining [0]")
Expand All @@ -685,10 +694,10 @@ func TestDecoder_readUint16_missing_data(t *testing.T) {
assert.EqualError(t, err, "checksum 256 required [32] bytes, remaining [0]")

_, err = NewDecoder([]byte{}).ReadPublicKey()
assert.EqualError(t, err, "unable to read public key type: byte required [1] byte, remaining [0]")
assert.EqualError(t, err, "unable to read public key type: required [1] byte, remaining [0]")

_, err = NewDecoder([]byte{}).ReadSignature()
assert.EqualError(t, err, "signature required [66] bytes, remaining [0]")
assert.EqualError(t, err, "unable to read signature type: required [1] byte, remaining [0]")

_, err = NewDecoder([]byte{}).ReadTstamp()
assert.EqualError(t, err, "tstamp required [8] bytes, remaining [0]")
Expand Down
2 changes: 1 addition & 1 deletion ecc/privkey_k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func (k *innerK1PrivateKey) sign(hash []byte) (out Signature, err error) {
return out, fmt.Errorf("canonical, %s", err)
}

return Signature{Curve: CurveK1, Content: compactSig, innerSignature: &innerK1Signature{}}, nil
return Signature{Curve: CurveK1, Content: compactSig, inner: &innerK1Signature{}}, nil
}

func (k *innerK1PrivateKey) string() string {
Expand Down
4 changes: 2 additions & 2 deletions ecc/pubkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ type pubkeyReaderManifest struct {
inner func() innerPublicKey
}

var pubKeyReaderManifest = map[string]pubkeyReaderManifest{
var pubKeyReaderManifests = map[string]pubkeyReaderManifest{
PublicKeyPrefixCompat: pubkeyReaderManifest{CurveK1, newInnerK1PublicKey},
PublicKeyK1Prefix: pubkeyReaderManifest{CurveK1, newInnerK1PublicKey},
PublicKeyR1Prefix: pubkeyReaderManifest{CurveR1, newInnerR1PublicKey},
Expand All @@ -83,7 +83,7 @@ func NewPublicKey(pubKey string) (out PublicKey, err error) {
return out, fmt.Errorf("invalid format")
}

for prefix, manifest := range pubKeyReaderManifest {
for prefix, manifest := range pubKeyReaderManifests {
if !strings.HasPrefix(pubKey, prefix) {
continue
}
Expand Down
Loading

0 comments on commit 7f5a661

Please sign in to comment.