github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/jwt/verifier.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package jwt 8 9 import ( 10 "crypto" 11 "crypto/rsa" 12 "crypto/x509" 13 "errors" 14 "fmt" 15 "strings" 16 17 "golang.org/x/crypto/ed25519" 18 19 "github.com/hyperledger/aries-framework-go/component/models/signature/verifier" 20 "github.com/hyperledger/aries-framework-go/pkg/doc/jose" 21 kmsapi "github.com/hyperledger/aries-framework-go/pkg/kms" 22 ) 23 24 const ( 25 // signatureEdDSA defines EdDSA alg. 26 signatureEdDSA = "EdDSA" 27 28 // signatureRS256 defines RS256 alg. 29 signatureRS256 = "RS256" 30 ) 31 32 // KeyResolver resolves public key based on what and kid. 33 type KeyResolver interface { 34 35 // Resolve resolves public key. 36 Resolve(what, kid string) (*verifier.PublicKey, error) 37 } 38 39 // KeyResolverFunc defines function. 40 type KeyResolverFunc func(what, kid string) (*verifier.PublicKey, error) 41 42 // Resolve resolves public key. 43 func (k KeyResolverFunc) Resolve(what, kid string) (*verifier.PublicKey, error) { 44 return k(what, kid) 45 } 46 47 // BasicVerifier defines basic Signed JWT verifier based on Issuer Claim and Key ID JOSE Header. 48 type BasicVerifier struct { 49 resolver KeyResolver 50 compositeVerifier *jose.CompositeAlgSigVerifier 51 } 52 53 // NewVerifier creates a new basic Verifier. 54 func NewVerifier(resolver KeyResolver) *BasicVerifier { 55 // TODO Support pluggable JWS verifiers 56 // (https://github.com/hyperledger/aries-framework-go/issues/1267) 57 verifiers := []verifier.SignatureVerifier{ 58 verifier.NewECDSAES256SignatureVerifier(), 59 verifier.NewECDSAES384SignatureVerifier(), 60 verifier.NewECDSAES521SignatureVerifier(), 61 verifier.NewEd25519SignatureVerifier(), 62 verifier.NewECDSASecp256k1SignatureVerifier(), 63 verifier.NewRSAPS256SignatureVerifier(), 64 verifier.NewRSARS256SignatureVerifier(), 65 } 66 67 algVerifiers := make([]jose.AlgSignatureVerifier, 0, len(verifiers)) 68 for _, v := range verifiers { 69 algVerifiers = append(algVerifiers, jose.AlgSignatureVerifier{ 70 Alg: v.Algorithm(), 71 Verifier: getVerifier(resolver, v.Verify), 72 }) 73 } 74 75 compositeVerifier := jose.NewCompositeAlgSigVerifier(algVerifiers[0], algVerifiers[1:]...) 76 // TODO ECDSA to support NIST P256 curve 77 // https://github.com/hyperledger/aries-framework-go/issues/1266 78 79 return &BasicVerifier{resolver: resolver, compositeVerifier: compositeVerifier} 80 } 81 82 // GetVerifier returns new BasicVerifier based on *verifier.PublicKey. 83 func GetVerifier(publicKey *verifier.PublicKey) (*BasicVerifier, error) { 84 keyType, err := publicKey.JWK.KeyType() 85 if err != nil { 86 return nil, err 87 } 88 89 var v verifier.SignatureVerifier 90 91 switch keyType { 92 case kmsapi.ECDSAP256TypeDER, kmsapi.ECDSAP256TypeIEEEP1363: 93 v = verifier.NewECDSAES256SignatureVerifier() 94 case kmsapi.ECDSAP384TypeDER, kmsapi.ECDSAP384TypeIEEEP1363: 95 v = verifier.NewECDSAES384SignatureVerifier() 96 case kmsapi.ECDSAP521TypeDER, kmsapi.ECDSAP521TypeIEEEP1363: 97 v = verifier.NewECDSAES521SignatureVerifier() 98 case kmsapi.ED25519Type: 99 v = verifier.NewEd25519SignatureVerifier() 100 case kmsapi.ECDSASecp256k1DER, kmsapi.ECDSASecp256k1TypeIEEEP1363: 101 v = verifier.NewECDSASecp256k1SignatureVerifier() 102 case kmsapi.RSAPS256Type: 103 v = verifier.NewRSAPS256SignatureVerifier() 104 case kmsapi.RSARS256Type: 105 v = verifier.NewRSARS256SignatureVerifier() 106 107 default: 108 return nil, errors.New("unsupported key type") 109 } 110 111 compositeVerifier := jose.NewCompositeAlgSigVerifier( 112 jose.AlgSignatureVerifier{ 113 Alg: v.Algorithm(), 114 Verifier: getPublicKeyVerifier(publicKey, v), 115 }, 116 ) 117 118 return &BasicVerifier{compositeVerifier: compositeVerifier}, nil 119 } 120 121 type signatureVerifier func(pubKey *verifier.PublicKey, message, signature []byte) error 122 123 func getVerifier(resolver KeyResolver, signatureVerifier signatureVerifier) jose.SignatureVerifier { 124 return jose.SignatureVerifierFunc(func(joseHeaders jose.Headers, payload, signingInput, signature []byte) error { 125 return verifySignature(resolver, signatureVerifier, joseHeaders, payload, signingInput, signature) 126 }) 127 } 128 129 func getPublicKeyVerifier(publicKey *verifier.PublicKey, v verifier.SignatureVerifier) jose.SignatureVerifier { 130 return jose.SignatureVerifierFunc(func(joseHeaders jose.Headers, payload, signingInput, signature []byte) error { 131 alg, ok := joseHeaders.Algorithm() 132 if !ok { 133 return errors.New("'alg' JOSE header is not present") 134 } 135 if alg != v.Algorithm() { 136 return fmt.Errorf("alg is not %s", v.Algorithm()) 137 } 138 139 return v.Verify(publicKey, signingInput, signature) 140 }) 141 } 142 143 func verifySignature(resolver KeyResolver, signatureVerifier signatureVerifier, 144 joseHeaders jose.Headers, _, signingInput, signature []byte) error { 145 kid, _ := joseHeaders.KeyID() 146 147 if !strings.HasPrefix(kid, "did:") { 148 return fmt.Errorf("kid %s is not DID", kid) 149 } 150 151 pubKey, err := resolver.Resolve(strings.Split(kid, "#")[0], strings.Split(kid, "#")[1]) 152 if err != nil { 153 return err 154 } 155 156 return signatureVerifier(pubKey, signingInput, signature) 157 } 158 159 // Verify verifies JSON Web Token. Public key is fetched using Issuer Claim and Key ID JOSE Header. 160 func (v BasicVerifier) Verify(joseHeaders jose.Headers, payload, signingInput, signature []byte) error { 161 return v.compositeVerifier.Verify(joseHeaders, payload, signingInput, signature) 162 } 163 164 // VerifyEdDSA verifies EdDSA signature. 165 func VerifyEdDSA(pubKey *verifier.PublicKey, message, signature []byte) error { 166 // TODO Use crypto for signing/verification logic 167 // https://github.com/hyperledger/aries-framework-go/issues/1278 168 if l := len(pubKey.Value); l != ed25519.PublicKeySize { 169 return errors.New("bad ed25519 public key length") 170 } 171 172 if ok := ed25519.Verify(pubKey.Value, message, signature); !ok { 173 return errors.New("signature doesn't match") 174 } 175 176 return nil 177 } 178 179 // VerifyRS256 verifies RS256 signature. 180 func VerifyRS256(pubKey *verifier.PublicKey, message, signature []byte) error { 181 // TODO Use crypto for signing/verification logic 182 // https://github.com/hyperledger/aries-framework-go/issues/1278 183 pubKeyRsa, err := x509.ParsePKCS1PublicKey(pubKey.Value) 184 if err != nil { 185 return errors.New("not *rsa.VerificationMethod public key") 186 } 187 188 hash := crypto.SHA256.New() 189 190 _, err = hash.Write(message) 191 if err != nil { 192 return err 193 } 194 195 hashed := hash.Sum(nil) 196 197 return rsa.VerifyPKCS1v15(pubKeyRsa, crypto.SHA256, hashed, signature) 198 }