...

Source file src/github.com/sigstore/rekor/pkg/pki/minisign/minisign.go

Documentation: github.com/sigstore/rekor/pkg/pki/minisign

     1  //
     2  // Copyright 2021 The Sigstore Authors.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package minisign
    17  
    18  import (
    19  	"bytes"
    20  	"crypto/ed25519"
    21  	"crypto/sha256"
    22  	"encoding/base64"
    23  	"encoding/hex"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"strings"
    28  
    29  	minisign "github.com/jedisct1/go-minisign"
    30  	"github.com/sigstore/rekor/pkg/pki/identity"
    31  	"github.com/sigstore/sigstore/pkg/cryptoutils"
    32  	sigsig "github.com/sigstore/sigstore/pkg/signature"
    33  	"golang.org/x/crypto/blake2b"
    34  )
    35  
    36  // Signature Signature that follows the minisign standard; supports both minisign and signify generated signatures
    37  type Signature struct {
    38  	signature *minisign.Signature
    39  }
    40  
    41  // NewSignature creates and validates a minisign signature object
    42  func NewSignature(r io.Reader) (*Signature, error) {
    43  	var s Signature
    44  	var inputBuffer bytes.Buffer
    45  
    46  	if _, err := io.Copy(&inputBuffer, r); err != nil {
    47  		return nil, fmt.Errorf("unable to read minisign signature: %w", err)
    48  	}
    49  
    50  	inputString := inputBuffer.String()
    51  	signature, err := minisign.DecodeSignature(inputString)
    52  	if err != nil {
    53  		// try to parse as signify
    54  		lines := strings.Split(strings.TrimRight(inputString, "\n"), "\n")
    55  		if len(lines) != 2 {
    56  			return nil, fmt.Errorf("invalid signature provided: %v lines detected", len(lines))
    57  		}
    58  		sigBytes, b64Err := base64.StdEncoding.DecodeString(lines[1])
    59  		if b64Err != nil {
    60  			return nil, errors.New("invalid signature provided: base64 decoding failed")
    61  		}
    62  		if len(sigBytes) != len(signature.SignatureAlgorithm)+len(signature.KeyId)+len(signature.Signature) {
    63  			return nil, fmt.Errorf("invalid signature provided: incorrect size %v detected", len(sigBytes))
    64  		}
    65  		copy(signature.SignatureAlgorithm[:], sigBytes[0:2])
    66  		copy(signature.KeyId[:], sigBytes[2:10])
    67  		copy(signature.Signature[:], sigBytes[10:])
    68  	}
    69  
    70  	s.signature = &signature
    71  	return &s, nil
    72  }
    73  
    74  // CanonicalValue implements the pki.Signature interface
    75  func (s Signature) CanonicalValue() ([]byte, error) {
    76  	if s.signature == nil {
    77  		return nil, errors.New("minisign signature has not been initialized")
    78  	}
    79  
    80  	buf := bytes.NewBuffer([]byte("untrusted comment:\n"))
    81  	b64Buf := bytes.NewBuffer(s.signature.SignatureAlgorithm[:])
    82  	if _, err := b64Buf.Write(s.signature.KeyId[:]); err != nil {
    83  		return nil, fmt.Errorf("error canonicalizing minisign signature: %w", err)
    84  	}
    85  	if _, err := b64Buf.Write(s.signature.Signature[:]); err != nil {
    86  		return nil, fmt.Errorf("error canonicalizing minisign signature: %w", err)
    87  	}
    88  	if _, err := buf.WriteString(base64.StdEncoding.EncodeToString(b64Buf.Bytes())); err != nil {
    89  		return nil, fmt.Errorf("error canonicalizing minisign signature: %w", err)
    90  	}
    91  	return buf.Bytes(), nil
    92  }
    93  
    94  // Verify implements the pki.Signature interface
    95  func (s Signature) Verify(r io.Reader, k interface{}, opts ...sigsig.VerifyOption) error {
    96  	if s.signature == nil {
    97  		return errors.New("minisign signature has not been initialized")
    98  	}
    99  
   100  	key, ok := k.(*PublicKey)
   101  	if !ok {
   102  		return errors.New("cannot use Verify with a non-minisign key")
   103  	}
   104  	if key.key == nil {
   105  		return errors.New("minisign public key has not been initialized")
   106  	}
   107  
   108  	verifier, err := sigsig.LoadED25519Verifier(key.key.PublicKey[:])
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	prehashed := s.signature.SignatureAlgorithm[1] == 0x44
   114  	if prehashed {
   115  		h, _ := blake2b.New512(nil)
   116  		_, err := io.Copy(h, r)
   117  		if err != nil {
   118  			return errors.New("reading minisign data")
   119  		}
   120  		r = bytes.NewReader(h.Sum(nil))
   121  	}
   122  
   123  	return verifier.VerifySignature(bytes.NewReader(s.signature.Signature[:]), r, opts...)
   124  }
   125  
   126  // PublicKey Public Key that follows the minisign standard; supports signify and minisign public keys
   127  type PublicKey struct {
   128  	key *minisign.PublicKey
   129  }
   130  
   131  // NewPublicKey implements the pki.PublicKey interface
   132  func NewPublicKey(r io.Reader) (*PublicKey, error) {
   133  	var k PublicKey
   134  	var inputBuffer bytes.Buffer
   135  
   136  	if _, err := io.Copy(&inputBuffer, r); err != nil {
   137  		return nil, fmt.Errorf("unable to read minisign public key: %w", err)
   138  	}
   139  
   140  	inputString := inputBuffer.String()
   141  
   142  	// There are three ways a minisign key can be stored.
   143  	// 1. The entire text key
   144  	// 2. A base64 encoded string
   145  	// 3. A legacy format we stored of just the key material (no key ID or Algorithm) due to bug fixed in https://github.com/sigstore/rekor/pull/562
   146  	key, err := minisign.DecodePublicKey(inputString)
   147  	if err == nil {
   148  		k.key = &key
   149  		return &k, nil
   150  	}
   151  	key, err = minisign.NewPublicKey(inputString)
   152  	if err == nil {
   153  		k.key = &key
   154  		return &k, nil
   155  	}
   156  
   157  	if len(inputString) == 32 {
   158  		k.key = &minisign.PublicKey{
   159  			SignatureAlgorithm: [2]byte{'E', 'd'},
   160  			KeyId:              [8]byte{},
   161  		}
   162  		copy(k.key.PublicKey[:], inputBuffer.Bytes())
   163  		return &k, nil
   164  	}
   165  	return nil, fmt.Errorf("unable to read minisign public key: %w", err)
   166  }
   167  
   168  // CanonicalValue implements the pki.PublicKey interface
   169  func (k PublicKey) CanonicalValue() ([]byte, error) {
   170  	if k.key == nil {
   171  		return nil, errors.New("minisign public key has not been initialized")
   172  	}
   173  
   174  	bin := []byte{}
   175  	bin = append(bin, k.key.SignatureAlgorithm[:]...)
   176  	bin = append(bin, k.key.KeyId[:]...)
   177  	bin = append(bin, k.key.PublicKey[:]...)
   178  	b64Key := base64.StdEncoding.EncodeToString(bin)
   179  	return []byte(b64Key), nil
   180  }
   181  
   182  // EmailAddresses implements the pki.PublicKey interface
   183  func (k PublicKey) EmailAddresses() []string {
   184  	return nil
   185  }
   186  
   187  // Subjects implements the pki.PublicKey interface
   188  func (k PublicKey) Subjects() []string {
   189  	return nil
   190  }
   191  
   192  // Identities implements the pki.PublicKey interface
   193  func (k PublicKey) Identities() ([]identity.Identity, error) {
   194  	// PKIX encode ed25519 public key
   195  	pkixKey, err := cryptoutils.MarshalPublicKeyToDER(ed25519.PublicKey(k.key.PublicKey[:]))
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	digest := sha256.Sum256(pkixKey)
   200  	return []identity.Identity{{
   201  		Crypto:      k.key,
   202  		Raw:         pkixKey,
   203  		Fingerprint: hex.EncodeToString(digest[:]),
   204  	}}, nil
   205  }
   206  

View as plain text