Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the TSM identity to Darc #2485

Merged
merged 3 commits into from
Feb 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/full_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
- cron: "12 6 * * 1-5"

env:
GO_VERSION: 1.15
GO_VERSION: 1.17

jobs:
go:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/lint_build_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:

env:
NODE_VERSION: 10
GO_VERSION: 1.15
GO_VERSION: 1.16
JAVA_VERSION: 9

jobs:
Expand Down Expand Up @@ -39,7 +39,7 @@ jobs:

strategy:
matrix:
golang-version: [1.14, 1.15] # Cannot use env. here :(
golang-version: [1.16, 1.17] # Cannot use env. here :(

steps:
- uses: actions/checkout@main
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
- 'v*'

env:
GO_VERSION: 1.15
GO_VERSION: 1.17

jobs:
go:
Expand Down
134 changes: 120 additions & 14 deletions darc/darc.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ package darc
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
Expand Down Expand Up @@ -773,6 +775,10 @@ func (s Signer) Type() int {
return 3
case s.EvmContract != nil:
return 4
case s.DID != nil:
return 5
case s.tsm != nil:
return 6
default:
return -1
}
Expand All @@ -790,6 +796,8 @@ func (s Signer) Identity() Identity {
return NewIdentityProxy(s.Proxy)
case 4:
return NewIdentityEvmContract(s.EvmContract)
case 6:
return NewIdentityTSM(s.tsm.PrivateKey.PublicKey)
default:
return Identity{}
}
Expand All @@ -811,6 +819,8 @@ func (s Signer) Sign(msg []byte) ([]byte, error) {
return s.Proxy.Sign(msg)
case 4:
return s.EvmContract.Sign(msg)
case 6:
return s.tsm.Sign(msg)
default:
return nil, errors.New("unknown signer type")
}
Expand All @@ -821,7 +831,7 @@ func (s Signer) GetPrivate() (kyber.Scalar, error) {
switch s.Type() {
case 1:
return s.Ed25519.Secret, nil
case 0, 2, 3:
case 0, 2, 3, 4, 5, 6:
return nil, errors.New("signer lacks a private key")
default:
return nil, errors.New("signer is of unknown type")
Expand All @@ -845,6 +855,8 @@ func (id Identity) Equal(id2 *Identity) bool {
return id.Proxy.Equal(id2.Proxy)
case 4:
return id.EvmContract.Equal(id2.EvmContract)
case 6:
return bytes.Equal(id.TSM.PublicKey, id2.TSM.PublicKey)
}
return false
}
Expand All @@ -863,26 +875,18 @@ func (id Identity) Type() int {
return 3
case id.EvmContract != nil:
return 4
case id.DID != nil:
return 5
case id.TSM != nil:
return 6
}
return -1
}

// PrimaryIdentity returns true if the identity is a primary identity, which is
// an identity that is associated with a concrete public/private key.
func (id Identity) PrimaryIdentity() bool {
switch {
case id.Darc != nil:
return false
case id.Ed25519 != nil:
return true
case id.X509EC != nil:
return true
case id.Proxy != nil:
return true
case id.EvmContract != nil:
return true
}
return false
return id.Type() != 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean identities other than Darc are always Primary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - this is used to know which identities have counters. It should probably be renamed, but here I just thought it's useless to have this long switch/case, when a simple test would do...

}

// TypeString returns the string of the type of the identity.
Expand All @@ -898,6 +902,10 @@ func (id Identity) TypeString() string {
return "proxy"
case 4:
return "evm_contract"
case 5:
return "did"
case 6:
return "tsm"
default:
return "No identity"
}
Expand All @@ -918,6 +926,11 @@ func (id Identity) String() string {
bevmString := hex.EncodeToString(id.EvmContract.BEvmID)
addrString := id.EvmContract.Address.Hex()
return fmt.Sprintf("%s:%s:%s", id.TypeString(), bevmString, addrString)
case 5:
return fmt.Sprintf("%s:%s", id.TypeString(), id.DID.DID)
case 6:
buf, _ := id.TSM.MarshalBinary()
return fmt.Sprintf("%s:%x", id.TypeString(), buf)
default:
return "No identity"
}
Expand All @@ -937,6 +950,8 @@ func (id Identity) Verify(msg, sig []byte) error {
return id.Proxy.Verify(msg, sig)
case 4:
return id.EvmContract.Verify(msg, sig)
case 6:
return id.TSM.Verify(msg, sig)
ineiti marked this conversation as resolved.
Show resolved Hide resolved
default:
return errors.New("unknown identity")
}
Expand Down Expand Up @@ -964,6 +979,8 @@ func (id Identity) GetPublicBytes() []byte {
return buf
case 4:
return id.EvmContract.Address[:]
case 6:
return id.TSM.PublicKey
default:
return nil
}
Expand Down Expand Up @@ -1012,6 +1029,52 @@ func NewIdentityX509EC(public []byte) Identity {
}
}

// NewIdentityTSM creates a new TSM identity struct given a public key
func NewIdentityTSM(ecKey ecdsa.PublicKey) Identity {
return Identity{
TSM: &IdentityTSM{
PublicKey: elliptic.MarshalCompressed(ecKey.Curve, ecKey.X,
ecKey.Y),
ecKey: &ecKey,
},
}
}

// GetPublic returns the public key of the Identity.
// As it is stored in binary format, it might have to be converted.
func (ide *IdentityTSM) GetPublic() ecdsa.PublicKey {
if ide.ecKey == nil {
ecKey := ecdsa.PublicKey{}
x, y := elliptic.UnmarshalCompressed(elliptic.P256(), ide.PublicKey)
ecKey.X = x
ecKey.Y = y
ecKey.Curve = elliptic.P256()
ide.ecKey = &ecKey
}
tharvik marked this conversation as resolved.
Show resolved Hide resolved
return *ide.ecKey
}

// Verify the signature of the identity.
func (ide *IdentityTSM) Verify(msg []byte, sig []byte) error {
ecKey := ide.GetPublic()
valid := ecdsa.VerifyASN1(&ecKey, msg, sig)
if !valid {
return errors.New("Signature failed to verify")
}
return nil
}

// MarshalBinary returns the compressed public key
func (ide IdentityTSM) MarshalBinary() ([]byte, error) {
return ide.PublicKey, nil
}

// UnmarshalBinary stores the compressed public key
func (ide *IdentityTSM) UnmarshalBinary(data []byte) error {
ide.PublicKey = data
return nil
}

// NewIdentityProxy creates a new OpenID Connect identity struct.
func NewIdentityProxy(s *SignerProxy) Identity {
return Identity{
Expand Down Expand Up @@ -1120,6 +1183,8 @@ func ParseIdentity(in string) (Identity, error) {
return parseIDProxy(fields[1])
case "evm_contract":
return parseIDEvmContract(fields[1])
case "tsm":
return parseIDTSM(fields[1])
default:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing for DID?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an issue now: #2486

return Identity{}, fmt.Errorf("unknown identity type %v", fields[0])
}
Expand All @@ -1142,6 +1207,16 @@ func parseIDX509ec(in string) (Identity, error) {
return Identity{X509EC: &IdentityX509EC{Public: id}}, nil
}

func parseIDTSM(in string) (Identity, error) {
idTSM := IdentityTSM{}
_, err := hex.Decode(idTSM.PublicKey, []byte(in))
if err != nil {
return Identity{}, err
}

return Identity{TSM: &idTSM}, nil
}

func parseIDDarc(in string) (Identity, error) {
id := make([]byte, hex.DecodedLen(len(in)))
_, err := hex.Decode(id, []byte(in))
Expand Down Expand Up @@ -1447,6 +1522,37 @@ func (kcs SignerX509EC) Sign(msg []byte) ([]byte, error) {
return nil, errors.New("not yet implemented")
}

// SignerTSM holds the private key necessary to sign Darcs.
// As this is only used in testing, it is not in proto.go and thus
// not exported.
type SignerTSM struct {
PrivateKey ecdsa.PrivateKey
}

// NewSignerTSM creates a tsm signer with a SECP256K1 key.
// If a nil key is given, then a random key is generated.
// This is mostly used for testing, as the real TSM is a hardware device
// and not supported in tests.
func NewSignerTSM(private ecdsa.PrivateKey) Signer {
if private.D == nil {
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
panic("couldn't generate key: " + err.Error())
}
private = *priv
}
return Signer{tsm: &SignerTSM{
PrivateKey: private,
}}
}

// Sign the message with the private key.
// This is not really possible with the TSM signer,
// so this is mostly useful for testing.
func (kcs SignerTSM) Sign(msg []byte) ([]byte, error) {
return ecdsa.SignASN1(rand.Reader, &kcs.PrivateKey, msg)
}

// NewSignerProxy creates a new SignerProxy. When Sign is called, the getSignature
// callback will be called, so that the caller can use the appropriate mechanism
// to retrieve and/or construct the signature.
Expand Down
39 changes: 38 additions & 1 deletion darc/darc_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package darc

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"math/big"
"net/url"
"strings"
"testing"
Expand Down Expand Up @@ -754,7 +759,6 @@ func testIdentity(t *testing.T, sig Signer) {
msg := []byte("something secret")
signed, err := sig.Sign(msg)
require.NoError(t, err)

id := sig.Identity()
require.NoError(t, id.Verify(msg, signed))
require.Error(t, id.Verify([]byte("wrong message"), signed))
Expand All @@ -763,4 +767,37 @@ func testIdentity(t *testing.T, sig Signer) {
// Test the different identities available - currently only Ed25519.
func TestIdentities(t *testing.T) {
testIdentity(t, NewSignerEd25519(nil, nil))
testIdentity(t, NewSignerTSM(ecdsa.PrivateKey{}))
}

// Test a signature from the TSM
func TestTSMSignature(t *testing.T) {
var x, _ = new(big.Int).SetString("25613385885653880697990944418179706546134037329992108968315147853972798913688", 10)
var y, _ = new(big.Int).SetString("74946767262888349555270609195205284686604880870734462312238891495596941025713", 10)
pk := ecdsa.PublicKey{
Curve: elliptic.P256(),
X: x,
Y: y,
}
id := NewIdentityTSM(pk)

msg := []byte(`Hello World`)
digest := sha256.Sum256(msg)

// Signature from code example go-tsm-sdk corresponding to tsm public
// key example
signed, _ := hex.DecodeString("304402204f0b20a44efacec7b0514683233a79552026fe80e468078f6fed6cfe3f3e8a0402201eb12db7f6fe0828cafe8b0a032a37ff377b342799cfe77cfbac40c8ec1fa9e8")

require.NoError(t, id.Verify(digest[:], signed))
require.Error(t, id.Verify([]byte("wrong message"), signed))
}

// Make sure Marshalling and Unmarshalling work
func TestTSMMarshalling(t *testing.T) {
id := NewSignerTSM(ecdsa.PrivateKey{}).Identity()
buf, err := id.TSM.MarshalBinary()
require.NoError(t, err)
var id2 IdentityTSM
require.NoError(t, id2.UnmarshalBinary(buf))
require.True(t, id.Equal(&Identity{TSM: &id2}))
}
4 changes: 2 additions & 2 deletions darc/expression/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ the syntax we use is from: https://en.wikipedia.org/wiki/Extended_Backus%E2%80%9
expr = term, [ '&', term ]*
term = factor, [ '|', factor ]*
factor = '(', expr, ')' | id | openid
identity = (darc|ed25519|x509ec):[0-9a-fA-F]+
identity = (darc|ed25519|x509ec|tsm):[0-9a-fA-F]+
proxy = proxy:[0-9a-fA-F]+:[^ \n\t]*
evm_identity = evm_contract:[0-9a-fA-F]+:0x[0-9a-fA-F]+
attr = attr:[0-9a-zA-Z\-\_]+:[^ \n\t]*
Expand Down Expand Up @@ -154,7 +154,7 @@ func (e Expr) AddAndElement(id string) Expr {
func identity() parsec.Parser {
return func(s parsec.Scanner) (parsec.ParsecNode, parsec.Scanner) {
_, s = s.SkipAny(`^[ \n\t]+`)
p := parsec.Token(`(darc|ed25519|x509ec):[0-9a-fA-F]+`, "HEX")
p := parsec.Token(`(darc|ed25519|x509ec|tsm):[0-9a-fA-F]+`, "HEX")
return p(s)
}
}
Expand Down
11 changes: 11 additions & 0 deletions darc/proto.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package darc

import (
"crypto/ecdsa"

"go.dedis.ch/cothority/v3/darc/expression"
"go.dedis.ch/kyber/v3"
"go.dedis.ch/onet/v3/network"
Expand Down Expand Up @@ -71,13 +73,21 @@ type Identity struct {
EvmContract *IdentityEvmContract
// A claim signed by one of the keys in a DID Doc
DID *IdentityDID
// Public-key identity from an ECDSA key
TSM *IdentityTSM
}

// IdentityEd25519 holds a Ed25519 public key (Point)
type IdentityEd25519 struct {
Point kyber.Point
}

// IdentityTSM holds a secp256k1 key (array of bytes)
type IdentityTSM struct {
PublicKey []byte
ecKey *ecdsa.PublicKey
}

// IdentityX509EC holds a public key from a X509EC
type IdentityX509EC struct {
Public []byte
Expand Down Expand Up @@ -159,6 +169,7 @@ type Signer struct {
Proxy *SignerProxy
EvmContract *SignerEvmContract
DID *SignerDID
tsm *SignerTSM
}

// SignerEd25519 holds a public and private keys necessary to sign Darcs
Expand Down
Loading