...

Source file src/github.com/google/certificate-transparency-go/trillian/ctfe/instance.go

Documentation: github.com/google/certificate-transparency-go/trillian/ctfe

     1  // Copyright 2016 Google LLC. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ctfe
    16  
    17  import (
    18  	"context"
    19  	"crypto"
    20  	"crypto/ecdsa"
    21  	"crypto/ed25519"
    22  	"crypto/rsa"
    23  	"errors"
    24  	"fmt"
    25  	"net/http"
    26  	"strconv"
    27  	"strings"
    28  	"time"
    29  
    30  	"github.com/google/certificate-transparency-go/asn1"
    31  	"github.com/google/certificate-transparency-go/schedule"
    32  	"github.com/google/certificate-transparency-go/trillian/util"
    33  	"github.com/google/certificate-transparency-go/x509"
    34  	"github.com/google/certificate-transparency-go/x509util"
    35  	"github.com/google/trillian"
    36  	"github.com/google/trillian/crypto/keys"
    37  	"github.com/google/trillian/monitoring"
    38  	"k8s.io/klog/v2"
    39  )
    40  
    41  // InstanceOptions describes the options for a log instance.
    42  type InstanceOptions struct {
    43  	// Validated holds the original configuration options for the log, and some
    44  	// of its fields parsed as a result of validating it.
    45  	Validated *ValidatedLogConfig
    46  	// Client is a corresponding Trillian log client.
    47  	Client trillian.TrillianLogClient
    48  	// Deadline is a timeout for Trillian RPC requests.
    49  	Deadline time.Duration
    50  	// MetricFactory allows creating metrics.
    51  	MetricFactory monitoring.MetricFactory
    52  	// ErrorMapper converts an error from an RPC request to an HTTP status, plus
    53  	// a boolean to indicate whether the conversion succeeded.
    54  	ErrorMapper func(error) (int, bool)
    55  	// RequestLog provides structured logging of CTFE requests.
    56  	RequestLog RequestLog
    57  	// RemoteUser returns a string representing the originating host for the
    58  	// given request. This string will be used as a User quota key.
    59  	// If unset, no quota will be requested for remote users.
    60  	RemoteQuotaUser func(*http.Request) string
    61  	// CertificateQuotaUser returns a string representing the passed in
    62  	// intermediate certificate. This string will be user as a User quota key for
    63  	// the cert. Quota will be requested for each intermediate in an
    64  	// add-[pre]-chain request so as to allow individual issuers to be rate
    65  	// limited. If unset, no quota will be requested for intermediate
    66  	// certificates.
    67  	CertificateQuotaUser func(*x509.Certificate) string
    68  	// STHStorage provides STHs of a source log for the mirror. Only mirror
    69  	// instances will use it, i.e. when IsMirror == true in the config. If it is
    70  	// empty then the DefaultMirrorSTHStorage will be used.
    71  	STHStorage MirrorSTHStorage
    72  	// MaskInternalErrors indicates if internal server errors should be masked
    73  	// or returned to the user containing the full error message.
    74  	MaskInternalErrors bool
    75  }
    76  
    77  // Instance is a set up log/mirror instance. It must be created with the
    78  // SetUpInstance call.
    79  type Instance struct {
    80  	Handlers  PathHandlers
    81  	STHGetter STHGetter
    82  	li        *logInfo
    83  }
    84  
    85  // RunUpdateSTH regularly updates the Instance STH so our metrics stay
    86  // up-to-date with any tree head changes that are not triggered by us.
    87  func (i *Instance) RunUpdateSTH(ctx context.Context, period time.Duration) {
    88  	c := i.li.instanceOpts.Validated.Config
    89  	klog.Infof("Start internal get-sth operations on %v (%d)", c.Prefix, c.LogId)
    90  	schedule.Every(ctx, period, func(ctx context.Context) {
    91  		klog.V(1).Infof("Force internal get-sth for %v (%d)", c.Prefix, c.LogId)
    92  		if _, err := i.li.getSTH(ctx); err != nil {
    93  			klog.Warningf("Failed to retrieve STH for %v (%d): %v", c.Prefix, c.LogId, err)
    94  		}
    95  	})
    96  }
    97  
    98  // GetPublicKey returns the public key from the instance's signer.
    99  func (i *Instance) GetPublicKey() crypto.PublicKey {
   100  	if i.li != nil && i.li.signer != nil {
   101  		return i.li.signer.Public()
   102  	}
   103  	return nil
   104  }
   105  
   106  // SetUpInstance sets up a log (or log mirror) instance using the provided
   107  // configuration, and returns an object containing a set of handlers for this
   108  // log, and an STH getter.
   109  func SetUpInstance(ctx context.Context, opts InstanceOptions) (*Instance, error) {
   110  	logInfo, err := setUpLogInfo(ctx, opts)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	handlers := logInfo.Handlers(opts.Validated.Config.Prefix)
   115  	return &Instance{Handlers: handlers, STHGetter: logInfo.sthGetter, li: logInfo}, nil
   116  }
   117  
   118  func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) {
   119  	vCfg := opts.Validated
   120  	cfg := vCfg.Config
   121  
   122  	// Check config validity.
   123  	if !cfg.IsMirror && len(cfg.RootsPemFile) == 0 {
   124  		return nil, errors.New("need to specify RootsPemFile")
   125  	}
   126  	// Load the trusted roots.
   127  	roots := x509util.NewPEMCertPool()
   128  	for _, pemFile := range cfg.RootsPemFile {
   129  		if err := roots.AppendCertsFromPEMFile(pemFile); err != nil {
   130  			return nil, fmt.Errorf("failed to read trusted roots: %v", err)
   131  		}
   132  	}
   133  
   134  	var signer crypto.Signer
   135  	if !cfg.IsMirror {
   136  		var err error
   137  		if signer, err = keys.NewSigner(ctx, vCfg.PrivKey); err != nil {
   138  			return nil, fmt.Errorf("failed to load private key: %v", err)
   139  		}
   140  
   141  		// If a public key has been configured for a log, check that it is consistent with the private key.
   142  		if vCfg.PubKey != nil {
   143  			switch pub := vCfg.PubKey.(type) {
   144  			case *ecdsa.PublicKey:
   145  				if !pub.Equal(signer.Public()) {
   146  					return nil, errors.New("public key is not consistent with private key")
   147  				}
   148  			case ed25519.PublicKey:
   149  				if !pub.Equal(signer.Public()) {
   150  					return nil, errors.New("public key is not consistent with private key")
   151  				}
   152  			case *rsa.PublicKey:
   153  				if !pub.Equal(signer.Public()) {
   154  					return nil, errors.New("public key is not consistent with private key")
   155  				}
   156  			default:
   157  				return nil, errors.New("failed to verify consistency of public key with private key")
   158  			}
   159  		}
   160  	}
   161  
   162  	validationOpts := CertValidationOpts{
   163  		trustedRoots:    roots,
   164  		rejectExpired:   cfg.RejectExpired,
   165  		rejectUnexpired: cfg.RejectUnexpired,
   166  		notAfterStart:   vCfg.NotAfterStart,
   167  		notAfterLimit:   vCfg.NotAfterLimit,
   168  		acceptOnlyCA:    cfg.AcceptOnlyCa,
   169  		extKeyUsages:    vCfg.KeyUsages,
   170  	}
   171  	var err error
   172  	validationOpts.rejectExtIds, err = parseOIDs(cfg.RejectExtensions)
   173  	if err != nil {
   174  		return nil, fmt.Errorf("failed to parse RejectExtensions: %v", err)
   175  	}
   176  
   177  	logInfo := newLogInfo(opts, validationOpts, signer, new(util.SystemTimeSource))
   178  	return logInfo, nil
   179  }
   180  
   181  func parseOIDs(oids []string) ([]asn1.ObjectIdentifier, error) {
   182  	ret := make([]asn1.ObjectIdentifier, 0, len(oids))
   183  	for _, s := range oids {
   184  		bits := strings.Split(s, ".")
   185  		var oid asn1.ObjectIdentifier
   186  		for _, n := range bits {
   187  			p, err := strconv.Atoi(n)
   188  			if err != nil {
   189  				return nil, err
   190  			}
   191  			oid = append(oid, p)
   192  		}
   193  		ret = append(ret, oid)
   194  	}
   195  	return ret, nil
   196  }
   197  

View as plain text