...

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

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

     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 x509
    17  
    18  import (
    19  	"bytes"
    20  	"crypto"
    21  	"crypto/sha256"
    22  	"crypto/x509"
    23  	"encoding/asn1"
    24  	"encoding/hex"
    25  	"encoding/pem"
    26  	"errors"
    27  	"fmt"
    28  	"io"
    29  	"strings"
    30  
    31  	"github.com/asaskevich/govalidator"
    32  	"github.com/sigstore/rekor/pkg/pki/identity"
    33  	"github.com/sigstore/sigstore/pkg/cryptoutils"
    34  	sigsig "github.com/sigstore/sigstore/pkg/signature"
    35  )
    36  
    37  // EmailAddressOID defined by https://oidref.com/1.2.840.113549.1.9.1
    38  var EmailAddressOID asn1.ObjectIdentifier = []int{1, 2, 840, 113549, 1, 9, 1}
    39  
    40  type Signature struct {
    41  	signature        []byte
    42  	verifierLoadOpts []sigsig.LoadOption
    43  }
    44  
    45  // NewSignature creates and validates an x509 signature object
    46  func NewSignature(r io.Reader) (*Signature, error) {
    47  	return NewSignatureWithOpts(r)
    48  }
    49  
    50  func NewSignatureWithOpts(r io.Reader, opts ...sigsig.LoadOption) (*Signature, error) {
    51  	b, err := io.ReadAll(r)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	return &Signature{
    56  		signature:        b,
    57  		verifierLoadOpts: opts,
    58  	}, nil
    59  }
    60  
    61  // CanonicalValue implements the pki.Signature interface
    62  func (s Signature) CanonicalValue() ([]byte, error) {
    63  	return s.signature, nil
    64  }
    65  
    66  // Verify implements the pki.Signature interface
    67  func (s Signature) Verify(r io.Reader, k interface{}, opts ...sigsig.VerifyOption) error {
    68  	if len(s.signature) == 0 {
    69  		//lint:ignore ST1005 X509 is proper use of term
    70  		return errors.New("X509 signature has not been initialized")
    71  	}
    72  
    73  	key, ok := k.(*PublicKey)
    74  	if !ok {
    75  		return fmt.Errorf("invalid public key type for: %v", k)
    76  	}
    77  
    78  	p := key.key
    79  	if p == nil {
    80  		switch {
    81  		case key.cert != nil:
    82  			p = key.cert.c.PublicKey
    83  		case len(key.certs) > 0:
    84  			if err := verifyCertChain(key.certs); err != nil {
    85  				return err
    86  			}
    87  			p = key.certs[0].PublicKey
    88  		default:
    89  			return errors.New("no public key found")
    90  		}
    91  	}
    92  
    93  	verifier, err := sigsig.LoadVerifierWithOpts(p, s.verifierLoadOpts...)
    94  	if err != nil {
    95  		return err
    96  	}
    97  	return verifier.VerifySignature(bytes.NewReader(s.signature), r, opts...)
    98  }
    99  
   100  // PublicKey Public Key that follows the x509 standard
   101  type PublicKey struct {
   102  	key   interface{}
   103  	cert  *cert
   104  	certs []*x509.Certificate
   105  }
   106  
   107  type cert struct {
   108  	c *x509.Certificate
   109  	b []byte
   110  }
   111  
   112  // NewPublicKey implements the pki.PublicKey interface
   113  func NewPublicKey(r io.Reader) (*PublicKey, error) {
   114  	rawPub, err := io.ReadAll(r)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	trimmedRawPub := bytes.TrimSpace(rawPub)
   119  
   120  	block, rest := pem.Decode(trimmedRawPub)
   121  	if block == nil {
   122  		return nil, errors.New("invalid public key: failure decoding PEM")
   123  	}
   124  
   125  	// Handle certificate chain, concatenated PEM-encoded certificates
   126  	if len(rest) > 0 {
   127  		// Support up to 10 certificates in a chain, to avoid parsing extremely long chains
   128  		certs, err := cryptoutils.UnmarshalCertificatesFromPEMLimited(trimmedRawPub, 10)
   129  		if err != nil {
   130  			return nil, err
   131  		}
   132  		return &PublicKey{certs: certs}, nil
   133  	}
   134  
   135  	switch block.Type {
   136  	case string(cryptoutils.PublicKeyPEMType):
   137  		key, err := x509.ParsePKIXPublicKey(block.Bytes)
   138  		if err != nil {
   139  			return nil, err
   140  		}
   141  		return &PublicKey{key: key}, nil
   142  	case string(cryptoutils.CertificatePEMType):
   143  		c, err := x509.ParseCertificate(block.Bytes)
   144  		if err != nil {
   145  			return nil, err
   146  		}
   147  		return &PublicKey{
   148  			cert: &cert{
   149  				c: c,
   150  				b: block.Bytes,
   151  			}}, nil
   152  	}
   153  	return nil, fmt.Errorf("invalid public key: cannot handle type %v", block.Type)
   154  }
   155  
   156  // CanonicalValue implements the pki.PublicKey interface
   157  func (k PublicKey) CanonicalValue() (encoded []byte, err error) {
   158  
   159  	switch {
   160  	case k.key != nil:
   161  		encoded, err = cryptoutils.MarshalPublicKeyToPEM(k.key)
   162  	case k.cert != nil:
   163  		encoded, err = cryptoutils.MarshalCertificateToPEM(k.cert.c)
   164  	case k.certs != nil:
   165  		encoded, err = cryptoutils.MarshalCertificatesToPEM(k.certs)
   166  	default:
   167  		err = errors.New("x509 public key has not been initialized")
   168  	}
   169  
   170  	return
   171  }
   172  
   173  func (k PublicKey) CryptoPubKey() crypto.PublicKey {
   174  	if k.cert != nil {
   175  		return k.cert.c.PublicKey
   176  	}
   177  	if len(k.certs) > 0 {
   178  		return k.certs[0].PublicKey
   179  	}
   180  	return k.key
   181  }
   182  
   183  // EmailAddresses implements the pki.PublicKey interface
   184  func (k PublicKey) EmailAddresses() []string {
   185  	var names []string
   186  	var cert *x509.Certificate
   187  	if k.cert != nil {
   188  		cert = k.cert.c
   189  	} else if len(k.certs) > 0 {
   190  		cert = k.certs[0]
   191  	}
   192  	if cert != nil {
   193  		for _, name := range cert.EmailAddresses {
   194  			if govalidator.IsEmail(name) {
   195  				names = append(names, strings.ToLower(name))
   196  			}
   197  		}
   198  	}
   199  	return names
   200  }
   201  
   202  // Subjects implements the pki.PublicKey interface
   203  func (k PublicKey) Subjects() []string {
   204  	var subjects []string
   205  	var cert *x509.Certificate
   206  	if k.cert != nil {
   207  		cert = k.cert.c
   208  	} else if len(k.certs) > 0 {
   209  		cert = k.certs[0]
   210  	}
   211  	if cert != nil {
   212  		subjects = cryptoutils.GetSubjectAlternateNames(cert)
   213  	}
   214  	return subjects
   215  }
   216  
   217  // Identities implements the pki.PublicKey interface
   218  func (k PublicKey) Identities() ([]identity.Identity, error) {
   219  	// k contains either a key, a cert, or a list of certs
   220  	if k.key != nil {
   221  		pkixKey, err := cryptoutils.MarshalPublicKeyToDER(k.key)
   222  		if err != nil {
   223  			return nil, err
   224  		}
   225  		digest := sha256.Sum256(pkixKey)
   226  		return []identity.Identity{{
   227  			Crypto:      k.key,
   228  			Raw:         pkixKey,
   229  			Fingerprint: hex.EncodeToString(digest[:]),
   230  		}}, nil
   231  	}
   232  
   233  	var cert *x509.Certificate
   234  	switch {
   235  	case k.cert != nil:
   236  		cert = k.cert.c
   237  	case len(k.certs) > 0:
   238  		cert = k.certs[0]
   239  	default:
   240  		return nil, errors.New("no key, certificate or certificate chain provided")
   241  	}
   242  
   243  	digest := sha256.Sum256(cert.Raw)
   244  	return []identity.Identity{{
   245  		Crypto:      cert,
   246  		Raw:         cert.Raw,
   247  		Fingerprint: hex.EncodeToString(digest[:]),
   248  	}}, nil
   249  }
   250  
   251  func verifyCertChain(certChain []*x509.Certificate) error {
   252  	if len(certChain) == 0 {
   253  		return errors.New("no certificate chain provided")
   254  	}
   255  	// No certificate chain to verify
   256  	if len(certChain) == 1 {
   257  		return nil
   258  	}
   259  	rootPool := x509.NewCertPool()
   260  	rootPool.AddCert(certChain[len(certChain)-1])
   261  	subPool := x509.NewCertPool()
   262  	for _, c := range certChain[1 : len(certChain)-1] {
   263  		subPool.AddCert(c)
   264  	}
   265  	if _, err := certChain[0].Verify(x509.VerifyOptions{
   266  		Roots:         rootPool,
   267  		Intermediates: subPool,
   268  		// Allow any key usage
   269  		KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
   270  		// Expired certificates can be uploaded and should be verifiable
   271  		CurrentTime: certChain[0].NotBefore,
   272  	}); err != nil {
   273  		return err
   274  	}
   275  	return nil
   276  }
   277  

View as plain text