github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/verifiable/test-suite/verifiable_suite_test.go (about) 1 //go:build testsuite 2 // +build testsuite 3 4 /* 5 Copyright SecureKey Technologies Inc. All Rights Reserved. 6 SPDX-License-Identifier: Apache-2.0 7 8 This is not actually a test but rather a stand-alone generator application 9 that is used by VC Test Suite (https://github.com/w3c/vc-test-suite). 10 To run VC Test Suite, execute `make vc-test-suite`. 11 */ 12 13 package main 14 15 import ( 16 "crypto" 17 "crypto/rand" 18 "crypto/rsa" 19 "crypto/x509" 20 _ "embed" 21 "encoding/base64" 22 "encoding/json" 23 "flag" 24 "fmt" 25 "io/ioutil" 26 "os" 27 "path/filepath" 28 29 "github.com/go-jose/go-jose/v3" 30 jsonld "github.com/piprate/json-gold/ld" 31 32 "github.com/hyperledger/aries-framework-go/component/storageutil/mem" 33 "github.com/hyperledger/aries-framework-go/pkg/common/log" 34 "github.com/hyperledger/aries-framework-go/pkg/doc/ld" 35 "github.com/hyperledger/aries-framework-go/pkg/doc/ldcontext" 36 "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" 37 "github.com/hyperledger/aries-framework-go/pkg/kms" 38 ldstore "github.com/hyperledger/aries-framework-go/pkg/store/ld" 39 ) 40 41 var logger = log.New("aries-framework/doc/verifiable/test-suite") 42 var loader jsonld.DocumentLoader //nolint:gochecknoglobals 43 44 // nolint:gochecknoglobals //required for go:embed 45 var ( 46 //go:embed contexts/credentials-examples_v1.jsonld 47 credentialExamplesVocab []byte 48 //go:embed contexts/odrl.jsonld 49 odrlVocab []byte 50 ) 51 52 func main() { 53 inputFile := os.Args[len(os.Args)-1] 54 55 vcBytes, readErr := ioutil.ReadFile(inputFile) // nolint:gosec 56 if readErr != nil { 57 abort("cannot open input file %s: %v", inputFile, readErr) 58 } 59 60 contextStore, err := ldstore.NewContextStore(mem.NewProvider()) 61 if err != nil { 62 abort("create JSON-LD context store: %v", err) 63 } 64 65 remoteProviderStore, err := ldstore.NewRemoteProviderStore(mem.NewProvider()) 66 if err != nil { 67 abort("create remote JSON-LD context provider store: %v", err) 68 } 69 70 p := &provider{ 71 ContextStore: contextStore, 72 RemoteProviderStore: remoteProviderStore, 73 } 74 75 loader, err = ld.NewDocumentLoader(p, 76 ld.WithExtraContexts( 77 ldcontext.Document{ 78 URL: "https://www.w3.org/2018/credentials/examples/v1", 79 Content: credentialExamplesVocab, 80 }, 81 ldcontext.Document{ 82 URL: "https://www.w3.org/ns/odrl.jsonld", 83 Content: odrlVocab, 84 }, 85 ), 86 ) 87 if err != nil { 88 abort("create document loader: %v", err) 89 } 90 91 jwt := flag.String("jwt", "", "base64encoded JSON object containing es256kPrivateKeyJwk and rs256PrivateKeyJwk.") 92 jwtAud := flag.String("jwt-aud", "", "indication to use aud attribute in all JWTs") 93 jwtNoJws := flag.Bool("jwt-no-jws", false, "indication to suppress the JWS although keys are present") 94 jwtPresentation := flag.Bool("jwt-presentation", false, "indication to generate a verifiable presentation") 95 jwtDecode := flag.Bool("jwt-decode", false, "indication to generate a credential from a JWT verifiable credential. The input file will be a JWT instead of a JSON-LD file.") // nolint: lll 96 isPresentation := flag.Bool("presentation", false, "presentation is passed") 97 flag.Parse() 98 99 if *jwt == "" { 100 if *isPresentation { 101 encodeVPToJSON(vcBytes) 102 } else { 103 encodeVCToJSON(vcBytes, filepath.Base(inputFile)) 104 } 105 106 return 107 } 108 109 privateKey, publicKey := parseRsaKeys(*jwt) 110 111 if *jwtDecode { 112 decodeVCJWTToJSON(vcBytes, publicKey) 113 return 114 } 115 116 if *jwtNoJws { 117 encodeVCToJWTUnsecured(vcBytes) 118 return 119 } 120 121 if *jwtPresentation { 122 encodeVPToJWS(vcBytes, *jwtAud, privateKey, publicKey) 123 } else { 124 encodeVCToJWS(vcBytes, privateKey) 125 } 126 } 127 128 func encodeVCToJWS(vcBytes []byte, privateKey *rsa.PrivateKey) { 129 credential, err := verifiable.ParseCredential(vcBytes, verifiable.WithNoProofCheck(), 130 verifiable.WithJSONLDDocumentLoader(loader)) 131 if err != nil { 132 abort("failed to decode credential: %v", err) 133 } 134 135 jwtClaims, err := credential.JWTClaims(true) 136 if err != nil { 137 abort("verifiable credential encoding to JWS failed: %v", err) 138 } 139 140 jws, err := jwtClaims.MarshalJWS(verifiable.RS256, getRsaSigner(privateKey), "any") 141 if err != nil { 142 abort("failed to serialize JWS: %v", err) 143 } 144 145 fmt.Println(jws) 146 } 147 148 func encodeVPToJWS(vpBytes []byte, audience string, privateKey *rsa.PrivateKey, publicKey *rsa.PublicKey) { 149 vp, err := verifiable.ParsePresentation(vpBytes, 150 // do not test the cryptographic proofs (see https://github.com/w3c/vc-test-suite/issues/101) 151 verifiable.WithPresNoProofCheck(), 152 // the public key is used to decode verifiable credentials passed as JWS to the presentation 153 verifiable.WithPresPublicKeyFetcher(verifiable.SingleKey(publicKeyPemToBytes(publicKey), kms.RSARS256)), 154 verifiable.WithPresJSONLDDocumentLoader(loader)) 155 if err != nil { 156 abort("failed to decode presentation: %v", err) 157 } 158 159 jwtClaims, err := vp.JWTClaims([]string{audience}, true) 160 if err != nil { 161 abort("failed to build JWT claims: %v", err) 162 } 163 164 jws, err := jwtClaims.MarshalJWS(verifiable.RS256, getRsaSigner(privateKey), "any") 165 if err != nil { 166 abort("failed to serialize JWS: %v", err) 167 } 168 169 fmt.Println(jws) 170 } 171 172 func encodeVCToJWTUnsecured(vcBytes []byte) { 173 credential, err := verifiable.ParseCredential(vcBytes, verifiable.WithNoProofCheck(), 174 verifiable.WithJSONLDDocumentLoader(loader)) 175 if err != nil { 176 abort("failed to decode credential: %v", err) 177 } 178 179 jwtClaims, err := credential.JWTClaims(true) 180 if err != nil { 181 abort("verifiable credential encoding to JWT failed: %v", err) 182 } 183 184 jwtUnsecured, err := jwtClaims.MarshalUnsecuredJWT() 185 if err != nil { 186 abort("failed to serialize unsecured JWT: %v", err) 187 } 188 189 fmt.Println(jwtUnsecured) 190 } 191 192 func decodeVCJWTToJSON(vcBytes []byte, publicKey *rsa.PublicKey) { 193 // Asked to decode JWT 194 credential, err := verifiable.ParseCredential(vcBytes, 195 verifiable.WithPublicKeyFetcher(verifiable.SingleKey(publicKeyPemToBytes(publicKey), kms.RSARS256)), 196 // do not test the cryptographic proofs (see https://github.com/w3c/vc-test-suite/issues/101) 197 verifiable.WithNoProofCheck(), 198 verifiable.WithJSONLDDocumentLoader(loader)) 199 if err != nil { 200 abort("failed to decode credential: %v", err) 201 } 202 203 credential.JWT = "" 204 205 jsonBytes, err := credential.MarshalJSON() 206 if err != nil { 207 abort("failed to marshall verifiable credential to JSON: %v", err) 208 } 209 210 fmt.Println(string(jsonBytes)) 211 } 212 213 func parseRsaKeys(packedKeys string) (private *rsa.PrivateKey, public *rsa.PublicKey) { 214 // there are several JWKs which are based64 215 decodedJwt, err := base64.StdEncoding.DecodeString(packedKeys) 216 if err != nil { 217 abort("cannot decode base64 of JSON containing JWT keys: %v", err) 218 } 219 220 // found the target JWK 221 decodedJwtMap := make(map[string]interface{}) 222 223 err = json.Unmarshal(decodedJwt, &decodedJwtMap) 224 if err != nil { 225 abort("failed to decode JSON containing JWT keys: %v", err) 226 } 227 228 rs256PrivateKeyJwk, exist := decodedJwtMap["rs256PrivateKeyJwk"] 229 if !exist { 230 abort("cannot get rs256PrivateKeyJwk key") 231 } 232 233 // marshal found key back to bytes 234 jwkBytes, err := json.Marshal(rs256PrivateKeyJwk) 235 if err != nil { 236 abort("JSON marshalling error: %v", err) 237 } 238 239 jwk := &jose.JSONWebKey{} 240 241 err = jwk.UnmarshalJSON(jwkBytes) 242 if err != nil { 243 abort("JWK unmarshalling error: %v", err) 244 } 245 246 privateKey, ok := jwk.Key.(*rsa.PrivateKey) 247 if !ok { 248 abort("expected to get *rsa.PrivateKey, but got smth different") 249 } 250 251 publicKey := &privateKey.PublicKey 252 253 return privateKey, publicKey 254 } 255 256 func encodeVCToJSON(vcBytes []byte, testFileName string) { 257 vcOpts := []verifiable.CredentialOpt{ 258 verifiable.WithNoCustomSchemaCheck(), 259 verifiable.WithNoProofCheck(), 260 verifiable.WithJSONLDDocumentLoader(loader), 261 } 262 263 // This are special test cases which should be made more precise in VC Test Suite. 264 // See https://github.com/w3c/vc-test-suite/issues/96 for more information. 265 if testFileName == "example-1-bad-cardinality.jsonld" || testFileName == "example-3-bad-cardinality.jsonld" { 266 vcOpts = append(vcOpts, verifiable.WithBaseContextValidation()) 267 } 268 269 credential, err := verifiable.ParseCredential(vcBytes, vcOpts...) 270 if err != nil { 271 abort("failed to decode credential: %v", err) 272 } 273 274 encoded, err := credential.MarshalJSON() 275 if err != nil { 276 abort("failed to encode credential: %v", err) 277 } 278 279 fmt.Println(string(encoded)) 280 } 281 282 func encodeVPToJSON(vcBytes []byte) { 283 // https://www.w3.org/TR/vc-data-model/#presentations-0 states "If present" under verifiableCredential 284 // but the test suite requires the element to be present. Hence, WithPresRequireVC is used in test suite runs. 285 vp, err := verifiable.ParsePresentation(vcBytes, 286 verifiable.WithPresDisabledProofCheck(), 287 verifiable.WithPresJSONLDDocumentLoader(loader)) 288 if err != nil { 289 abort("failed to decode presentation: %v", err) 290 } 291 292 encoded, err := vp.MarshalJSON() 293 if err != nil { 294 abort("failed to encode presentation: %v", err) 295 } 296 297 fmt.Println(string(encoded)) 298 } 299 300 func getRsaSigner(privKey *rsa.PrivateKey) *rsaSigner { 301 return &rsaSigner{privateKey: privKey} 302 } 303 304 type rsaSigner struct { 305 privateKey *rsa.PrivateKey 306 } 307 308 func (s *rsaSigner) Sign(data []byte) ([]byte, error) { 309 hash := crypto.SHA256.New() 310 311 _, err := hash.Write(data) 312 if err != nil { 313 return nil, err 314 } 315 316 hashed := hash.Sum(nil) 317 318 return rsa.SignPKCS1v15(rand.Reader, s.privateKey, crypto.SHA256, hashed) 319 } 320 321 func (s *rsaSigner) Alg() string { 322 return "PS256" 323 } 324 325 func abort(msg string, args ...interface{}) { 326 logger.Errorf(msg, args...) 327 os.Exit(1) 328 } 329 330 func publicKeyPemToBytes(key *rsa.PublicKey) []byte { 331 return x509.MarshalPKCS1PublicKey(key) 332 } 333 334 type provider struct { 335 ContextStore ldstore.ContextStore 336 RemoteProviderStore ldstore.RemoteProviderStore 337 } 338 339 func (p *provider) JSONLDContextStore() ldstore.ContextStore { 340 return p.ContextStore 341 } 342 343 func (p *provider) JSONLDRemoteProviderStore() ldstore.RemoteProviderStore { 344 return p.RemoteProviderStore 345 }