예제 #1
0
func TestIssuerCache(t *testing.T) {
	tester := func(ic *issuerCache, issuer *x509.Certificate) {
		if issuer := ic.getFromCertificate(issuer.RawSubject, issuer.SubjectKeyId); issuer == nil {
			t.Fatal("Failed to retrieve issuer from cache using subject + skid")
		}
		for _, h := range []crypto.Hash{crypto.SHA1, crypto.SHA256, crypto.SHA384, crypto.SHA512} {
			issuerSubjectHash, spkiHash, err := common.HashNameAndPKI(h.New(), issuer.RawSubject, issuer.RawSubjectPublicKeyInfo)
			if err != nil {
				t.Fatalf("Failed to hash subject and subject public key info: %s", err)
			}
			if issuer := ic.getFromRequest(issuerSubjectHash, spkiHash); issuer == nil {
				t.Fatal("Failed to retrieve issuer from cache using subject hash + spki hash")
			}
		}
	}

	testIssuer, err := common.ReadCertificate("../testdata/test-issuer.der")
	if err != nil {
		t.Fatalf("Failed to read ../testdata/test-issuer.der: %s", err)
	}

	ic := newIssuerCache(nil, everyHash)
	err = ic.add(testIssuer)
	if err != nil {
		t.Fatalf("Failed to add test issuer to cache: %s", err)
	}
	tester(ic, testIssuer)

	ic = newIssuerCache([]*x509.Certificate{testIssuer}, everyHash)
	tester(ic, testIssuer)
}
예제 #2
0
// AddFromCertificate creates an entry from a certificate on disk and
// adds it to the cache, a issuer or set of OCSP responders can be
// provided
func (c *EntryCache) AddFromCertificate(filename string, issuer *x509.Certificate, responders []string) error {
	e := NewEntry(c.log, c.clk)
	e.name = strings.TrimSuffix(
		filepath.Base(filename),
		filepath.Ext(filename),
	)
	cert, err := common.ReadCertificate(filename)
	if err != nil {
		return err
	}
	e.serial = cert.SerialNumber
	e.responders = cert.OCSPServer
	if len(responders) > 0 {
		e.responders = responders
	}
	e.issuer = issuer
	if e.issuer == nil {
		// check issuer cache
		if e.issuer = c.issuers.getFromCertificate(cert.RawIssuer, cert.AuthorityKeyId); e.issuer == nil {
			// fetch from AIA
			for _, issuerURL := range cert.IssuingCertificateURL {
				e.issuer, err = getIssuer(issuerURL)
				if err != nil {
					e.log.Err("Failed to retrieve issuer from '%s': %s", issuerURL, err)
					continue
				}
				c.issuers.add(e.issuer)
				break
			}
		}
	}
	ctx, cancel := context.WithTimeout(context.Background(), c.requestTimeout)
	defer cancel()
	err = e.init(ctx, c.StableBackings, c.client)
	if err != nil {
		return err
	}
	return c.add(e)
}
예제 #3
0
func main() {
	var configFilename string

	flag.StringVar(&configFilename, "config", "example.yaml", "YAML configuration file")
	flag.Parse()

	configBytes, err := ioutil.ReadFile(configFilename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to read configuration file '%s': %s", configFilename, err)
		os.Exit(1)
	}
	var conf config.Configuration
	err = yaml.Unmarshal(configBytes, &conf)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to parse configuration file: %s", err)
		os.Exit(1)
	}

	clk := clock.Default()
	logger := log.NewLogger(conf.Syslog.Network, conf.Syslog.Addr, conf.Syslog.StdoutLevel, clk)

	timeout := time.Second * time.Duration(10)
	if conf.Fetcher.Timeout.Duration != 0 {
		timeout = conf.Fetcher.Timeout.Duration
	}

	client := new(http.Client)
	if len(conf.Fetcher.Proxies) != 0 {
		proxyFunc, err := common.ProxyFunc(conf.Fetcher.Proxies)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to parsed proxy URI: %s", err)
		}
		client.Transport = &http.Transport{
			Proxy: proxyFunc,
			Dial: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 10 * time.Second,
		}
	}

	stableBackings := []scache.Cache{}
	if conf.Disk.CacheFolder != "" {
		stableBackings = append(stableBackings, scache.NewDisk(logger, clk, conf.Disk.CacheFolder))
	}

	issuers := []*x509.Certificate{}
	if conf.Definitions.IssuerFolder != "" {
		files, err := ioutil.ReadDir(conf.Definitions.IssuerFolder)
		if err != nil {
			logger.Err("Failed to read directory '%s': %s", conf.Definitions.IssuerFolder, err)
			os.Exit(1)
		}
		for _, fi := range files {
			if fi.IsDir() {
				continue
			}
			issuer, err := common.ReadCertificate(fi.Name())
			if err != nil {
				logger.Err("Failed to read issuer '%s': %s", fi.Name(), err)
				continue
			}
			issuers = append(issuers, issuer)
		}
	}

	c := mcache.NewEntryCache(clk, logger, 1*time.Minute, stableBackings, client, timeout, issuers, conf.SupportedHashes)

	logger.Info("Loading certificates")
	for _, def := range conf.Definitions.Certificates {
		var issuer *x509.Certificate
		var responders []string
		if def.Issuer != "" {
			issuer, err = common.ReadCertificate(def.Issuer)
			if err != nil {
				logger.Err("Failed to load issuer '%s': %s", def.Issuer, err)
				os.Exit(1)
			}
		}
		err = c.AddFromCertificate(def.Certificate, issuer, responders)
		if err != nil {
			logger.Err("Failed to load entry: %s", err)
			os.Exit(1)
		}
	}

	logger.Info("Initializing stapled")
	s, err := New(
		c,
		logger,
		clk,
		conf.HTTP.Addr,
		conf.Fetcher.UpstreamResponders,
		conf.Definitions.CertWatchFolder,
	)
	if err != nil {
		logger.Err("Failed to initialize stapled: %s", err)
		os.Exit(1)
	}

	logger.Info("Running stapled")
	err = s.Run()
	if err != nil {
		logger.Err("stapled failed: %s", err)
		os.Exit(1)
	}
}
예제 #4
0
func TestEntryCache(t *testing.T) {
	c := NewEntryCache(clock.Default(), log.NewLogger("", "", 10, clock.Default()), time.Minute, nil, nil, time.Minute, nil, everyHash)

	issuer, err := common.ReadCertificate("../testdata/test-issuer.der")
	if err != nil {
		t.Fatalf("Failed to read test issuer: %s", err)
	}
	e := &Entry{
		mu:       new(sync.RWMutex),
		name:     "test.der",
		serial:   big.NewInt(1337),
		issuer:   issuer,
		response: []byte{5, 0, 1},
	}

	err = c.add(e)
	if err != nil {
		t.Fatalf("Failed to add entry to cache: %s", err)
	}

	for _, h := range []crypto.Hash{crypto.SHA1, crypto.SHA256, crypto.SHA384, crypto.SHA512} {
		nameHash, pkHash, err := common.HashNameAndPKI(h.New(), issuer.RawSubject, issuer.RawSubjectPublicKeyInfo)
		if err != nil {
			t.Fatalf("Failed to hash subject and public key info: %s", err)
		}
		req := &ocsp.Request{h, nameHash, pkHash, e.serial}
		foundEntry, present := c.lookup(req)
		if !present {
			t.Fatal("Didn't find entry that should be in cache")
		}
		if foundEntry != e {
			t.Fatal("Cache returned wrong entry")
		}
		response, present := c.LookupResponse(req)
		if !present {
			t.Fatal("Didn't find response that should be in cache")
		}
		if bytes.Compare(response, e.response) != 0 {
			t.Fatal("Cache returned wrong response")
		}
	}

	err = c.Remove("test.der")
	if err != nil {
		t.Fatalf("Failed to remove entry from cache: %s", err)
	}

	for _, h := range []crypto.Hash{crypto.SHA1, crypto.SHA256, crypto.SHA384, crypto.SHA512} {
		nameHash, pkHash, err := common.HashNameAndPKI(h.New(), issuer.RawSubject, issuer.RawSubjectPublicKeyInfo)
		if err != nil {
			t.Fatalf("Failed to hash subject and public key info: %s", err)
		}
		_, present := c.lookup(&ocsp.Request{h, nameHash, pkHash, e.serial})
		if present {
			t.Fatal("Found entry that should've been removed from cache")
		}
		_, present = c.LookupResponse(&ocsp.Request{h, nameHash, pkHash, e.serial})
		if present {
			t.Fatal("Found response that should've been removed from cache")
		}
	}
}