github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/jwt/jwt_support.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/ed25519"
    12  	"crypto/rand"
    13  	"crypto/rsa"
    14  	"errors"
    15  
    16  	"github.com/hyperledger/aries-framework-go/pkg/doc/jose"
    17  )
    18  
    19  // JoseED25519Signer is a Jose compliant signer.
    20  type JoseED25519Signer struct {
    21  	privKey []byte
    22  	headers map[string]interface{}
    23  }
    24  
    25  // Sign data.
    26  func (s JoseED25519Signer) Sign(data []byte) ([]byte, error) {
    27  	return ed25519.Sign(s.privKey, data), nil
    28  }
    29  
    30  // Headers returns the signer's headers map.
    31  func (s JoseED25519Signer) Headers() jose.Headers {
    32  	return s.headers
    33  }
    34  
    35  // NewEd25519Signer returns a Jose compliant signer that can be passed as a signer to jwt.NewSigned().
    36  func NewEd25519Signer(privKey []byte) *JoseED25519Signer {
    37  	return &JoseED25519Signer{
    38  		privKey: privKey,
    39  		headers: prepareJWSHeaders(nil, signatureEdDSA),
    40  	}
    41  }
    42  
    43  // JoseEd25519Verifier is a Jose compliant verifier.
    44  type JoseEd25519Verifier struct {
    45  	pubKey []byte
    46  }
    47  
    48  // Verify signingInput against signature. it validates that joseHeaders contains EdDSA alg for this implementation.
    49  func (v JoseEd25519Verifier) Verify(joseHeaders jose.Headers, _, signingInput, signature []byte) error {
    50  	alg, ok := joseHeaders.Algorithm()
    51  	if !ok {
    52  		return errors.New("alg is not defined")
    53  	}
    54  
    55  	if alg != "EdDSA" {
    56  		return errors.New("alg is not EdDSA")
    57  	}
    58  
    59  	if ok := ed25519.Verify(v.pubKey, signingInput, signature); !ok {
    60  		return errors.New("signature doesn't match")
    61  	}
    62  
    63  	return nil
    64  }
    65  
    66  // NewEd25519Verifier returns a Jose compliant verifier that can be passed as a verifier option to jwt.Parse().
    67  func NewEd25519Verifier(pubKey []byte) (*JoseEd25519Verifier, error) {
    68  	if l := len(pubKey); l != ed25519.PublicKeySize {
    69  		return nil, errors.New("bad ed25519 public key length")
    70  	}
    71  
    72  	return &JoseEd25519Verifier{pubKey: pubKey}, nil
    73  }
    74  
    75  // RS256Signer is a Jose complient signer.
    76  type RS256Signer struct {
    77  	privKey *rsa.PrivateKey
    78  	headers map[string]interface{}
    79  }
    80  
    81  // NewRS256Signer returns a Jose compliant signer that can be passed as a signer to jwt.NewSigned().
    82  func NewRS256Signer(privKey *rsa.PrivateKey, headers map[string]interface{}) *RS256Signer {
    83  	return &RS256Signer{
    84  		privKey: privKey,
    85  		headers: prepareJWSHeaders(headers, signatureRS256),
    86  	}
    87  }
    88  
    89  // Sign data.
    90  func (s RS256Signer) Sign(data []byte) ([]byte, error) {
    91  	hash := crypto.SHA256.New()
    92  
    93  	_, err := hash.Write(data)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	hashed := hash.Sum(nil)
    99  
   100  	return rsa.SignPKCS1v15(rand.Reader, s.privKey, crypto.SHA256, hashed)
   101  }
   102  
   103  // Headers returns the signer's headers map.
   104  func (s RS256Signer) Headers() jose.Headers {
   105  	return s.headers
   106  }
   107  
   108  // RS256Verifier is a Jose compliant verifier.
   109  type RS256Verifier struct {
   110  	pubKey *rsa.PublicKey
   111  }
   112  
   113  // NewRS256Verifier returns a Jose compliant verifier that can be passed as a verifier option to jwt.Parse().
   114  func NewRS256Verifier(pubKey *rsa.PublicKey) *RS256Verifier {
   115  	return &RS256Verifier{pubKey: pubKey}
   116  }
   117  
   118  // Verify signingInput against the signature. It also validates that joseHeaders includes the right alg.
   119  func (v RS256Verifier) Verify(joseHeaders jose.Headers, _, signingInput, signature []byte) error {
   120  	alg, ok := joseHeaders.Algorithm()
   121  	if !ok {
   122  		return errors.New("alg is not defined")
   123  	}
   124  
   125  	if alg != "RS256" {
   126  		return errors.New("alg is not RS256")
   127  	}
   128  
   129  	hash := crypto.SHA256.New()
   130  
   131  	_, err := hash.Write(signingInput)
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	hashed := hash.Sum(nil)
   137  
   138  	return rsa.VerifyPKCS1v15(v.pubKey, crypto.SHA256, hashed, signature)
   139  }
   140  
   141  func verifyEd25519(jws string, pubKey ed25519.PublicKey) error {
   142  	v, err := NewEd25519Verifier(pubKey)
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	sVerifier := jose.NewCompositeAlgSigVerifier(jose.AlgSignatureVerifier{
   148  		Alg:      "EdDSA",
   149  		Verifier: v,
   150  	})
   151  
   152  	token, _, err := Parse(jws, WithSignatureVerifier(sVerifier))
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	if token == nil {
   158  		return errors.New("nil token")
   159  	}
   160  
   161  	return nil
   162  }
   163  
   164  func verifyRS256(jws string, pubKey *rsa.PublicKey) error {
   165  	v := NewRS256Verifier(pubKey)
   166  
   167  	sVerifier := jose.NewCompositeAlgSigVerifier(jose.AlgSignatureVerifier{
   168  		Alg:      "RS256",
   169  		Verifier: v,
   170  	})
   171  
   172  	token, _, err := Parse(jws, WithSignatureVerifier(sVerifier))
   173  	if err != nil {
   174  		return err
   175  	}
   176  
   177  	if token == nil {
   178  		return errors.New("nil token")
   179  	}
   180  
   181  	return nil
   182  }
   183  
   184  func prepareJWSHeaders(headers map[string]interface{}, alg string) map[string]interface{} {
   185  	newHeaders := make(map[string]interface{})
   186  
   187  	for k, v := range headers {
   188  		newHeaders[k] = v
   189  	}
   190  
   191  	newHeaders[jose.HeaderAlgorithm] = alg
   192  
   193  	return newHeaders
   194  }