github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/verifiable/common.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 Copyright Avast Software. All Rights Reserved. 4 5 SPDX-License-Identifier: Apache-2.0 6 */ 7 8 // Package verifiable implements Verifiable Credential and Presentation data model 9 // (https://www.w3.org/TR/vc-data-model). 10 // It provides the data structures and functions which allow to process the Verifiable documents on different 11 // sides and levels. For example, an Issuer can create verifiable.Credential structure and issue it to a 12 // Holder in JWS form. The Holder can decode received Credential and make sure the signature is valid. 13 // The Holder can present the Credential to the Verifier or combine one or more Credentials into a Verifiable 14 // Presentation. The Verifier can decode and verify the received Credentials and Presentations. 15 package verifiable 16 17 import ( 18 "encoding/json" 19 "errors" 20 "fmt" 21 "strings" 22 23 "github.com/piprate/json-gold/ld" 24 "github.com/xeipuuv/gojsonschema" 25 26 "github.com/hyperledger/aries-framework-go/pkg/doc/did" 27 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier" 28 jsonutil "github.com/hyperledger/aries-framework-go/pkg/doc/util/json" 29 vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr" 30 kmsapi "github.com/hyperledger/aries-framework-go/pkg/kms" 31 ) 32 33 // TODO https://github.com/square/go-jose/issues/263 support ES256K 34 35 // JWSAlgorithm defines JWT signature algorithms of Verifiable Credential. 36 type JWSAlgorithm int 37 38 const ( 39 // RS256 JWT Algorithm. 40 RS256 JWSAlgorithm = iota 41 42 // PS256 JWT Algorithm. 43 PS256 44 45 // EdDSA JWT Algorithm. 46 EdDSA 47 48 // ECDSASecp256k1 JWT Algorithm. 49 ECDSASecp256k1 50 51 // ECDSASecp256r1 JWT Algorithm. 52 ECDSASecp256r1 53 54 // ECDSASecp384r1 JWT Algorithm. 55 ECDSASecp384r1 56 57 // ECDSASecp521r1 JWT Algorithm. 58 ECDSASecp521r1 59 ) 60 61 // KeyTypeToJWSAlgo returns the JWSAlgorithm based on keyType. 62 func KeyTypeToJWSAlgo(keyType kmsapi.KeyType) (JWSAlgorithm, error) { 63 switch keyType { 64 case kmsapi.ECDSAP256TypeDER, kmsapi.ECDSAP256TypeIEEEP1363: 65 return ECDSASecp256r1, nil 66 case kmsapi.ECDSAP384TypeDER, kmsapi.ECDSAP384TypeIEEEP1363: 67 return ECDSASecp384r1, nil 68 case kmsapi.ECDSAP521TypeDER, kmsapi.ECDSAP521TypeIEEEP1363: 69 return ECDSASecp521r1, nil 70 case kmsapi.ED25519Type: 71 return EdDSA, nil 72 case kmsapi.ECDSASecp256k1TypeIEEEP1363, kmsapi.ECDSASecp256k1DER: 73 return ECDSASecp256k1, nil 74 case kmsapi.RSARS256Type: 75 return RS256, nil 76 case kmsapi.RSAPS256Type: 77 return PS256, nil 78 default: 79 return 0, errors.New("unsupported key type") 80 } 81 } 82 83 // Name return the name of the signature algorithm. 84 func (ja JWSAlgorithm) Name() (string, error) { 85 switch ja { 86 case RS256: 87 return "RS256", nil 88 case PS256: 89 return "PS256", nil 90 case EdDSA: 91 return "EdDSA", nil 92 case ECDSASecp256k1: 93 return "ES256K", nil 94 case ECDSASecp256r1: 95 return "ES256", nil 96 case ECDSASecp384r1: 97 return "ES384", nil 98 case ECDSASecp521r1: 99 return "ES521", nil 100 default: 101 return "", fmt.Errorf("unsupported algorithm: %v", ja) 102 } 103 } 104 105 type jsonldCredentialOpts struct { 106 jsonldDocumentLoader ld.DocumentLoader 107 externalContext []string 108 jsonldOnlyValidRDF bool 109 } 110 111 // PublicKeyFetcher fetches public key for JWT signing verification based on Issuer ID (possibly DID) 112 // and Key ID. 113 // If not defined, JWT encoding is not tested. 114 type PublicKeyFetcher func(issuerID, keyID string) (*verifier.PublicKey, error) 115 116 // SingleKey defines the case when only one verification key is used and we don't need to pick the one. 117 func SingleKey(pubKey []byte, pubKeyType string) PublicKeyFetcher { 118 return func(_, _ string) (*verifier.PublicKey, error) { 119 return &verifier.PublicKey{ 120 Type: pubKeyType, 121 Value: pubKey, 122 }, nil 123 } 124 } 125 126 // VDRKeyResolver resolves DID in order to find public keys for VC verification using vdr.Registry. 127 // A source of DID could be issuer of VC or holder of VP. It can be also obtained from 128 // JWS "issuer" claim or "verificationMethod" of Linked Data Proof. 129 type VDRKeyResolver struct { 130 vdr didResolver 131 } 132 133 type didResolver interface { 134 Resolve(did string, opts ...vdrapi.DIDMethodOption) (*did.DocResolution, error) 135 } 136 137 // NewVDRKeyResolver creates VDRKeyResolver. 138 func NewVDRKeyResolver(vdr didResolver) *VDRKeyResolver { 139 return &VDRKeyResolver{vdr: vdr} 140 } 141 142 func (r *VDRKeyResolver) resolvePublicKey(issuerDID, keyID string) (*verifier.PublicKey, error) { 143 docResolution, err := r.vdr.Resolve(issuerDID) 144 if err != nil { 145 return nil, fmt.Errorf("resolve DID %s: %w", issuerDID, err) 146 } 147 148 for _, verifications := range docResolution.DIDDocument.VerificationMethods() { 149 for _, verification := range verifications { 150 if strings.Contains(verification.VerificationMethod.ID, keyID) && 151 verification.Relationship != did.KeyAgreement { 152 return &verifier.PublicKey{ 153 Type: verification.VerificationMethod.Type, 154 Value: verification.VerificationMethod.Value, 155 JWK: verification.VerificationMethod.JSONWebKey(), 156 }, nil 157 } 158 } 159 } 160 161 return nil, fmt.Errorf("public key with KID %s is not found for DID %s", keyID, issuerDID) 162 } 163 164 // PublicKeyFetcher returns Public Key Fetcher via DID resolution mechanism. 165 func (r *VDRKeyResolver) PublicKeyFetcher() PublicKeyFetcher { 166 return r.resolvePublicKey 167 } 168 169 // Proof defines embedded proof of Verifiable Credential. 170 type Proof map[string]interface{} 171 172 // CustomFields is a map of extra fields of struct build when unmarshalling JSON which are not 173 // mapped to the struct fields. 174 type CustomFields map[string]interface{} 175 176 // TypedID defines a flexible structure with id and name fields and arbitrary extra fields 177 // kept in CustomFields. 178 type TypedID struct { 179 ID string `json:"id,omitempty"` 180 Type string `json:"type,omitempty"` 181 182 CustomFields `json:"-"` 183 } 184 185 // MarshalJSON defines custom marshalling of TypedID to JSON. 186 func (tid TypedID) MarshalJSON() ([]byte, error) { 187 // TODO hide this exported method 188 type Alias TypedID 189 190 alias := Alias(tid) 191 192 data, err := jsonutil.MarshalWithCustomFields(alias, tid.CustomFields) 193 if err != nil { 194 return nil, fmt.Errorf("marshal TypedID: %w", err) 195 } 196 197 return data, nil 198 } 199 200 // UnmarshalJSON defines custom unmarshalling of TypedID from JSON. 201 func (tid *TypedID) UnmarshalJSON(data []byte) error { 202 // TODO hide this exported method 203 type Alias TypedID 204 205 alias := (*Alias)(tid) 206 207 tid.CustomFields = make(CustomFields) 208 209 err := jsonutil.UnmarshalWithCustomFields(data, alias, tid.CustomFields) 210 if err != nil { 211 return fmt.Errorf("unmarshal TypedID: %w", err) 212 } 213 214 return nil 215 } 216 217 func newTypedID(v interface{}) (TypedID, error) { 218 bytes, err := json.Marshal(v) 219 if err != nil { 220 return TypedID{}, err 221 } 222 223 var tid TypedID 224 err = json.Unmarshal(bytes, &tid) 225 226 return tid, err 227 } 228 229 func describeSchemaValidationError(result *gojsonschema.Result, what string) string { 230 errMsg := what + " is not valid:\n" 231 for _, desc := range result.Errors() { 232 errMsg += fmt.Sprintf("- %s\n", desc) 233 } 234 235 return errMsg 236 } 237 238 func stringSlice(values []interface{}) ([]string, error) { 239 s := make([]string, len(values)) 240 241 for i := range values { 242 t, valid := values[i].(string) 243 if !valid { 244 return nil, errors.New("array element is not a string") 245 } 246 247 s[i] = t 248 } 249 250 return s, nil 251 } 252 253 // decodeType decodes raw type(s). 254 // 255 // type can be defined as a single string value or array of strings. 256 func decodeType(t interface{}) ([]string, error) { 257 switch rType := t.(type) { 258 case string: 259 return []string{rType}, nil 260 case []interface{}: 261 types, err := stringSlice(rType) 262 if err != nil { 263 return nil, fmt.Errorf("vc types: %w", err) 264 } 265 266 return types, nil 267 default: 268 return nil, errors.New("credential type of unknown structure") 269 } 270 } 271 272 // decodeContext decodes raw context(s). 273 // 274 // context can be defined as a single string value or array; 275 // at the second case, the array can be a mix of string and object types 276 // (objects can express context information); object context are 277 // defined at the tail of the array. 278 func decodeContext(c interface{}) ([]string, []interface{}, error) { 279 switch rContext := c.(type) { 280 case string: 281 return []string{rContext}, nil, nil 282 case []interface{}: 283 s := make([]string, 0) 284 285 for i := range rContext { 286 c, valid := rContext[i].(string) 287 if !valid { 288 // the remaining contexts are of custom type 289 return s, rContext[i:], nil 290 } 291 292 s = append(s, c) 293 } 294 // no contexts of custom type, just string contexts found 295 return s, nil, nil 296 default: 297 return nil, nil, errors.New("credential context of unknown type") 298 } 299 } 300 301 func safeStringValue(v interface{}) string { 302 if v == nil { 303 return "" 304 } 305 306 return v.(string) 307 } 308 309 func proofsToRaw(proofs []Proof) ([]byte, error) { 310 switch len(proofs) { 311 case 0: 312 return nil, nil 313 case 1: 314 return json.Marshal(proofs[0]) 315 default: 316 return json.Marshal(proofs) 317 } 318 } 319 320 func parseProof(proofBytes json.RawMessage) ([]Proof, error) { 321 if len(proofBytes) == 0 { 322 return nil, nil 323 } 324 325 var singleProof Proof 326 327 err := json.Unmarshal(proofBytes, &singleProof) 328 if err == nil { 329 return []Proof{singleProof}, nil 330 } 331 332 var composedProof []Proof 333 334 err = json.Unmarshal(proofBytes, &composedProof) 335 if err == nil { 336 return composedProof, nil 337 } 338 339 return nil, err 340 }