-
Notifications
You must be signed in to change notification settings - Fork 5
/
tokenProvider.go
232 lines (192 loc) · 7.17 KB
/
tokenProvider.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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
package tir
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"encoding/base64"
"errors"
"net/http"
"os"
common "github.com/fiware/VCVerifier/common"
configModel "github.com/fiware/VCVerifier/config"
"github.com/fiware/VCVerifier/logging"
v5 "github.com/golang-jwt/jwt/v5"
"github.com/google/uuid"
"github.com/piprate/json-gold/ld"
"github.com/trustbloc/did-go/doc/ld/processor"
"github.com/trustbloc/kms-go/spi/kms"
"github.com/trustbloc/vc-go/proof/creator"
"github.com/trustbloc/vc-go/proof/jwtproofs/ps256"
"github.com/trustbloc/vc-go/proof/ldproofs/jsonwebsignature2020"
"github.com/trustbloc/vc-go/verifiable"
)
/**
* Global file accessor
*/
var localFileAccessor fileAccessor = diskFileAccessor{}
var ErrorTokenProviderNoKey = errors.New("no_key_configured")
var ErrorTokenProviderNoVC = errors.New("no_vc_configured")
var ErrorTokenProviderNoVerificationMethod = errors.New("no_verification_method_configured")
var ErrorBadPrivateKey = errors.New("bad_private_key_length")
var ErrorTokenProviderNoDid = errors.New("no_did_configured")
type TokenProvider interface {
GetToken(vc *verifiable.Credential, audience string) (string, error)
GetAuthCredential() (vc *verifiable.Credential, err error)
}
type M2MTokenProvider struct {
// encodes the token according to the configuration
tokenEncoder TokenEncoder
// the credential
authCredential *verifiable.Credential
// the signing key
signingKey *rsa.PrivateKey
// clock to get issuance time from
clock common.Clock
// verification method to be used on the tokens
verificationMethod string
// signature type to be used
signatureType string
// type of the provided key
keyType string
// did of the token provider
did string
}
type TokenEncoder interface {
GetEncodedToken(vp *verifiable.Presentation, audience string) (encodedToken string, err error)
}
type Base64TokenEncoder struct{}
func InitM2MTokenProvider(config *configModel.Configuration, clock common.Clock) (tokenProvider TokenProvider, err error) {
m2mConfig := config.M2M
if m2mConfig.KeyPath == "" {
logging.Log().Warn("No private key configured, cannot provide m2m tokens.")
return tokenProvider, ErrorTokenProviderNoKey
}
if m2mConfig.VerificationMethod == "" {
logging.Log().Warn("No verification method configured, cannot provide m2m tokens.")
return tokenProvider, ErrorTokenProviderNoVerificationMethod
}
privateKey, err := getSigningKey(m2mConfig.KeyPath)
if err != nil {
logging.Log().Warnf("Was not able to load the signing key. Err: %v", err)
return tokenProvider, err
}
if m2mConfig.CredentialPath == "" {
return tokenProvider, ErrorTokenProviderNoVC
}
if config.Verifier.Did == "" {
logging.Log().Warn("No did for token provider")
return tokenProvider, ErrorTokenProviderNoDid
}
vc, err := getCredential(m2mConfig.CredentialPath)
if err != nil {
logging.Log().Warnf("Was not able to load the credential. Err: %v", err)
return tokenProvider, err
}
logging.Log().Debug("Successfully initialized the M2MTokenProvider.")
return M2MTokenProvider{tokenEncoder: Base64TokenEncoder{}, authCredential: vc, signingKey: privateKey, did: config.Verifier.Did, clock: clock, verificationMethod: m2mConfig.VerificationMethod, keyType: config.M2M.KeyType, signatureType: config.M2M.SignatureType}, err
}
func (tokenProvider M2MTokenProvider) GetAuthCredential() (vc *verifiable.Credential, err error) {
return tokenProvider.authCredential, err
}
func (tokenProvider M2MTokenProvider) GetToken(vc *verifiable.Credential, audience string) (token string, err error) {
vp, err := tokenProvider.signVerifiablePresentation(vc)
if err != nil {
logging.Log().Warnf("Was not able to get a signed verifiable presentation. Err: %v", err)
return token, err
}
return tokenProvider.tokenEncoder.GetEncodedToken(vp, audience)
}
func (base64TokenEncoder Base64TokenEncoder) GetEncodedToken(vc *verifiable.Presentation, audience string) (encodedToken string, err error) {
marshalledPayload, err := vc.MarshalJSON()
if err != nil {
logging.Log().Warnf("Was not able to marshal the token payload. Err: %v", err)
return encodedToken, err
}
return base64.RawURLEncoding.EncodeToString(marshalledPayload), err
}
func (tp M2MTokenProvider) signVerifiablePresentation(authCredential *verifiable.Credential) (vp *verifiable.Presentation, err error) {
vp, err = verifiable.NewPresentation(verifiable.WithCredentials(authCredential))
if err != nil {
logging.Log().Warnf("Was not able to create a presentation. Err: %v", err)
return vp, err
}
vp.ID = "urn:uuid:" + uuid.NewString()
vp.Holder = tp.did
proofCreator := creator.New(creator.WithLDProofType(jsonwebsignature2020.New(), NewRS256Signer(tp.signingKey)), creator.WithJWTAlg(ps256.New(), NewRS256Signer(tp.signingKey)))
created := tp.clock.Now()
err = vp.AddLinkedDataProof(&verifiable.LinkedDataProofContext{
Created: &created,
SignatureType: tp.signatureType,
KeyType: kms.KeyType(tp.keyType),
ProofCreator: proofCreator,
SignatureRepresentation: verifiable.SignatureJWS,
VerificationMethod: tp.verificationMethod,
}, processor.WithDocumentLoader(ld.NewDefaultDocumentLoader(http.DefaultClient)))
if err != nil {
logging.Log().Warnf("Was not able to add an ld-proof. Err: %v", err)
return vp, err
}
return vp, err
}
/**
* Read siging key from local filesystem
*/
func getSigningKey(keyPath string) (key *rsa.PrivateKey, err error) {
// read key file
rawKey, err := localFileAccessor.ReadFile(keyPath)
if err != nil {
logging.Log().Warnf("Was not able to read the key file from %s. err: %v", keyPath, err)
return key, err
} // parse key file
key, err = v5.ParseRSAPrivateKeyFromPEM(rawKey)
if err != nil {
logging.Log().Warnf("Was not able to parse the key %s. err: %v", rawKey, err)
return key, err
}
return
}
func getCredential(vcPath string) (vc *verifiable.Credential, err error) {
vcBytes, err := localFileAccessor.ReadFile(vcPath)
if err != nil {
logging.Log().Warnf("Was not able to read the vc file from %s. err: %v", vcPath, err)
return vc, err
}
logging.Log().Warnf("Got bytes %v", string(vcBytes))
vc, err = verifiable.ParseCredential(vcBytes, verifiable.WithJSONLDDocumentLoader(ld.NewDefaultDocumentLoader(http.DefaultClient)), verifiable.WithDisabledProofCheck())
if err != nil {
logging.Log().Warnf("Was not able to unmarshal the credential. Err: %v", err)
return vc, err
}
c, _ := vc.MarshalJSON()
logging.Log().Warnf("The cred %s", string(c))
return vc, err
}
// file system interfaces
// Interface to the http-client
type fileAccessor interface {
ReadFile(filename string) ([]byte, error)
}
type diskFileAccessor struct{}
func (diskFileAccessor) ReadFile(filename string) ([]byte, error) {
return os.ReadFile(filename)
}
// NewRS256Signer creates RS256Signer.
func NewRS256Signer(privKey *rsa.PrivateKey) *RS256Signer {
return &RS256Signer{
privKey: privKey,
}
}
// Sign data.
func (s RS256Signer) Sign(data []byte) ([]byte, error) {
hash := crypto.SHA256.New()
_, err := hash.Write(data)
if err != nil {
return nil, err
}
hashed := hash.Sum(nil)
return rsa.SignPKCS1v15(rand.Reader, s.privKey, crypto.SHA256, hashed)
}
// RS256Signer is a Jose complient signer.
type RS256Signer struct {
privKey *rsa.PrivateKey
}