| /*- |
| * Copyright 2018 Square Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package cryptosigner |
| |
| import ( |
| "bytes" |
| "crypto" |
| "crypto/ecdsa" |
| "crypto/elliptic" |
| "crypto/rand" |
| "crypto/rsa" |
| "fmt" |
| "testing" |
| |
| "golang.org/x/crypto/ed25519" |
| "gopkg.in/square/go-jose.v2" |
| ) |
| |
| func TestRoundtripsJWSCryptoSigner(t *testing.T) { |
| sigAlgs := []jose.SignatureAlgorithm{jose.RS256, jose.RS384, jose.RS512, jose.PS256, jose.PS384, jose.PS512, jose.ES256, jose.ES384, jose.ES512, jose.EdDSA} |
| |
| serializers := []func(*jose.JSONWebSignature) (string, error){ |
| func(obj *jose.JSONWebSignature) (string, error) { return obj.CompactSerialize() }, |
| func(obj *jose.JSONWebSignature) (string, error) { return obj.FullSerialize(), nil }, |
| } |
| |
| for _, alg := range sigAlgs { |
| signingKey, verificationKey := generateSigningTestKey(alg) |
| |
| for i, serializer := range serializers { |
| err := roundtripJWS(alg, serializer, Opaque(signingKey.(crypto.Signer)), verificationKey) |
| if err != nil { |
| t.Error(err, alg, i) |
| } |
| } |
| } |
| } |
| |
| type staticNonceSource string |
| |
| func (sns staticNonceSource) Nonce() (string, error) { |
| return string(sns), nil |
| } |
| |
| func roundtripJWS(sigAlg jose.SignatureAlgorithm, serializer func(*jose.JSONWebSignature) (string, error), signingKey interface{}, verificationKey interface{}) error { |
| nonce := "test_nonce" |
| opts := &jose.SignerOptions{ |
| NonceSource: staticNonceSource(nonce), |
| } |
| |
| signer, err := jose.NewSigner(jose.SigningKey{Algorithm: sigAlg, Key: signingKey}, opts) |
| if err != nil { |
| return fmt.Errorf("error on new signer: %s", err) |
| } |
| |
| input := []byte("Lorem ipsum dolor sit amet") |
| obj, err := signer.Sign(input) |
| if err != nil { |
| return fmt.Errorf("error on sign: %s", err) |
| } |
| |
| msg, err := serializer(obj) |
| if err != nil { |
| return fmt.Errorf("error on serialize: %s", err) |
| } |
| |
| obj, err = jose.ParseSigned(msg) |
| if err != nil { |
| return fmt.Errorf("error on parse: %s", err) |
| } |
| |
| output, err := obj.Verify(verificationKey) |
| if err != nil { |
| return fmt.Errorf("error on verify: %s", err) |
| } |
| |
| // Check that verify works with embedded keys (if present) |
| for i, sig := range obj.Signatures { |
| if sig.Header.JSONWebKey != nil { |
| _, err = obj.Verify(sig.Header.JSONWebKey) |
| if err != nil { |
| return fmt.Errorf("error on verify with embedded key %d: %s", i, err) |
| } |
| } |
| |
| // Check that the nonce correctly round-tripped (if present) |
| if sig.Header.Nonce != nonce { |
| return fmt.Errorf("Incorrect nonce returned: [%s]", sig.Header.Nonce) |
| } |
| } |
| |
| if bytes.Compare(output, input) != 0 { |
| return fmt.Errorf("input/output do not match, got '%s', expected '%s'", output, input) |
| } |
| |
| return nil |
| } |
| |
| func generateSigningTestKey(sigAlg jose.SignatureAlgorithm) (sig, ver interface{}) { |
| switch sigAlg { |
| case jose.EdDSA: |
| ver, sig, _ = ed25519.GenerateKey(rand.Reader) |
| case jose.RS256, jose.RS384, jose.RS512, jose.PS256, jose.PS384, jose.PS512: |
| rsaTestKey, _ := rsa.GenerateKey(rand.Reader, 2048) |
| sig = rsaTestKey |
| ver = &rsaTestKey.PublicKey |
| case jose.ES256: |
| key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) |
| sig = key |
| ver = &key.PublicKey |
| case jose.ES384: |
| key, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) |
| sig = key |
| ver = &key.PublicKey |
| case jose.ES512: |
| key, _ := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) |
| sig = key |
| ver = &key.PublicKey |
| default: |
| panic("Must update test case") |
| } |
| return |
| } |