...

Source file src/github.com/google/certificate-transparency-go/fixchain/fix_and_log_test.go

Documentation: github.com/google/certificate-transparency-go/fixchain

     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 fixchain
    16  
    17  import (
    18  	"context"
    19  	"net/http"
    20  	"strings"
    21  	"sync"
    22  	"testing"
    23  
    24  	"github.com/google/certificate-transparency-go/client"
    25  	"github.com/google/certificate-transparency-go/jsonclient"
    26  	"github.com/google/certificate-transparency-go/x509"
    27  )
    28  
    29  var newFixAndLogTests = []fixAndLogTest{
    30  	// Tests that add chains to the FixAndLog one at a time using QueueChain()
    31  	{ // Full chain successfully logged.
    32  		url:   "https://ct.googleapis.com/pilot",
    33  		chain: []string{googleLeaf, thawteIntermediate, verisignRoot},
    34  
    35  		function: "QueueChain",
    36  		expLoggedChains: [][]string{
    37  			{"Google", "Thawte", "VeriSign"},
    38  		},
    39  	},
    40  	{ // Chain without the root successfully logged.
    41  		url:   "https://ct.googleapis.com/pilot",
    42  		chain: []string{googleLeaf, thawteIntermediate},
    43  
    44  		function: "QueueChain",
    45  		expLoggedChains: [][]string{
    46  			{"Google", "Thawte", "VeriSign"},
    47  		},
    48  	},
    49  	{ // Chain to wrong root results in error.
    50  		url:   "https://ct.googleapis.com/pilot",
    51  		chain: []string{megaLeaf, comodoIntermediate, comodoRoot},
    52  
    53  		function:     "QueueChain",
    54  		expectedErrs: []errorType{VerifyFailed, FixFailed},
    55  	},
    56  	{ // Chain without correct root containing loop results in error.
    57  		url:   "https://ct.googleapis.com/pilot",
    58  		chain: []string{testC, testB, testA},
    59  
    60  		function:     "QueueChain",
    61  		expectedErrs: []errorType{VerifyFailed, FixFailed},
    62  	},
    63  	{ // Incomplete chain successfully logged.
    64  		url:   "https://ct.googleapis.com/pilot",
    65  		chain: []string{googleLeaf},
    66  
    67  		function: "QueueChain",
    68  		expLoggedChains: [][]string{
    69  			{"Google", "Thawte", "VeriSign"},
    70  		},
    71  		expectedErrs: []errorType{VerifyFailed},
    72  	},
    73  	{
    74  		url:   "https://ct.googleapis.com/pilot",
    75  		chain: []string{testLeaf},
    76  
    77  		function: "QueueChain",
    78  		expLoggedChains: [][]string{
    79  			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
    80  		},
    81  		expectedErrs: []errorType{VerifyFailed},
    82  	},
    83  	{ // Garbled chain (with a leaf that has no chain to our roots) results in an error.
    84  		url:   "https://ct.googleapis.com/pilot",
    85  		chain: []string{megaLeaf, googleLeaf, thawteIntermediate, verisignRoot},
    86  
    87  		function:     "QueueChain",
    88  		expectedErrs: []errorType{VerifyFailed, FixFailed},
    89  	},
    90  	{ // Garbled chain (with a leaf that has a chain to our roots) successfully logged.
    91  		url:   "https://ct.googleapis.com/pilot",
    92  		chain: []string{testLeaf, megaLeaf, googleLeaf, thawteIntermediate, comodoRoot},
    93  
    94  		function: "QueueChain",
    95  		expLoggedChains: [][]string{
    96  			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
    97  		},
    98  		expectedErrs: []errorType{VerifyFailed},
    99  	},
   100  	// Tests that add chains to the FixAndLog using QueueAllCertsInChain()
   101  	{ // Full chain successfully logged.
   102  		url:   "https://ct.googleapis.com/pilot",
   103  		chain: []string{googleLeaf, thawteIntermediate, verisignRoot},
   104  
   105  		function: "QueueAllCertsInChain",
   106  		expLoggedChains: [][]string{
   107  			{"Google", "Thawte", "VeriSign"},
   108  			{"Thawte", "VeriSign"},
   109  			{"VeriSign"},
   110  		},
   111  	},
   112  	{
   113  		url:   "https://ct.googleapis.com/pilot",
   114  		chain: []string{googleLeaf, thawteIntermediate},
   115  
   116  		function: "QueueAllCertsInChain",
   117  		expLoggedChains: [][]string{
   118  			{"Google", "Thawte", "VeriSign"},
   119  			{"Thawte", "VeriSign"},
   120  		},
   121  	},
   122  	{ // Chain to wrong root results errors.
   123  		url:   "https://ct.googleapis.com/pilot",
   124  		chain: []string{megaLeaf, comodoIntermediate, comodoRoot},
   125  
   126  		function: "QueueAllCertsInChain",
   127  		expectedErrs: []errorType{
   128  			VerifyFailed, FixFailed,
   129  			VerifyFailed, FixFailed,
   130  			VerifyFailed, FixFailed,
   131  		},
   132  	},
   133  	{ // Chain without correct root containing loop results in error.
   134  		url:   "https://ct.googleapis.com/pilot",
   135  		chain: []string{testC, testB, testA},
   136  
   137  		function: "QueueAllCertsInChain",
   138  		expectedErrs: []errorType{
   139  			VerifyFailed, FixFailed,
   140  			VerifyFailed, FixFailed,
   141  			VerifyFailed, FixFailed,
   142  		},
   143  	},
   144  	{ // Incomplete chain successfully logged.
   145  		url:   "https://ct.googleapis.com/pilot",
   146  		chain: []string{googleLeaf},
   147  
   148  		function: "QueueAllCertsInChain",
   149  		expLoggedChains: [][]string{
   150  			{"Google", "Thawte", "VeriSign"},
   151  		},
   152  		expectedErrs: []errorType{VerifyFailed},
   153  	},
   154  	{
   155  		url:   "https://ct.googleapis.com/pilot",
   156  		chain: []string{testLeaf},
   157  
   158  		function: "QueueAllCertsInChain",
   159  		expLoggedChains: [][]string{
   160  			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
   161  		},
   162  		expectedErrs: []errorType{VerifyFailed},
   163  	},
   164  	{ // Garbled chain (with a leaf that has no chain to our roots)
   165  		url:   "https://ct.googleapis.com/pilot",
   166  		chain: []string{megaLeaf, googleLeaf, thawteIntermediate, verisignRoot},
   167  
   168  		function: "QueueAllCertsInChain",
   169  		expLoggedChains: [][]string{
   170  			{"Google", "Thawte", "VeriSign"},
   171  			{"Thawte", "VeriSign"},
   172  			{"VeriSign"},
   173  		},
   174  		expectedErrs: []errorType{
   175  			VerifyFailed, FixFailed,
   176  		},
   177  	},
   178  	{ // Garbled chain (with a leaf that has a chain to our roots)
   179  		url:   "https://ct.googleapis.com/pilot",
   180  		chain: []string{testLeaf, megaLeaf, googleLeaf, thawteIntermediate, comodoRoot},
   181  
   182  		function: "QueueAllCertsInChain",
   183  		expLoggedChains: [][]string{
   184  			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
   185  			{"Google", "Thawte", "VeriSign"},
   186  			{"Thawte", "VeriSign"},
   187  		},
   188  		expectedErrs: []errorType{
   189  			VerifyFailed,
   190  			VerifyFailed, FixFailed,
   191  			VerifyFailed, FixFailed,
   192  		},
   193  	},
   194  }
   195  
   196  func TestNewFixAndLog(t *testing.T) {
   197  	// Test that expected chains are logged when adding a chain using QueueChain()
   198  	ctx := context.Background()
   199  	for i, test := range newFixAndLogTests {
   200  		seen := make([]bool, len(test.expLoggedChains))
   201  		errors := make(chan *FixError)
   202  		c := &http.Client{Transport: &testRoundTripper{t: t, test: &test, testIndex: i, seen: seen}}
   203  		logClient, err := client.New(test.url, c, jsonclient.Options{})
   204  		if err != nil {
   205  			t.Fatalf("failed to create LogClient: %v", err)
   206  		}
   207  		fl := NewFixAndLog(ctx, 1, 1, errors, c, logClient, newNilLimiter(), false)
   208  
   209  		var wg sync.WaitGroup
   210  		wg.Add(1)
   211  		go func() {
   212  			defer wg.Done()
   213  			testErrors(t, i, test.expectedErrs, errors)
   214  		}()
   215  		switch test.function {
   216  		case "QueueChain":
   217  			fl.QueueChain(extractTestChain(t, i, test.chain))
   218  		case "QueueAllCertsInChain":
   219  			fl.QueueAllCertsInChain(extractTestChain(t, i, test.chain))
   220  		}
   221  		fl.Wait()
   222  		close(errors)
   223  		wg.Wait()
   224  
   225  		// Check that no chains that were expected to be logged were not.
   226  		for j, val := range seen {
   227  			if !val {
   228  				t.Errorf("#%d: Expected chain was not logged: %s", i, strings.Join(test.expLoggedChains[j], " -> "))
   229  			}
   230  		}
   231  	}
   232  }
   233  
   234  var fixAndLogQueueTests = []fixAndLogTest{
   235  	{
   236  		url:   "https://ct.googleapis.com/pilot",
   237  		chain: []string{googleLeaf, thawteIntermediate, verisignRoot},
   238  
   239  		expectedCert:  "Google",
   240  		expectedChain: []string{"Google", "Thawte", "VeriSign"},
   241  		expectedRoots: []string{verisignRoot, testRoot},
   242  	},
   243  	{
   244  		url:   "https://ct.googleapis.com/pilot",
   245  		chain: []string{googleLeaf, googleLeaf, thawteIntermediate, verisignRoot},
   246  
   247  		expectedCert:  "Google",
   248  		expectedChain: []string{"Google", "Thawte", "VeriSign"},
   249  		expectedRoots: []string{verisignRoot, testRoot},
   250  	},
   251  	{ // Test passing a nil chain to FixAndLog.QueueChain()
   252  		url: "https://ct.googleapis.com/pilot",
   253  	},
   254  }
   255  
   256  func testQueueAllCertsInChain(t *testing.T, i int, test *fixAndLogTest, fl *FixAndLog) {
   257  	defer fl.wg.Done()
   258  	seen := make([]bool, len(test.expectedChain))
   259  NextToFix:
   260  	for fix := range fl.fixer.toFix {
   261  		// Check fix.chain is the chain that's expected.
   262  		matchTestChain(t, i, test.expectedChain, fix.chain.certs)
   263  		//Check fix.roots are the roots that are expected for the given url.
   264  		matchTestRoots(t, i, test.expectedRoots, fix.roots)
   265  		for j, expCert := range test.expectedChain {
   266  			if seen[j] {
   267  				continue
   268  			}
   269  			if strings.Contains(nameToKey(&fix.cert.Subject), expCert) {
   270  				seen[j] = true
   271  				continue NextToFix
   272  			}
   273  		}
   274  		t.Errorf("#%d: Queued certificate %s was not expected", i, nameToKey(&fix.cert.Subject))
   275  	}
   276  	for j, val := range seen {
   277  		if !val {
   278  			t.Errorf("#%d: Expected certificate %s was not queued", i, test.expectedChain[j])
   279  		}
   280  	}
   281  }
   282  
   283  func TestQueueAllCertsInChain(t *testing.T) {
   284  	ctx := context.Background()
   285  	for i, test := range fixAndLogQueueTests {
   286  		f := &Fixer{toFix: make(chan *toFix)}
   287  		c := &http.Client{Transport: &testRoundTripper{}}
   288  		logClient, err := client.New(test.url, c, jsonclient.Options{})
   289  		if err != nil {
   290  			t.Fatalf("failed to create LogClient: %v", err)
   291  		}
   292  		l := &Logger{
   293  			ctx:           ctx,
   294  			client:        logClient,
   295  			postCertCache: newLockedMap(),
   296  		}
   297  		fl := &FixAndLog{fixer: f, chains: make(chan []*x509.Certificate), logger: l, done: newLockedMap()}
   298  
   299  		fl.wg.Add(1)
   300  		go testQueueAllCertsInChain(t, i, &test, fl)
   301  		fl.QueueAllCertsInChain(extractTestChain(t, i, test.chain))
   302  		fl.Wait()
   303  	}
   304  }
   305  
   306  func testFixAndLogQueueChain(t *testing.T, i int, test *fixAndLogTest, fl *FixAndLog) {
   307  	defer fl.wg.Done()
   308  
   309  	fix, ok := <-fl.fixer.toFix
   310  	if ok {
   311  		// Check fix.cert is the cert that's expected.
   312  		if !strings.Contains(nameToKey(&fix.cert.Subject), test.expectedCert) {
   313  			t.Errorf("#%d: Expected cert does not match queued cert", i)
   314  		}
   315  
   316  		// Check fix.chain is the chain that's expected.
   317  		matchTestChain(t, i, test.expectedChain, fix.chain.certs)
   318  
   319  		//Check fix.roots are the roots that are expected for the given url.
   320  		matchTestRoots(t, i, test.expectedRoots, fix.roots)
   321  	}
   322  }
   323  
   324  func TestFixAndLogQueueChain(t *testing.T) {
   325  	ctx := context.Background()
   326  	for i, test := range fixAndLogQueueTests {
   327  		f := &Fixer{toFix: make(chan *toFix)}
   328  		c := &http.Client{Transport: &testRoundTripper{}}
   329  		logClient, err := client.New(test.url, c, jsonclient.Options{})
   330  		if err != nil {
   331  			t.Fatalf("failed to create LogClient: %v", err)
   332  		}
   333  		l := &Logger{
   334  			ctx:           ctx,
   335  			client:        logClient,
   336  			postCertCache: newLockedMap(),
   337  		}
   338  		fl := &FixAndLog{fixer: f, chains: make(chan []*x509.Certificate), logger: l, done: newLockedMap()}
   339  
   340  		fl.wg.Add(1)
   341  		go testFixAndLogQueueChain(t, i, &test, fl)
   342  		fl.QueueChain(extractTestChain(t, i, test.chain))
   343  		fl.Wait()
   344  	}
   345  }
   346  

View as plain text