pkg/sdk/value/signature/raw/transformer.go (152 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you 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 raw import ( "context" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/sha256" "crypto/sha512" "errors" "fmt" "hash" "math/big" "github.com/elastic/harp/pkg/sdk/security/crypto/rfc6979" "github.com/elastic/harp/pkg/sdk/types" "github.com/elastic/harp/pkg/sdk/value/signature" ) type rawTransformer struct { key interface{} } // ----------------------------------------------------------------------------- func (d *rawTransformer) To(ctx context.Context, input []byte) ([]byte, error) { if types.IsNil(d.key) { return nil, fmt.Errorf("paseto: signer key must not be nil") } var ( sig []byte err error ) switch sk := d.key.(type) { case ed25519.PrivateKey: // Ed25519 doesn't support pre-hash as input to prevent collision. sig = ed25519.Sign(sk, input) case *ecdsa.PrivateKey: var digest []byte // Get hash function for curve hf, errHash := d.hashFromCurve(sk.Curve) if errHash != nil { return nil, fmt.Errorf("raw: unable to retrieve hash function for curve: %w", errHash) } // Build a hash function instance h := hf() // Input is already a hash? if signature.IsInputPreHashed(ctx) { digest = input if len(digest) != h.Size() { return nil, fmt.Errorf("raw: invalid pre-hash length, expected %d bytes, got %d", h.Size(), len(input)) } } else { // Hash the decoded content h.Write(input) // Set hash value digest = h.Sum(nil) } var ( errSig error r, s *big.Int ) if signature.IsDeterministic(ctx) { // Deterministic signature r, s = rfc6979.SignECDSA(sk, digest, hf) if r == nil { errSig = errors.New("unable to apply determistic signature") } } else { // Sign r, s, errSig = ecdsa.Sign(rand.Reader, sk, digest) } if errSig != nil { return nil, fmt.Errorf("raw: unable to sign the content: %w", errSig) } // Calculate optimized buffer size curveBits := sk.Curve.Params().BitSize keyBytes := curveBits / 8 if curveBits%8 > 0 { keyBytes++ } // We serialize the outputs (r and s) into big-endian byte arrays and pad // them with zeros on the left to make sure the sizes work out. Both arrays // must be keyBytes long, and the output must be 2*keyBytes long. rBytes := r.Bytes() rBytesPadded := make([]byte, keyBytes) copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) sBytes := s.Bytes() sBytesPadded := make([]byte, keyBytes) copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) // Assemble the signature sig = rBytesPadded sig = append(sig, sBytesPadded...) default: return nil, errors.New("raw: key is not supported") } if err != nil { return nil, fmt.Errorf("raw: unable to sign input: %w", err) } // Detached signature requested? if signature.IsDetached(ctx) { return sig, nil } // No error return append(sig, input...), nil } func (d *rawTransformer) From(ctx context.Context, input []byte) ([]byte, error) { switch sk := d.key.(type) { case ed25519.PublicKey: // Ed25519 doesn't support pre-hash as input to prevent collision. if ed25519.Verify(sk, input[ed25519.SignatureSize:], input[:ed25519.SignatureSize]) { return input[ed25519.SignatureSize:], nil } case *ecdsa.PublicKey: // Extract signature pkLen, err := d.privateKeySizeFromCurve(sk.Curve) if err != nil { return nil, fmt.Errorf("raw: unable to retrieve private key length: %w", err) } // Check minimal input length if len(input) < 2*pkLen { return nil, errors.New("raw: too short signature") } // Get hash function for curve hf, err := d.hashFromCurve(sk.Curve) if err != nil { return nil, fmt.Errorf("raw: unable to retrieve hash function for curve: %w", err) } // Build a hash function instance h := hf() var digest []byte // Input is already a hash? if signature.IsInputPreHashed(ctx) { digest = input[2*pkLen:] if len(digest) != h.Size() { return nil, fmt.Errorf("invalid pre-hash length, expected %d bytes, got %d bytes", h.Size(), len(digest)) } } else { // Hash the decoded content h.Write(input[2*pkLen:]) // Set hash value digest = h.Sum(nil) } // Extract sig sig := input[:2*pkLen] // Unpack signature var ( r = new(big.Int).SetBytes(sig[:pkLen]) s = new(big.Int).SetBytes(sig[pkLen:]) ) // Validate signature if ecdsa.Verify(sk, digest, r, s) { return input[2*pkLen:], nil } default: return nil, errors.New("raw: key is not supported") } // Default to error return nil, errors.New("raw: unable to validate input signature") } // ----------------------------------------------------------------------------- func (d *rawTransformer) hashFromCurve(curve elliptic.Curve) (func() hash.Hash, error) { switch curve { case elliptic.P256(): return sha256.New, nil case elliptic.P384(): return sha512.New384, nil case elliptic.P521(): return sha512.New, nil default: } // Default to error return nil, errors.New("current curve is not supported") } func (d *rawTransformer) privateKeySizeFromCurve(curve elliptic.Curve) (int, error) { switch curve { case elliptic.P256(): return 32, nil case elliptic.P384(): return 48, nil case elliptic.P521(): return 66, nil default: } return 0, errors.New("current curve is not supported") }