Skip to content

Commit aa5d447

Browse files
committed
feat: sign claims and add entity attributes
1 parent 638f88e commit aa5d447

10 files changed

Lines changed: 214 additions & 58 deletions

File tree

claim/claim.go

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package claim
22

33
import (
4-
"encoding/hex"
54
"encoding/json"
65
"strings"
6+
"time"
77

88
"github.com/ockam-network/ockam"
99
"github.com/ockam-network/ockam/random"
@@ -14,10 +14,13 @@ type Data map[string]interface{}
1414

1515
// Claim is
1616
type Claim struct {
17-
id string
18-
data Data
19-
issuer ockam.Entity
20-
subject ockam.Entity
17+
nonce string
18+
id string
19+
data Data
20+
_type string
21+
issuer ockam.Entity
22+
subject ockam.Entity
23+
signatures []ockam.Signature
2124
}
2225

2326
// Option is
@@ -31,15 +34,16 @@ func New(data Data, options ...Option) (*Claim, error) {
3134
option(c)
3235
}
3336

34-
s, err := random.GenerateAlphaNumericString(31)
37+
nonce, err := random.GenerateAlphaNumericString(10)
3538
if err != nil {
3639
return nil, err
3740
}
41+
c.nonce = nonce
3842

3943
if c.issuer != nil {
40-
c.id = c.issuer.ID().String() + "/claim/" + s
44+
c.id = c.issuer.ID().String() + "/claim/" + nonce
4145
} else {
42-
c.id = s
46+
c.id = nonce
4347
}
4448

4549
return c, nil
@@ -52,6 +56,13 @@ func ID(id string) Option {
5256
}
5357
}
5458

59+
// Type is
60+
func Type(t string) Option {
61+
return func(c *Claim) {
62+
c._type = t
63+
}
64+
}
65+
5566
// Issuer is
5667
func Issuer(e ockam.Entity) Option {
5768
return func(c *Claim) {
@@ -71,9 +82,19 @@ func (c *Claim) ID() string {
7182
return c.id
7283
}
7384

74-
// SetID sets the claim's ID
75-
func (c *Claim) SetID(id string) {
76-
c.id = id
85+
// Nonce returns the claim's Nonce
86+
func (c *Claim) Nonce() string {
87+
return c.nonce
88+
}
89+
90+
// Type returns the claim's Type
91+
func (c *Claim) Type() string {
92+
return c._type
93+
}
94+
95+
// SetType sets the claim's Type
96+
func (c *Claim) SetType(t string) {
97+
c._type = t
7798
}
7899

79100
// Issuer returns the claim's Issuer entity
@@ -119,15 +140,44 @@ func (c *Claim) Signatures() []ockam.Signature {
119140
}
120141

121142
// AddSignature is
122-
func (c *Claim) AddSignature(ockam.Signature) {
123-
}
143+
func (c *Claim) AddSignature(s ockam.Signature) {
144+
c.signatures = append(c.signatures, s)
145+
}
146+
147+
// MarshalJSON is
148+
func (c *Claim) MarshalJSON() ([]byte, error) {
149+
type j struct {
150+
Context []string `json:"@context"`
151+
ID string `json:"id"`
152+
Type []string `json:"type"`
153+
Issuer string `json:"issuer"`
154+
Issued string `json:"issued"`
155+
Claim map[string]interface{} `json:"claim"`
156+
Signatures []map[string]interface{} `json:"signatures,omitempty"`
157+
}
124158

125-
// MarshalBinary is
126-
func (c Claim) MarshalBinary() ([]byte, error) {
127-
b, err := json.Marshal(c.data)
128-
if err != nil {
129-
return nil, err
159+
vc := &j{
160+
Context: []string{"https://w3id.org/identity/v1", "https://w3id.org/security/v1"},
161+
ID: c.ID(),
162+
Type: []string{c.Type()},
163+
Issuer: c.Issuer().ID().String(),
164+
Issued: time.Now().UTC().Format("2006-01-02"),
130165
}
131-
s := hex.EncodeToString(b)
132-
return []byte(c.id + "=" + s), nil
166+
167+
vc.Claim = c.Data()
168+
vc.Claim["id"] = c.Subject().ID().String()
169+
170+
for _, s := range c.signatures {
171+
sj := map[string]interface{}{
172+
"type": s.Type(),
173+
"created": s.Created(),
174+
"creator": s.Creator(),
175+
"domain": s.Domain(),
176+
"nonce": s.Nonce(),
177+
"signatureValue": s.SignatureValue(),
178+
}
179+
vc.Signatures = append(vc.Signatures, sj)
180+
}
181+
182+
return json.Marshal(vc)
133183
}

entity/entity.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
11
package entity
22

33
import (
4+
"strconv"
5+
46
"github.com/ockam-network/did"
57
"github.com/ockam-network/ockam"
68
)
79

10+
// Attributes is
11+
type Attributes map[string]interface{}
12+
813
// Entity is
914
type Entity struct {
10-
id *did.DID
11-
signers []ockam.Signer
15+
id *did.DID
16+
signers []ockam.Signer
17+
attributes Attributes
1218
}
1319

1420
// Option is
1521
type Option func(*Entity)
1622

1723
// New creates
18-
func New(options ...Option) (*Entity, error) {
19-
e := &Entity{}
24+
func New(attributes Attributes, options ...Option) (*Entity, error) {
25+
e := &Entity{attributes: attributes}
2026

2127
for _, option := range options {
2228
option(e)
@@ -42,6 +48,7 @@ func ID(did *did.DID) Option {
4248
func Signer(s ockam.Signer) Option {
4349
return func(e *Entity) {
4450
// s.PublicKey().SetOwner(e)
51+
s.PublicKey().SetLabel("#key-" + strconv.Itoa(len(e.signers)+1))
4552
e.signers = append(e.signers, s)
4653
}
4754
}
@@ -51,6 +58,11 @@ func (e *Entity) ID() *did.DID {
5158
return e.id
5259
}
5360

61+
// Attributes is
62+
func (e *Entity) Attributes() map[string]interface{} {
63+
return e.attributes
64+
}
65+
5466
// Signers is
5567
func (e *Entity) Signers() []ockam.Signer {
5668
return e.signers

example/02_register_entity.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,21 @@ func main() {
3030
exitOnError(err)
3131

3232
// create a new ockam entity to represent a temperature sensor
33-
temperatureSensor, err := entity.New(entity.Signer(signer))
33+
temperatureSensor, err := entity.New(
34+
entity.Attributes{
35+
"name": "Temperature Sensor",
36+
"manufacturer": "Element 14",
37+
"model": "Raspberry Pi 3 Model B+",
38+
},
39+
entity.Signer(signer),
40+
)
3441
exitOnError(err)
3542

3643
// register the ockam
3744
registrationClaim, err := ockamChain.Register(temperatureSensor)
3845
exitOnError(err)
3946

40-
fmt.Printf("registrationClaim - %s\n", registrationClaim)
47+
fmt.Printf("registrationClaim - %s\n", registrationClaim.ID())
4148
}
4249

4350
func exitOnError(err error) {

example/03_submit_claim.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ func main() {
3131
exitOnError(err)
3232

3333
// create a new ockam entity to represent a temperature sensor
34-
temperatureSensor, err := entity.New(entity.Signer(signer))
34+
temperatureSensor, err := entity.New(
35+
entity.Attributes{"name": "Temperature Sensor"},
36+
entity.Signer(signer),
37+
)
3538
exitOnError(err)
3639

3740
// create a temperature claim with this new sensor entity as both the issuer and the subject of the claim

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ require (
55
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect
66
github.com/mr-tron/base58 v1.1.0
77
github.com/ockam-network/did v0.1.3
8+
github.com/piprate/json-gold v0.1.1
89
github.com/pkg/errors v0.8.0
910
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc
1011
github.com/tendermint/go-amino v0.14.1

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ=
66
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
77
github.com/ockam-network/did v0.1.3 h1:qJGdccOV4bLfsS/eFM+Aj+CdCRJKNMxbmJevQclw44k=
88
github.com/ockam-network/did v0.1.3/go.mod h1:ZsbTIuVGt8OrQEbqWrSztUISN4joeMabdsinbLubbzw=
9+
github.com/piprate/json-gold v0.1.1 h1:gEWltb371VE5Uo8FBB+CfQIfLmUVPfcvjcPeml2wLbw=
10+
github.com/piprate/json-gold v0.1.1/go.mod h1:5EEeMX0Gg1CyQxoy4QRhufCfMSCOvcRAaqwkrn6NqqY=
911
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
1012
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
13+
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
14+
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
1115
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc h1:F5tKCVGp+MUAHhKp5MZtGqAlGX3+oCsiL1Q629FL90M=
1216
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
1317
github.com/tendermint/go-amino v0.14.1 h1:o2WudxNfdLNBwMyl2dqOJxiro5rfrEaU0Ugs6offJMk=

key/ed25519/ed25519.go

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import (
44
"crypto/rand"
55
"crypto/sha512"
66
"encoding/hex"
7+
"encoding/json"
78
"hash"
89
"time"
910

1011
"github.com/ockam-network/did"
1112
"github.com/ockam-network/ockam"
1213
"github.com/ockam-network/ockam/entity"
13-
"github.com/ockam-network/ockam/random"
14+
"github.com/piprate/json-gold/ld"
1415
"github.com/pkg/errors"
1516
"golang.org/x/crypto/ed25519"
1617
)
@@ -41,25 +42,41 @@ func (k *Ed25519) PublicKey() ockam.PublicKey {
4142

4243
// Sign is
4344
func (k *Ed25519) Sign(c ockam.Claim) error {
44-
binary, err := c.MarshalBinary()
45+
claimJSON, err := c.MarshalJSON()
4546
if err != nil {
4647
return err
4748
}
4849

49-
k.hasher.Write(binary)
50-
signature := ed25519.Sign(k.private, k.hasher.Sum(nil))
50+
var claimMap map[string]interface{}
51+
err = json.Unmarshal(claimJSON, &claimMap)
52+
if err != nil {
53+
return errors.WithStack(err)
54+
}
55+
56+
delete(claimMap, "signatures")
57+
58+
proc := ld.NewJsonLdProcessor()
59+
options := ld.NewJsonLdOptions("")
60+
options.Format = "application/nquads"
61+
options.Algorithm = "URDNA2015"
5162

52-
nonce, err := random.GenerateBytes(20)
63+
canonicalized, err := proc.Normalize(claimMap, options)
5364
if err != nil {
54-
return err
65+
return errors.WithStack(err)
5566
}
5667

68+
toSign := []byte(canonicalized.(string))
69+
70+
k.hasher.Write(toSign)
71+
signature := ed25519.Sign(k.private, k.hasher.Sum(nil))
72+
5773
s := &Signature{
5874
t: "Ed25519Signature2018",
59-
creator: k.PublicKey(),
60-
created: time.Now(),
61-
nonce: nonce,
75+
creator: c.Issuer().ID().String() + k.PublicKey().Label(),
76+
created: time.Now().UTC().Format(time.RFC3339),
77+
nonce: c.Nonce(),
6278
signatureValue: signature,
79+
signedValue: toSign,
6380
}
6481

6582
c.AddSignature(s)

key/ed25519/signature.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
package ed25519
22

3-
import (
4-
"time"
5-
6-
"github.com/ockam-network/ockam"
7-
)
8-
93
// Signature is
104
type Signature struct {
115
t string
12-
creator ockam.PublicKey
13-
created time.Time
6+
creator string
7+
created string
148
domain string
15-
nonce []byte
9+
nonce string
1610
signatureValue []byte
11+
signedValue []byte
1712
}
1813

1914
// Type is
@@ -23,23 +18,23 @@ func (s *Signature) Type() string {
2318
}
2419

2520
// Creator is
26-
func (s *Signature) Creator() ockam.PublicKey {
21+
func (s *Signature) Creator() string {
2722
return s.creator
2823
}
2924

3025
// Created is
31-
func (s *Signature) Created() time.Time {
26+
func (s *Signature) Created() string {
3227
return s.created
3328
}
3429

3530
// Domain is
3631
func (s *Signature) Domain() string {
37-
return s.domain
32+
return "ockam"
3833
}
3934

4035
// Nonce is
4136
// https://web-payments.org/vocabs/security#nonce
42-
func (s *Signature) Nonce() []byte {
37+
func (s *Signature) Nonce() string {
4338
return s.nonce
4439
}
4540

@@ -48,3 +43,7 @@ func (s *Signature) Nonce() []byte {
4843
func (s *Signature) SignatureValue() []byte {
4944
return s.signatureValue
5045
}
46+
47+
func (s *Signature) SignedValue() []byte {
48+
return s.signedValue
49+
}

0 commit comments

Comments
 (0)