| /*- |
| * 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 implements an OpaqueSigner that wraps a "crypto".Signer |
| // |
| // https://godoc.org/crypto#Signer |
| package cryptosigner |
| |
| import ( |
| "crypto" |
| "crypto/ecdsa" |
| "crypto/rand" |
| "crypto/rsa" |
| "encoding/asn1" |
| "io" |
| "math/big" |
| |
| "golang.org/x/crypto/ed25519" |
| "gopkg.in/square/go-jose.v2" |
| ) |
| |
| // Opaque creates an OpaqueSigner from a "crypto".Signer |
| func Opaque(s crypto.Signer) jose.OpaqueSigner { |
| pk := &jose.JSONWebKey{ |
| Key: s.Public(), |
| } |
| return &cryptoSigner{signer: s, rand: rand.Reader, pk: pk} |
| } |
| |
| type cryptoSigner struct { |
| pk *jose.JSONWebKey |
| signer crypto.Signer |
| rand io.Reader |
| } |
| |
| func (s *cryptoSigner) Public() *jose.JSONWebKey { |
| return s.pk |
| } |
| |
| func (s *cryptoSigner) Algs() []jose.SignatureAlgorithm { |
| switch s.signer.Public().(type) { |
| case ed25519.PublicKey: |
| return []jose.SignatureAlgorithm{jose.EdDSA} |
| case *ecdsa.PublicKey: |
| // This could be more precise |
| return []jose.SignatureAlgorithm{jose.ES256, jose.ES384, jose.ES512} |
| case *rsa.PublicKey: |
| return []jose.SignatureAlgorithm{jose.RS256, jose.RS384, jose.RS512, jose.PS256, jose.PS384, jose.PS512} |
| default: |
| return nil |
| } |
| } |
| |
| func (s *cryptoSigner) SignPayload(payload []byte, alg jose.SignatureAlgorithm) ([]byte, error) { |
| var hash crypto.Hash |
| switch alg { |
| case jose.EdDSA: |
| case jose.RS256, jose.PS256, jose.ES256: |
| hash = crypto.SHA256 |
| case jose.RS384, jose.PS384, jose.ES384: |
| hash = crypto.SHA384 |
| case jose.RS512, jose.PS512, jose.ES512: |
| hash = crypto.SHA512 |
| default: |
| return nil, jose.ErrUnsupportedAlgorithm |
| } |
| |
| var hashed []byte |
| if hash != crypto.Hash(0) { |
| hasher := hash.New() |
| if _, err := hasher.Write(payload); err != nil { |
| return nil, err |
| } |
| hashed = hasher.Sum(nil) |
| } |
| |
| var ( |
| out []byte |
| err error |
| ) |
| switch alg { |
| case jose.EdDSA: |
| out, err = s.signer.Sign(s.rand, payload, crypto.Hash(0)) |
| case jose.ES256, jose.ES384, jose.ES512: |
| var byteLen int |
| switch alg { |
| case jose.ES256: |
| byteLen = 32 |
| case jose.ES384: |
| byteLen = 48 |
| case jose.ES512: |
| byteLen = 66 |
| } |
| var b []byte |
| b, err = s.signer.Sign(s.rand, hashed, hash) |
| if err != nil { |
| return nil, err |
| } |
| |
| sig := struct { |
| R, S *big.Int |
| }{} |
| if _, err = asn1.Unmarshal(b, &sig); err != nil { |
| return nil, err |
| } |
| |
| rBytes := sig.R.Bytes() |
| rBytesPadded := make([]byte, byteLen) |
| copy(rBytesPadded[byteLen-len(rBytes):], rBytes) |
| |
| sBytes := sig.S.Bytes() |
| sBytesPadded := make([]byte, byteLen) |
| copy(sBytesPadded[byteLen-len(sBytes):], sBytes) |
| |
| out = append(rBytesPadded, sBytesPadded...) |
| case jose.RS256, jose.RS384, jose.RS512: |
| out, err = s.signer.Sign(s.rand, hashed, hash) |
| case jose.PS256, jose.PS384, jose.PS512: |
| out, err = s.signer.Sign(s.rand, hashed, &rsa.PSSOptions{ |
| SaltLength: rsa.PSSSaltLengthAuto, |
| Hash: hash, |
| }) |
| } |
| return out, err |
| } |