...

Source file src/github.com/google/certificate-transparency-go/trillian/ctfe/instance_test.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  	"errors"
    20  	"fmt"
    21  	"net/http/httptest"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	ct "github.com/google/certificate-transparency-go"
    27  	"github.com/google/certificate-transparency-go/trillian/ctfe/configpb"
    28  	"github.com/google/trillian/crypto/keys"
    29  	"github.com/google/trillian/crypto/keys/pem"
    30  	"github.com/google/trillian/crypto/keyspb"
    31  	"github.com/google/trillian/monitoring"
    32  	"google.golang.org/protobuf/types/known/anypb"
    33  	"google.golang.org/protobuf/types/known/timestamppb"
    34  )
    35  
    36  func init() {
    37  	keys.RegisterHandler(&keyspb.PEMKeyFile{}, pem.FromProto)
    38  }
    39  
    40  func TestSetUpInstance(t *testing.T) {
    41  	ctx := context.Background()
    42  
    43  	privKey := mustMarshalAny(&keyspb.PEMKeyFile{Path: "../testdata/ct-http-server.privkey.pem", Password: "dirk"})
    44  	missingPrivKey := mustMarshalAny(&keyspb.PEMKeyFile{Path: "../testdata/bogus.privkey.pem", Password: "dirk"})
    45  	wrongPassPrivKey := mustMarshalAny(&keyspb.PEMKeyFile{Path: "../testdata/ct-http-server.privkey.pem", Password: "dirkly"})
    46  	pubKey := mustReadPublicKey("../testdata/ct-http-server.pubkey.pem")
    47  
    48  	var tests = []struct {
    49  		desc    string
    50  		cfg     *configpb.LogConfig
    51  		wantErr string
    52  	}{
    53  		{
    54  			desc: "valid",
    55  			cfg: &configpb.LogConfig{
    56  				LogId:        1,
    57  				Prefix:       "log",
    58  				RootsPemFile: []string{"../testdata/fake-ca.cert"},
    59  				PrivateKey:   privKey,
    60  			},
    61  		},
    62  		{
    63  			desc: "valid-mirror",
    64  			cfg: &configpb.LogConfig{
    65  				LogId:        1,
    66  				Prefix:       "log",
    67  				RootsPemFile: []string{"../testdata/fake-ca.cert"},
    68  				PublicKey:    pubKey,
    69  				IsMirror:     true,
    70  			},
    71  		},
    72  		{
    73  			desc: "no-roots",
    74  			cfg: &configpb.LogConfig{
    75  				LogId:      1,
    76  				Prefix:     "log",
    77  				PrivateKey: privKey,
    78  			},
    79  			wantErr: "specify RootsPemFile",
    80  		},
    81  		{
    82  			desc: "no-roots-mirror",
    83  			cfg: &configpb.LogConfig{
    84  				LogId:     1,
    85  				Prefix:    "log",
    86  				PublicKey: pubKey,
    87  				IsMirror:  true,
    88  			},
    89  		},
    90  		{
    91  			desc: "missing-root-cert",
    92  			cfg: &configpb.LogConfig{
    93  				LogId:        1,
    94  				Prefix:       "log",
    95  				RootsPemFile: []string{"../testdata/bogus.cert"},
    96  				PrivateKey:   privKey,
    97  			},
    98  			wantErr: "failed to read trusted roots",
    99  		},
   100  		{
   101  			desc: "missing-privkey",
   102  			cfg: &configpb.LogConfig{
   103  				LogId:        1,
   104  				Prefix:       "log",
   105  				RootsPemFile: []string{"../testdata/fake-ca.cert"},
   106  				PrivateKey:   missingPrivKey,
   107  			},
   108  			wantErr: "failed to load private key",
   109  		},
   110  		{
   111  			desc: "privkey-wrong-password",
   112  			cfg: &configpb.LogConfig{
   113  				LogId:        1,
   114  				Prefix:       "log",
   115  				RootsPemFile: []string{"../testdata/fake-ca.cert"},
   116  				PrivateKey:   wrongPassPrivKey,
   117  			},
   118  			wantErr: "failed to load private key",
   119  		},
   120  		{
   121  			desc: "valid-ekus-1",
   122  			cfg: &configpb.LogConfig{
   123  				LogId:        1,
   124  				Prefix:       "log",
   125  				RootsPemFile: []string{"../testdata/fake-ca.cert"},
   126  				PrivateKey:   privKey,
   127  				ExtKeyUsages: []string{"Any"},
   128  			},
   129  		},
   130  		{
   131  			desc: "valid-ekus-2",
   132  			cfg: &configpb.LogConfig{
   133  				LogId:        1,
   134  				Prefix:       "log",
   135  				RootsPemFile: []string{"../testdata/fake-ca.cert"},
   136  				PrivateKey:   privKey,
   137  				ExtKeyUsages: []string{"Any", "ServerAuth", "TimeStamping"},
   138  			},
   139  		},
   140  		{
   141  			desc: "valid-reject-ext",
   142  			cfg: &configpb.LogConfig{
   143  				LogId:            1,
   144  				Prefix:           "log",
   145  				RootsPemFile:     []string{"../testdata/fake-ca.cert"},
   146  				PrivateKey:       privKey,
   147  				RejectExtensions: []string{"1.2.3.4", "5.6.7.8"},
   148  			},
   149  		},
   150  		{
   151  			desc: "invalid-reject-ext",
   152  			cfg: &configpb.LogConfig{
   153  				LogId:            1,
   154  				Prefix:           "log",
   155  				RootsPemFile:     []string{"../testdata/fake-ca.cert"},
   156  				PrivateKey:       privKey,
   157  				RejectExtensions: []string{"1.2.3.4", "one.banana.two.bananas"},
   158  			},
   159  			wantErr: "one",
   160  		},
   161  	}
   162  
   163  	for _, test := range tests {
   164  		t.Run(test.desc, func(t *testing.T) {
   165  			vCfg, err := ValidateLogConfig(test.cfg)
   166  			if err != nil {
   167  				t.Fatalf("ValidateLogConfig(): %v", err)
   168  			}
   169  			opts := InstanceOptions{Validated: vCfg, Deadline: time.Second, MetricFactory: monitoring.InertMetricFactory{}}
   170  
   171  			if _, err := SetUpInstance(ctx, opts); err != nil {
   172  				if test.wantErr == "" {
   173  					t.Errorf("SetUpInstance()=_,%v; want _,nil", err)
   174  				} else if !strings.Contains(err.Error(), test.wantErr) {
   175  					t.Errorf("SetUpInstance()=_,%v; want err containing %q", err, test.wantErr)
   176  				}
   177  				return
   178  			}
   179  			if test.wantErr != "" {
   180  				t.Errorf("SetUpInstance()=_,nil; want err containing %q", test.wantErr)
   181  			}
   182  		})
   183  	}
   184  }
   185  
   186  func equivalentTimes(a *time.Time, b *timestamppb.Timestamp) bool {
   187  	if a == nil && b == nil {
   188  		return true
   189  	}
   190  	if a == nil {
   191  		// b can't be nil as it would have returned above.
   192  		return false
   193  	}
   194  	tsA := timestamppb.New(*a)
   195  	return tsA.AsTime().Format(time.RFC3339Nano) == b.AsTime().Format(time.RFC3339Nano)
   196  }
   197  
   198  func TestSetUpInstanceSetsValidationOpts(t *testing.T) {
   199  	ctx := context.Background()
   200  
   201  	start := timestamppb.New(time.Unix(10000, 0))
   202  	limit := timestamppb.New(time.Unix(12000, 0))
   203  
   204  	privKey, err := anypb.New(&keyspb.PEMKeyFile{Path: "../testdata/ct-http-server.privkey.pem", Password: "dirk"})
   205  	if err != nil {
   206  		t.Fatalf("Could not marshal private key proto: %v", err)
   207  	}
   208  	var tests = []struct {
   209  		desc string
   210  		cfg  *configpb.LogConfig
   211  	}{
   212  		{
   213  			desc: "no validation opts",
   214  			cfg: &configpb.LogConfig{
   215  				LogId:        1,
   216  				Prefix:       "/log",
   217  				RootsPemFile: []string{"../testdata/fake-ca.cert"},
   218  				PrivateKey:   privKey,
   219  			},
   220  		},
   221  		{
   222  			desc: "notAfterStart only",
   223  			cfg: &configpb.LogConfig{
   224  				LogId:         1,
   225  				Prefix:        "/log",
   226  				RootsPemFile:  []string{"../testdata/fake-ca.cert"},
   227  				PrivateKey:    privKey,
   228  				NotAfterStart: start,
   229  			},
   230  		},
   231  		{
   232  			desc: "notAfter range",
   233  			cfg: &configpb.LogConfig{
   234  				LogId:         1,
   235  				Prefix:        "/log",
   236  				RootsPemFile:  []string{"../testdata/fake-ca.cert"},
   237  				PrivateKey:    privKey,
   238  				NotAfterStart: start,
   239  				NotAfterLimit: limit,
   240  			},
   241  		},
   242  		{
   243  			desc: "caOnly",
   244  			cfg: &configpb.LogConfig{
   245  				LogId:        1,
   246  				Prefix:       "/log",
   247  				RootsPemFile: []string{"../testdata/fake-ca.cert"},
   248  				PrivateKey:   privKey,
   249  				AcceptOnlyCa: true,
   250  			},
   251  		},
   252  	}
   253  
   254  	for _, test := range tests {
   255  		t.Run(test.desc, func(t *testing.T) {
   256  			vCfg, err := ValidateLogConfig(test.cfg)
   257  			if err != nil {
   258  				t.Fatalf("ValidateLogConfig(): %v", err)
   259  			}
   260  			opts := InstanceOptions{Validated: vCfg, Deadline: time.Second, MetricFactory: monitoring.InertMetricFactory{}}
   261  
   262  			inst, err := SetUpInstance(ctx, opts)
   263  			if err != nil {
   264  				t.Fatalf("%v: SetUpInstance() = %v, want no error", test.desc, err)
   265  			}
   266  			addChainHandler, ok := inst.Handlers[test.cfg.Prefix+ct.AddChainPath]
   267  			if !ok {
   268  				t.Fatal("Couldn't find AddChain handler")
   269  			}
   270  			gotOpts := addChainHandler.Info.validationOpts
   271  			if got, want := gotOpts.notAfterStart, test.cfg.NotAfterStart; want != nil && !equivalentTimes(got, want) {
   272  				t.Errorf("%v: handler notAfterStart %v, want %v", test.desc, got, want)
   273  			}
   274  			if got, want := gotOpts.notAfterLimit, test.cfg.NotAfterLimit; want != nil && !equivalentTimes(got, want) {
   275  				t.Errorf("%v: handler notAfterLimit %v, want %v", test.desc, got, want)
   276  			}
   277  			if got, want := gotOpts.acceptOnlyCA, test.cfg.AcceptOnlyCa; got != want {
   278  				t.Errorf("%v: handler acceptOnlyCA %v, want %v", test.desc, got, want)
   279  			}
   280  		})
   281  	}
   282  }
   283  
   284  func TestErrorMasking(t *testing.T) {
   285  	info := logInfo{}
   286  	w := httptest.NewRecorder()
   287  	prefix := "Internal Server Error"
   288  	err := errors.New("well that's bad")
   289  	info.SendHTTPError(w, 500, err)
   290  	if got, want := w.Body.String(), fmt.Sprintf("%s\n%v\n", prefix, err); got != want {
   291  		t.Errorf("SendHTTPError: got %s, want %s", got, want)
   292  	}
   293  	info.instanceOpts.MaskInternalErrors = true
   294  	w = httptest.NewRecorder()
   295  	info.SendHTTPError(w, 500, err)
   296  	if got, want := w.Body.String(), prefix+"\n"; got != want {
   297  		t.Errorf("SendHTTPError: got %s, want %s", got, want)
   298  	}
   299  
   300  }
   301  

View as plain text