forked from hyperledger-archives/aries-framework-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
proof.go
216 lines (178 loc) · 5.45 KB
/
proof.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package proof
import (
"encoding/base64"
"errors"
"fmt"
"github.com/Universal-Health-Chain/aries-framework-go/pkg/doc/util"
)
const (
// jsonldType is key for proof type.
jsonldType = "type"
// jsonldCreator is key for creator.
jsonldCreator = "creator"
// jsonldCreated is key for time proof created.
jsonldCreated = "created"
// jsonldDomain is key for domain name.
jsonldDomain = "domain"
// jsonldNonce is key for nonce.
jsonldNonce = "nonce"
// jsonldProofValue is key for proof value.
jsonldProofValue = "proofValue"
// jsonldProofPurpose is a purpose of proof.
jsonldProofPurpose = "proofPurpose"
// jsonldJWSProof is key for JWS proof.
jsonldJWS = "jws"
// jsonldVerificationMethod is a key for verification method.
jsonldVerificationMethod = "verificationMethod"
// jsonldChallenge is a key for challenge.
jsonldChallenge = "challenge"
// jsonldCapabilityChain is a key for capabilityChain.
jsonldCapabilityChain = "capabilityChain"
)
// Proof is cryptographic proof of the integrity of the DID Document.
type Proof struct {
Type string
Created *util.TimeWithTrailingZeroMsec
Creator string
VerificationMethod string
ProofValue []byte
JWS string
ProofPurpose string
Domain string
Nonce []byte
Challenge string
SignatureRepresentation SignatureRepresentation
// CapabilityChain must be an array. Each element is either a string or an object.
CapabilityChain []interface{}
}
// NewProof creates new proof.
func NewProof(emap map[string]interface{}) (*Proof, error) {
created := stringEntry(emap[jsonldCreated])
timeValue, err := util.ParseTimeWithTrailingZeroMsec(created)
if err != nil {
return nil, err
}
var (
proofValue []byte
proofHolder SignatureRepresentation
jws string
)
if generalProof, ok := emap[jsonldProofValue]; ok {
proofValue, err = decodeBase64(stringEntry(generalProof))
if err != nil {
return nil, err
}
proofHolder = SignatureProofValue
} else if jwsProof, ok := emap[jsonldJWS]; ok {
jws = stringEntry(jwsProof)
proofHolder = SignatureJWS
}
if len(proofValue) == 0 && jws == "" {
return nil, errors.New("signature is not defined")
}
nonce, err := decodeBase64(stringEntry(emap[jsonldNonce]))
if err != nil {
return nil, err
}
capabilityChain, err := decodeCapabilityChain(emap)
if err != nil {
return nil, fmt.Errorf("failed to decode capabilityChain: %w", err)
}
return &Proof{
Type: stringEntry(emap[jsonldType]),
Created: timeValue,
Creator: stringEntry(emap[jsonldCreator]),
VerificationMethod: stringEntry(emap[jsonldVerificationMethod]),
ProofValue: proofValue,
SignatureRepresentation: proofHolder,
JWS: jws,
ProofPurpose: stringEntry(emap[jsonldProofPurpose]),
Domain: stringEntry(emap[jsonldDomain]),
Nonce: nonce,
Challenge: stringEntry(emap[jsonldChallenge]),
CapabilityChain: capabilityChain,
}, nil
}
func decodeCapabilityChain(proof map[string]interface{}) ([]interface{}, error) {
var capabilityChain []interface{}
untyped, found := proof[jsonldCapabilityChain]
if found {
var ok bool
capabilityChain, ok = untyped.([]interface{})
if !ok {
return nil, fmt.Errorf("invalid format for capabilityChain - must be an array: %+v", untyped)
}
}
return capabilityChain, nil
}
func decodeBase64(s string) ([]byte, error) {
allEncodings := []*base64.Encoding{
base64.RawURLEncoding, base64.StdEncoding,
}
for _, encoding := range allEncodings {
value, err := encoding.DecodeString(s)
if err == nil {
return value, nil
}
}
return nil, errors.New("unsupported encoding")
}
// stringEntry.
func stringEntry(entry interface{}) string {
if entry == nil {
return ""
}
return entry.(string)
}
// JSONLdObject returns map that represents JSON LD Object.
func (p *Proof) JSONLdObject() map[string]interface{} { // nolint:gocyclo
emap := make(map[string]interface{})
emap[jsonldType] = p.Type
if p.Creator != "" {
emap[jsonldCreator] = p.Creator
}
if p.VerificationMethod != "" {
emap[jsonldVerificationMethod] = p.VerificationMethod
}
if p.Created != nil {
emap[jsonldCreated] = p.Created.Format(p.Created.GetFormat())
}
if len(p.ProofValue) > 0 {
emap[jsonldProofValue] = base64.RawURLEncoding.EncodeToString(p.ProofValue)
}
if len(p.JWS) > 0 {
emap[jsonldJWS] = p.JWS
}
if p.Domain != "" {
emap[jsonldDomain] = p.Domain
}
if len(p.Nonce) > 0 {
emap[jsonldNonce] = base64.RawURLEncoding.EncodeToString(p.Nonce)
}
if p.ProofPurpose != "" {
emap[jsonldProofPurpose] = p.ProofPurpose
}
if p.Challenge != "" {
emap[jsonldChallenge] = p.Challenge
}
if p.CapabilityChain != nil {
emap[jsonldCapabilityChain] = p.CapabilityChain
}
return emap
}
// PublicKeyID provides ID of public key to be used to independently verify the proof.
// "verificationMethod" field is checked first. If not empty, its value is returned.
// Otherwise, "creator" field is returned if not empty. Otherwise, error is returned.
func (p *Proof) PublicKeyID() (string, error) {
if p.VerificationMethod != "" {
return p.VerificationMethod, nil
}
if p.Creator != "" {
return p.Creator, nil
}
return "", errors.New("no public key ID")
}