Example #1
0
// LoadConfig attempts to load the configuration from a byte slice.
// On error, it returns nil.
func LoadConfig(config []byte) (*Config, error) {
	var cfg = &Config{}
	err := json.Unmarshal(config, &cfg)
	if err != nil {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
			errors.New("failed to unmarshal configuration: "+err.Error()))
	}

	if cfg.Signing == nil {
		return nil, errors.New("No \"signing\" field present")
	}

	if cfg.Signing.Default == nil {
		log.Debugf("no default given: using default config")
		cfg.Signing.Default = DefaultConfig()
	} else {
		if err := cfg.Signing.Default.populate(cfg); err != nil {
			return nil, err
		}
	}

	for k := range cfg.Signing.Profiles {
		if err := cfg.Signing.Profiles[k].populate(cfg); err != nil {
			return nil, err
		}
	}

	if !cfg.Valid() {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid configuration"))
	}

	log.Debugf("configuration ok")
	return cfg, nil
}
Example #2
0
// BundleFromRemote fetches the certificate served by the server at
// serverName (or ip, if the ip argument is not the empty string). It
// is expected that the method will be able to make a connection at
// port 443. The certificate used by the server in this connection is
// used to build the bundle, which will necessarily be keyless.
func (b *Bundler) BundleFromRemote(serverName, ip string, flavor BundleFlavor) (*Bundle, error) {
	config := &tls.Config{
		RootCAs:    b.RootPool,
		ServerName: serverName,
	}

	// Dial by IP if present
	var dialName string
	if ip != "" {
		dialName = ip + ":443"
	} else {
		dialName = serverName + ":443"
	}

	log.Debugf("bundling from remote %s", dialName)

	dialer := &net.Dialer{Timeout: time.Duration(5) * time.Second}
	conn, err := tls.DialWithDialer(dialer, "tcp", dialName, config)
	var dialError string
	// If there's an error in tls.Dial, try again with
	// InsecureSkipVerify to fetch the remote bundle to (re-)bundle
	// with. If the bundle is indeed not usable (expired, mismatched
	// hostnames, etc.), report the error.  Otherwise, create a
	// working bundle and insert the tls error in the bundle.Status.
	if err != nil {
		log.Debugf("dial failed: %v", err)
		// record the error msg
		dialError = fmt.Sprintf("Failed rigid TLS handshake with %s: %v", dialName, err)
		// dial again with InsecureSkipVerify
		log.Debugf("try again with InsecureSkipVerify.")
		config.InsecureSkipVerify = true
		conn, err = tls.DialWithDialer(dialer, "tcp", dialName, config)
		if err != nil {
			log.Debugf("dial with InsecureSkipVerify failed: %v", err)
			return nil, errors.Wrap(errors.DialError, errors.Unknown, err)
		}
	}

	connState := conn.ConnectionState()

	certs := connState.PeerCertificates

	err = conn.VerifyHostname(serverName)
	if err != nil {
		log.Debugf("failed to verify hostname: %v", err)
		return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
	}

	// Bundle with remote certs. Inject the initial dial error, if any, to the status reporting.
	bundle, err := b.Bundle(certs, nil, flavor)
	if err != nil {
		return nil, err
	} else if dialError != "" {
		bundle.Status.Messages = append(bundle.Status.Messages, dialError)
	}
	return bundle, err
}
Example #3
0
func TestListener(t *testing.T) {
	var before = 55 * time.Second

	trl, err := New(before, testLIdentity)
	if err != nil {
		t.Fatalf("failed to set up transport: %v", err)
	}

	trl.Identity.Request.CN = "localhost test server"

	err = trl.RefreshKeys()
	if err != nil {
		t.Fatalf("%v", err)
	}

	l, err = Listen("127.0.0.1:8765", trl)
	if err != nil {
		t.Fatalf("%v", err)
	}

	errChan := make(chan error, 0)
	go func() {
		err := <-errChan
		if err != nil {
			t.Fatalf("listener auto update failed: %v", err)
		}
	}()

	cert := trl.Provider.Certificate()
	before = cert.NotAfter.Sub(time.Now())
	before -= 5 * time.Second

	trl.Before = before
	go l.AutoUpdate(nil, errChan)
	go testListen(t)

	<-time.After(1 * time.Second)
	log.Debug("dialer making connection")
	conn, err := Dial("127.0.0.1:8765", tr)
	if err != nil {
		log.Debugf("certificate time: %s-%s / %s",
			trl.Provider.Certificate().NotBefore,
			trl.Provider.Certificate().NotAfter,
			time.Now().UTC())
		log.Debugf("%#v", trl.Provider.Certificate())
		t.Fatalf("%v", err)
	}
	log.Debugf("client connected to server")

	conn.Close()
}
Example #4
0
func (b *Bundler) verifyChain(chain []*fetchedIntermediate) bool {
	// This process will verify if the root of the (partial) chain is in our root pool,
	// and will fail otherwise.
	log.Debugf("verifying chain")
	for vchain := chain[:]; len(vchain) > 0; vchain = vchain[1:] {
		cert := vchain[0]
		// If this is a certificate in one of the pools, skip it.
		if b.KnownIssuers[string(cert.Cert.Signature)] {
			log.Debugf("certificate is known")
			continue
		}

		_, err := cert.Cert.Verify(b.VerifyOptions())
		if err != nil {
			log.Debugf("certificate failed verification: %v", err)
			return false
		} else if len(chain) == len(vchain) && isChainRootNode(cert.Cert) {
			// The first certificate in the chain is a root; it shouldn't be stored.
			log.Debug("looking at root certificate, will not store")
			continue
		}

		// leaf cert has an empty name, don't store leaf cert.
		if cert.Name == "" {
			continue
		}

		log.Debug("add certificate to intermediate pool:", cert.Name)
		b.IntermediatePool.AddCert(cert.Cert)
		b.KnownIssuers[string(cert.Cert.Signature)] = true

		if IntermediateStash != "" {
			fileName := filepath.Join(IntermediateStash, cert.Name)

			var block = pem.Block{Type: "CERTIFICATE", Bytes: cert.Cert.Raw}

			log.Debugf("write intermediate to stash directory: %s", fileName)
			// If the write fails, verification should not fail.
			err = ioutil.WriteFile(fileName, pem.EncodeToMemory(&block), 0644)
			if err != nil {
				log.Errorf("failed to write new intermediate: %v", err)
			} else {
				log.Info("stashed new intermediate ", cert.Name)
			}
		}
	}
	return true
}
Example #5
0
File: csr.go Project: kisom/cfssl
// Generate generates a key as specified in the request. Currently,
// only ECDSA and RSA are supported.
func (kr *BasicKeyRequest) Generate() (crypto.PrivateKey, error) {
	log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo(), kr.Size())
	switch kr.Algo() {
	case "rsa":
		if kr.Size() < 2048 {
			return nil, errors.New("RSA key is too weak")
		}
		if kr.Size() > 8192 {
			return nil, errors.New("RSA key size too large")
		}
		return rsa.GenerateKey(rand.Reader, kr.Size())
	case "ecdsa":
		var curve elliptic.Curve
		switch kr.Size() {
		case curveP256:
			curve = elliptic.P256()
		case curveP384:
			curve = elliptic.P384()
		case curveP521:
			curve = elliptic.P521()
		default:
			return nil, errors.New("invalid curve")
		}
		return ecdsa.GenerateKey(curve, rand.Reader)
	default:
		return nil, errors.New("invalid algorithm")
	}
}
Example #6
0
func TestLoadBadRootConfs(t *testing.T) {
	confs := []string{
		"testdata/roots_bad_db.conf",
		"testdata/roots_bad_certificate.conf",
		"testdata/roots_bad_private_key.conf",
		"testdata/roots_badconfig.conf",
		"testdata/roots_badspec.conf",
		"testdata/roots_badspec2.conf",
		"testdata/roots_badspec3.conf",
		"testdata/roots_bad_whitelist.conf",
		"testdata/roots_bad_whitelist.conf2",
		"testdata/roots_missing_certificate.conf",
		"testdata/roots_missing_certificate_entry.conf",
		"testdata/roots_missing_private_key.conf",
		"testdata/roots_missing_private_key_entry.conf",
	}

	for _, cf := range confs {
		_, err := Parse(cf)
		if err == nil {
			t.Fatalf("expected config file %s to fail", cf)
		}
		log.Debugf("%s: %v", cf, err)
	}
}
Example #7
0
// LoadFile attempts to load the db configuration file stored at the path
// and returns the configuration. On error, it returns nil.
func LoadFile(path string) (cfg *DBConfig, err error) {
	log.Debugf("loading db configuration file from %s", path)
	if path == "" {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path"))
	}

	var body []byte
	body, err = ioutil.ReadFile(path)
	if err != nil {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file"))
	}

	cfg = &DBConfig{}
	err = json.Unmarshal(body, &cfg)
	if err != nil {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
			errors.New("failed to unmarshal configuration: "+err.Error()))
	}

	if cfg.DataSourceName == "" || cfg.DriverName == "" {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid db configuration"))
	}

	return
}
Example #8
0
func TestAutoUpdate(t *testing.T) {
	// To force a refresh, make sure that the certificate is
	// updated 5 seconds from now.
	cert := tr.Provider.Certificate()
	if cert == nil {
		t.Fatal("no certificate from provider")
	}

	certUpdates := make(chan time.Time, 0)
	errUpdates := make(chan error, 0)
	oldBefore := tr.Before
	before := cert.NotAfter.Sub(time.Now())
	before -= 5 * time.Second
	tr.Before = before
	defer func() {
		tr.Before = oldBefore
		PollInterval = 30 * time.Second
	}()

	PollInterval = 2 * time.Second

	go tr.AutoUpdate(certUpdates, errUpdates)
	log.Debugf("waiting for certificate update or error from auto updater")
	select {
	case <-certUpdates:
		// Nothing needs to be done
	case err := <-errUpdates:
		t.Fatalf("%v", err)
	case <-time.After(15 * time.Second):
		t.Fatal("timeout waiting for update")
	}
}
Example #9
0
func (ctx *context) copyResults(timeout time.Duration) map[string]FamilyResult {
	var timedOut bool
	done := make(chan bool, 1)
	results := make(map[string]FamilyResult)

	go func() {
		for result := range ctx.resultChan {
			if timedOut {
				log.Debugf("Received result after timeout: %v", result)
				continue
			}

			if results[result.Family] == nil {
				results[result.Family] = make(FamilyResult)
			}

			results[result.Family][result.Scanner] = result.ScannerResult
		}
		done <- true
	}()

	select {
	case <-done:
	case <-time.After(timeout):
		timedOut = true
		log.Warningf("Scan timed out after %v", timeout)
	}

	return results
}
Example #10
0
// AutoUpdate will automatically update the listener. If a non-nil
// certUpdates chan is provided, it will receive timestamps for
// reissued certificates. If errChan is non-nil, any errors that occur
// in the updater will be passed along.
func (l *Listener) AutoUpdate(certUpdates chan<- time.Time, errChan chan<- error) {
	defer func() {
		if r := recover(); r != nil {
			log.Criticalf("AutoUpdate panicked: %v", r)
		}
	}()

	for {
		// Wait until it's time to update the certificate.
		target := time.Now().Add(l.Lifespan())
		if PollInterval == 0 {
			<-time.After(l.Lifespan())
		} else {
			pollWait(target)
		}

		// Keep trying to update the certificate until it's
		// ready.
		for {
			log.Debug("refreshing certificate")
			err := l.RefreshKeys()
			if err == nil {
				break
			}

			delay := l.Transport.Backoff.Duration()
			log.Debugf("failed to update certificate, will try again in %s", delay)
			if errChan != nil {
				errChan <- err
			}

			<-time.After(delay)
		}

		if certUpdates != nil {
			certUpdates <- time.Now()
		}

		config, err := l.getConfig()
		if err != nil {
			log.Debug("immediately after getting a new certificate, the Transport is reporting errors: %v", err)
			if errChan != nil {
				errChan <- err
			}
		}

		address := l.Listener.Addr().String()
		lnet := l.Listener.Addr().Network()
		l.Listener, err = tls.Listen(lnet, address, config)
		if err != nil {
			log.Debug("immediately after getting a new certificate, the Transport is reporting errors: %v", err)
			if errChan != nil {
				errChan <- err
			}
		}

		log.Debug("listener: auto update of certificate complete")
		l.Transport.Backoff.Reset()
	}
}
Example #11
0
// LoadRootCAs loads the default root certificate authorities from file.
func LoadRootCAs(caBundleFile string) (err error) {
	if caBundleFile != "" {
		log.Debugf("Loading scan RootCAs: %s", caBundleFile)
		RootCAs, err = helpers.LoadPEMCertPool(caBundleFile)
	}
	return
}
Example #12
0
func (tr *Transport) getCertificate() (cert tls.Certificate, err error) {
	if !tr.Provider.Ready() {
		log.Debug("transport isn't ready; attempting to refresh keypair")
		err = tr.RefreshKeys()
		if err != nil {
			log.Debugf("transport couldn't get a certificate: %v", err)
			return
		}
	}

	cert, err = tr.Provider.X509KeyPair()
	if err != nil {
		log.Debugf("couldn't generate an X.509 keypair: %v", err)
	}

	return
}
Example #13
0
// Scan performs the scan to be performed on the given host and stores its result.
func (s *Scanner) Scan(addr, hostname string) (Grade, Output, error) {
	grade, output, err := s.scan(addr, hostname)
	if err != nil {
		log.Debugf("scan: %v", err)
		return grade, output, err
	}
	return grade, output, err
}
Example #14
0
// fetchRemoteCertificate retrieves a single URL pointing to a certificate
// and attempts to first parse it as a DER-encoded certificate; if
// this fails, it attempts to decode it as a PEM-encoded certificate.
func fetchRemoteCertificate(certURL string) (fi *fetchedIntermediate, err error) {
	log.Debugf("fetching remote certificate: %s", certURL)
	var resp *http.Response
	resp, err = http.Get(certURL)
	if err != nil {
		log.Debugf("failed HTTP get: %v", err)
		return
	}

	defer resp.Body.Close()
	var certData []byte
	certData, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Debugf("failed to read response body: %v", err)
		return
	}

	log.Debugf("attempting to parse certificate as DER")
	crt, err := x509.ParseCertificate(certData)
	if err != nil {
		log.Debugf("attempting to parse certificate as PEM")
		crt, err = helpers.ParseCertificatePEM(certData)
		if err != nil {
			log.Debugf("failed to parse certificate: %v", err)
			return
		}
	}

	log.Debugf("certificate fetch succeeds")
	fi = &fetchedIntermediate{Cert: crt, Name: constructCertFileName(crt)}
	return
}
Example #15
0
// Valid checks the signature policies, ensuring they are valid
// policies. A policy is valid if it has defined at least key usages
// to be used, and a valid default profile has defined at least a
// default expiration.
func (p *Signing) Valid() bool {
	if p == nil {
		return false
	}

	log.Debugf("validating configuration")
	if !p.Default.validProfile(true) {
		log.Debugf("default profile is invalid")
		return false
	}

	for _, sp := range p.Profiles {
		if !sp.validProfile(false) {
			log.Debugf("invalid profile")
			return false
		}
	}
	return true
}
Example #16
0
// AutoUpdate will automatically update the listener. If a non-nil
// certUpdates chan is provided, it will receive timestamps for
// reissued certificates. If errChan is non-nil, any errors that occur
// in the updater will be passed along.
func (tr *Transport) AutoUpdate(certUpdates chan<- time.Time, errChan chan<- error) {
	defer func() {
		if r := recover(); r != nil {
			log.Criticalf("AutoUpdate panicked: %v", r)
		}
	}()

	for {
		// Wait until it's time to update the certificate.
		target := time.Now().Add(tr.Lifespan())
		if PollInterval == 0 {
			<-time.After(tr.Lifespan())
		} else {
			pollWait(target)
		}

		// Keep trying to update the certificate until it's
		// ready.
		for {
			log.Debugf("attempting to refresh keypair")
			err := tr.RefreshKeys()
			if err == nil {
				break
			}

			delay := tr.Backoff.Duration()
			log.Debugf("failed to update certificate, will try again in %s", delay)
			if errChan != nil {
				errChan <- err
			}

			<-time.After(delay)
		}

		log.Debugf("certificate updated")
		if certUpdates != nil {
			certUpdates <- time.Now()
		}

		tr.Backoff.Reset()
	}
}
Example #17
0
func testListen(t *testing.T) {
	log.Debug("listener waiting for connection")
	conn, err := l.Accept()
	if err != nil {
		t.Fatalf("%v", err)
	}

	log.Debugf("client has connected")
	conn.Write([]byte("hello"))

	conn.Close()
}
Example #18
0
// LoadFile attempts to load the configuration file stored at the path
// and returns the configuration. On error, it returns nil.
func LoadFile(path string) (*Config, error) {
	log.Debugf("loading configuration file from %s", path)
	if path == "" {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path"))
	}

	body, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file"))
	}

	return LoadConfig(body)
}
Example #19
0
// RefreshKeys will make sure the Transport has loaded keys and has a
// valid certificate. It will handle any persistence, check that the
// certificate is valid (i.e. that its expiry date is within the
// Before date), and handle certificate reissuance as needed.
func (tr *Transport) RefreshKeys() (err error) {
	if !tr.Provider.Ready() {
		log.Debug("key and certificate aren't ready, loading")
		err = tr.Provider.Load()
		if err != nil && err != kp.ErrCertificateUnavailable {
			log.Debugf("failed to load keypair: %v", err)
			kr := tr.Identity.Request.KeyRequest
			if kr == nil {
				kr = csr.NewBasicKeyRequest()
			}

			err = tr.Provider.Generate(kr.Algo(), kr.Size())
			if err != nil {
				log.Debugf("failed to generate key: %v", err)
				return
			}
		}
	}

	lifespan := tr.Lifespan()
	if lifespan < tr.Before {
		log.Debugf("transport's certificate is out of date (lifespan %s)", lifespan)
		req, err := tr.Provider.CertificateRequest(tr.Identity.Request)
		if err != nil {
			log.Debugf("couldn't get a CSR: %v", err)
			return err
		}

		log.Debug("requesting certificate from CA")
		cert, err := tr.CA.SignCSR(req)
		if err != nil {
			log.Debugf("failed to get the certificate signed: %v", err)
			return err
		}

		log.Debug("giving the certificate to the provider")
		err = tr.Provider.SetCertificatePEM(cert)
		if err != nil {
			log.Debugf("failed to set the provider's certificate: %v", err)
			return err
		}

		log.Debug("storing the certificate")
		err = tr.Provider.Store()
		if err != nil {
			log.Debugf("the provider failed to store the certificate: %v", err)
			return err
		}
	}

	return nil
}
Example #20
0
// BundleFromPEMorDER builds a certificate bundle from the set of byte
// slices containing the PEM or DER-encoded certificate(s), private key.
func (b *Bundler) BundleFromPEMorDER(certsRaw, keyPEM []byte, flavor BundleFlavor, password string) (*Bundle, error) {
	log.Debug("bundling from PEM files")
	var key crypto.Signer
	var err error
	if len(keyPEM) != 0 {
		key, err = helpers.ParsePrivateKeyPEM(keyPEM)
		if err != nil {
			log.Debugf("failed to parse private key: %v", err)
			return nil, err
		}
	}

	certs, err := helpers.ParseCertificatesPEM(certsRaw)
	if err != nil {
		// If PEM doesn't work try DER
		var keyDER crypto.Signer
		var errDER error
		certs, keyDER, errDER = helpers.ParseCertificatesDER(certsRaw, password)
		// Only use DER key if no key read from file
		if key == nil && keyDER != nil {
			key = keyDER
		}
		if errDER != nil {
			log.Debugf("failed to parse certificates: %v", err)
			// If neither parser works pass along PEM error
			return nil, err
		}

	}
	if len(certs) == 0 {
		log.Debugf("no certificates found")
		return nil, errors.New(errors.CertificateError, errors.DecodeFailed)
	}

	log.Debugf("bundle ready")
	return b.Bundle(certs, key, flavor)
}
Example #21
0
// ParseCertificatePEM parses and returns a PEM-encoded certificate,
// can handle PEM encoded PKCS #7 structures.
func ParseCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
	certPEM = bytes.TrimSpace(certPEM)
	cert, rest, err := ParseOneCertificateFromPEM(certPEM)
	if err != nil {
		// Log the actual parsing error but throw a default parse error message.
		log.Debugf("Certificate parsing error: %v", err)
		return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed)
	} else if cert == nil {
		return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
	} else if len(rest) > 0 {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PEM file should contain only one object"))
	} else if len(cert) > 1 {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PKCS7 object in the PEM file should contain only one certificate"))
	}
	return cert[0], nil
}
Example #22
0
// BundleFromFile takes a set of files containing the PEM-encoded leaf certificate
// (optionally along with some intermediate certs), the PEM-encoded private key
// and returns the bundle built from that key and the certificate(s).
func (b *Bundler) BundleFromFile(bundleFile, keyFile string, flavor BundleFlavor, password string) (*Bundle, error) {
	log.Debug("Loading Certificate: ", bundleFile)
	certsRaw, err := ioutil.ReadFile(bundleFile)
	if err != nil {
		return nil, errors.Wrap(errors.CertificateError, errors.ReadFailed, err)
	}

	var keyPEM []byte
	// Load private key PEM only if a file is given
	if keyFile != "" {
		log.Debug("Loading private key: ", keyFile)
		keyPEM, err = ioutil.ReadFile(keyFile)
		if err != nil {
			log.Debugf("failed to read private key: ", err)
			return nil, errors.Wrap(errors.PrivateKeyError, errors.ReadFailed, err)
		}
		if len(keyPEM) == 0 {
			log.Debug("key is empty")
			return nil, errors.Wrap(errors.PrivateKeyError, errors.DecodeFailed, err)
		}
	}

	return b.BundleFromPEMorDER(certsRaw, keyPEM, flavor, password)
}
Example #23
0
// New returns a new PKCS #11 signer.
func New(caCertFile string, policy *config.Signing, cfg *Config) (signer.Signer, error) {
	if cfg == nil {
		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed)
	}

	log.Debugf("Loading PKCS #11 module %s", cfg.Module)
	certData, err := ioutil.ReadFile(caCertFile)
	if err != nil {
		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed)
	}

	cert, err := helpers.ParseCertificatePEM(certData)
	if err != nil {
		return nil, err
	}

	priv, err := pkcs11key.New(cfg.Module, cfg.Token, cfg.PIN, cfg.Label)
	if err != nil {
		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed)
	}
	sigAlgo := signer.DefaultSigAlgo(priv)

	return local.NewSigner(priv, cert, sigAlgo, policy)
}
Example #24
0
// NewPKCS11Signer returns a new PKCS #11 signer.
func NewPKCS11Signer(cfg ocspConfig.Config) (ocsp.Signer, error) {
	log.Debugf("Loading PKCS #11 module %s", cfg.PKCS11.Module)
	certData, err := ioutil.ReadFile(cfg.CACertFile)
	if err != nil {
		return nil, errors.New(errors.CertificateError, errors.ReadFailed)
	}

	cert, err := helpers.ParseCertificatePEM(certData)
	if err != nil {
		return nil, err
	}

	PKCS11 := cfg.PKCS11
	priv, err := pkcs11key.New(
		PKCS11.Module,
		PKCS11.TokenLabel,
		PKCS11.PIN,
		PKCS11.PrivateKeyLabel)
	if err != nil {
		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed)
	}

	return ocsp.NewSigner(cert, cert, priv, cfg.Interval)
}
Example #25
0
// fetchIntermediates goes through each of the URLs in the AIA "Issuing
// CA" extensions and fetches those certificates. If those
// certificates are not present in either the root pool or
// intermediate pool, the certificate is saved to file and added to
// the list of intermediates to be used for verification. This will
// not add any new certificates to the root pool; if the ultimate
// issuer is not trusted, fetching the certicate here will not change
// that.
func (b *Bundler) fetchIntermediates(certs []*x509.Certificate) (err error) {
	if IntermediateStash != "" {
		log.Debugf("searching intermediates")
		if _, err := os.Stat(IntermediateStash); err != nil && os.IsNotExist(err) {
			log.Infof("intermediate stash directory %s doesn't exist, creating", IntermediateStash)
			err = os.MkdirAll(IntermediateStash, 0755)
			if err != nil {
				log.Errorf("failed to create intermediate stash directory %s: %v", IntermediateStash, err)
				return err
			}
			log.Infof("intermediate stash directory %s created", IntermediateStash)
		}
	}
	// stores URLs and certificate signatures that have been seen
	seen := map[string]bool{}
	var foundChains int

	// Construct a verify chain as a reversed partial bundle,
	// such that the certs are ordered by promxity to the root CAs.
	var chain []*fetchedIntermediate
	for i, cert := range certs {
		var name string

		// Only construct filenames for non-leaf intermediate certs
		// so they will be saved to disk if necessary.
		// Leaf cert gets a empty name and will be skipped.
		if i > 0 {
			name = constructCertFileName(cert)
		}

		chain = append([]*fetchedIntermediate{&fetchedIntermediate{cert, name}}, chain...)
		seen[string(cert.Signature)] = true
	}

	// Verify the chain and store valid intermediates in the chain.
	// If it doesn't verify, fetch the intermediates and extend the chain
	// in a DFS manner and verify each time we hit a root.
	for {
		if len(chain) == 0 {
			log.Debugf("search complete")
			if foundChains == 0 {
				return x509.UnknownAuthorityError{}
			}
			return nil
		}

		current := chain[0]
		var advanced bool
		if b.verifyChain(chain) {
			foundChains++
		}
		log.Debugf("walk AIA issuers")
		for _, url := range current.Cert.IssuingCertificateURL {
			if seen[url] {
				log.Debugf("url %s has been seen", url)
				continue
			}
			crt, err := fetchRemoteCertificate(url)
			if err != nil {
				continue
			} else if seen[string(crt.Cert.Signature)] {
				log.Debugf("fetched certificate is known")
				continue
			}
			seen[url] = true
			seen[string(crt.Cert.Signature)] = true
			chain = append([]*fetchedIntermediate{crt}, chain...)
			advanced = true
			break
		}

		if !advanced {
			log.Debugf("didn't advance, stepping back")
			chain = chain[1:]
		}
	}
}
Example #26
0
// Bundle takes an X509 certificate (already in the
// Certificate structure), a private key as crypto.Signer in one of the appropriate
// formats (i.e. *rsa.PrivateKey or *ecdsa.PrivateKey, or even a opaque key), using them to
// build a certificate bundle.
func (b *Bundler) Bundle(certs []*x509.Certificate, key crypto.Signer, flavor BundleFlavor) (*Bundle, error) {
	log.Infof("bundling certificate for %+v", certs[0].Subject)
	if len(certs) == 0 {
		return nil, nil
	}

	// Detect reverse ordering of the cert chain.
	if len(certs) > 1 && !partialVerify(certs) {
		rcerts := reverse(certs)
		if partialVerify(rcerts) {
			certs = rcerts
		}
	}

	var ok bool
	cert := certs[0]
	if key != nil {
		switch {
		case cert.PublicKeyAlgorithm == x509.RSA:

			var rsaPublicKey *rsa.PublicKey
			if rsaPublicKey, ok = key.Public().(*rsa.PublicKey); !ok {
				return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
			}
			if cert.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 {
				return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
			}
		case cert.PublicKeyAlgorithm == x509.ECDSA:
			var ecdsaPublicKey *ecdsa.PublicKey
			if ecdsaPublicKey, ok = key.Public().(*ecdsa.PublicKey); !ok {
				return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
			}
			if cert.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 {
				return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
			}
		default:
			return nil, errors.New(errors.PrivateKeyError, errors.NotRSAOrECC)
		}
	} else {
		switch {
		case cert.PublicKeyAlgorithm == x509.RSA:
		case cert.PublicKeyAlgorithm == x509.ECDSA:
		default:
			return nil, errors.New(errors.PrivateKeyError, errors.NotRSAOrECC)
		}
	}

	bundle := new(Bundle)
	bundle.Cert = cert
	bundle.Key = key
	bundle.Issuer = &cert.Issuer
	bundle.Subject = &cert.Subject

	bundle.buildHostnames()

	if flavor == Force {
		// force bundle checks the certificates
		// forms a verification chain.
		if !partialVerify(certs) {
			return nil,
				errors.Wrap(errors.CertificateError, errors.VerifyFailed,
					goerr.New("Unable to verify the certificate chain"))
		}
		bundle.Chain = certs
	} else {
		// disallow self-signed cert
		if cert.CheckSignatureFrom(cert) == nil {
			return nil, errors.New(errors.CertificateError, errors.SelfSigned)
		}

		// verify and store input intermediates to the intermediate pool.
		// Ignore the returned error here, will treat it in the second call.
		b.fetchIntermediates(certs)

		chains, err := cert.Verify(b.VerifyOptions())
		if err != nil {
			log.Debugf("verification failed: %v", err)
			// If the error was an unknown authority, try to fetch
			// the intermediate specified in the AIA and add it to
			// the intermediates bundle.
			switch err := err.(type) {
			case x509.UnknownAuthorityError:
				// Do nothing -- have the default case return out.
			default:
				return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
			}

			log.Debugf("searching for intermediates via AIA issuer")
			err = b.fetchIntermediates(certs)
			if err != nil {
				log.Debugf("search failed: %v", err)
				return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
			}

			log.Debugf("verifying new chain")
			chains, err = cert.Verify(b.VerifyOptions())
			if err != nil {
				log.Debugf("failed to verify chain: %v", err)
				return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
			}
			log.Debugf("verify ok")
		}
		var matchingChains [][]*x509.Certificate
		switch flavor {
		case Optimal:
			matchingChains = optimalChains(chains)
		case Ubiquitous:
			if len(ubiquity.Platforms) == 0 {
				log.Warning("No metadata, Ubiquitous falls back to Optimal.")
			}
			matchingChains = ubiquitousChains(chains)
		default:
			matchingChains = ubiquitousChains(chains)
		}

		bundle.Chain = matchingChains[0]
	}

	statusCode := int(errors.Success)
	var messages []string
	// Check if bundle is expiring.
	expiringCerts := checkExpiringCerts(bundle.Chain)
	bundle.Expires = helpers.ExpiryTime(bundle.Chain)
	if len(expiringCerts) > 0 {
		statusCode |= errors.BundleExpiringBit
		messages = append(messages, expirationWarning(expiringCerts))
	}
	// Check if bundle contains SHA2 certs.
	if ubiquity.ChainHashUbiquity(bundle.Chain) <= ubiquity.SHA2Ubiquity {
		statusCode |= errors.BundleNotUbiquitousBit
		messages = append(messages, sha2Warning)
	}
	// Check if bundle contains ECDSA signatures.
	if ubiquity.ChainKeyAlgoUbiquity(bundle.Chain) <= ubiquity.ECDSA256Ubiquity {
		statusCode |= errors.BundleNotUbiquitousBit
		messages = append(messages, ecdsaWarning)
	}

	// when forcing a bundle, bundle ubiquity doesn't matter
	// also we don't retrieve the anchoring root of the bundle
	var untrusted []string
	if flavor != Force {
		// Add root store presence info
		root := bundle.Chain[len(bundle.Chain)-1]
		bundle.Root = root
		log.Infof("the anchoring root is %v", root.Subject)
		// Check if there is any platform that doesn't trust the chain.
		// Also, an warning will be generated if ubiquity.Platforms is nil,
		untrusted = ubiquity.UntrustedPlatforms(root)
		untrustedMsg := untrustedPlatformsWarning(untrusted)
		if len(untrustedMsg) > 0 {
			log.Debug("Populate untrusted platform warning.")
			statusCode |= errors.BundleNotUbiquitousBit
			messages = append(messages, untrustedMsg)
		}
	}

	// Check if there is any platform that rejects the chain because of SHA1 deprecation.
	sha1Msgs := ubiquity.SHA1DeprecationMessages(bundle.Chain)
	if len(sha1Msgs) > 0 {
		log.Debug("Populate SHA1 deprecation warning.")
		statusCode |= errors.BundleNotUbiquitousBit
		messages = append(messages, sha1Msgs...)
	}

	bundle.Status = &BundleStatus{ExpiringSKIs: getSKIs(bundle.Chain, expiringCerts), Code: statusCode, Messages: messages, Untrusted: untrusted}

	// attempt to not to include the root certificate for optimization
	if flavor != Force {
		// Include at least one intermediate if the leaf has enabled OCSP and is not CA.
		if bundle.Cert.OCSPServer != nil && !bundle.Cert.IsCA && len(bundle.Chain) <= 2 {
			// No op. Return one intermediate if there is one.
		} else {
			// do not include the root.
			bundle.Chain = bundle.Chain[:len(bundle.Chain)-1]
		}
	}

	bundle.Status.IsRebundled = diff(bundle.Chain, certs)

	log.Debugf("bundle complete")
	return bundle, nil
}
Example #27
0
// A valid profile must be a valid local profile or a valid remote profile.
// A valid local profile has defined at least key usages to be used, and a
// valid local default profile has defined at least a default expiration.
// A valid remote profile (default or not) has remote signer initialized.
// In addition, a remote profile must has a valid auth provider if auth
// key defined.
func (p *SigningProfile) validProfile(isDefault bool) bool {
	if p == nil {
		return false
	}

	if p.RemoteName != "" {
		log.Debugf("validate remote profile")

		if p.RemoteServer == "" {
			log.Debugf("invalid remote profile: no remote signer specified")
			return false
		}

		if p.AuthKeyName != "" && p.Provider == nil {
			log.Debugf("invalid remote profile: auth key name is defined but no auth provider is set")
			return false
		}

		if p.AuthRemote.RemoteName != "" {
			log.Debugf("invalid remote profile: auth remote is also specified")
		}
	} else if p.AuthRemote.RemoteName != "" {
		log.Debugf("validate auth remote profile")
		if p.RemoteServer == "" {
			log.Debugf("invalid auth remote profile: no remote signer specified")
			return false
		}

		if p.AuthRemote.AuthKeyName == "" || p.RemoteProvider == nil {
			log.Debugf("invalid auth remote profile: no auth key is defined")
			return false
		}
	} else {
		log.Debugf("validate local profile")
		if !isDefault {
			if len(p.Usage) == 0 {
				log.Debugf("invalid local profile: no usages specified")
				return false
			} else if _, _, unk := p.Usages(); len(unk) == len(p.Usage) {
				log.Debugf("invalid local profile: no valid usages")
				return false
			}
		} else {
			if p.Expiry == 0 {
				log.Debugf("invalid local profile: no expiry set")
				return false
			}
		}
	}

	log.Debugf("profile is valid")
	return true
}
Example #28
0
// populate is used to fill in the fields that are not in JSON
//
// First, the ExpiryString parameter is needed to parse
// expiration timestamps from JSON. The JSON decoder is not able to
// decode a string time duration to a time.Duration, so this is called
// when loading the configuration to properly parse and fill out the
// Expiry parameter.
// This function is also used to create references to the auth key
// and default remote for the profile.
// It returns true if ExpiryString is a valid representation of a
// time.Duration, and the AuthKeyString and RemoteName point to
// valid objects. It returns false otherwise.
func (p *SigningProfile) populate(cfg *Config) error {
	if p == nil {
		return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("can't parse nil profile"))
	}

	var err error
	if p.RemoteName == "" && p.AuthRemote.RemoteName == "" {
		log.Debugf("parse expiry in profile")
		if p.ExpiryString == "" {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("empty expiry string"))
		}

		dur, err := time.ParseDuration(p.ExpiryString)
		if err != nil {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
		}

		log.Debugf("expiry is valid")
		p.Expiry = dur

		if p.BackdateString != "" {
			dur, err = time.ParseDuration(p.BackdateString)
			if err != nil {
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
			}

			p.Backdate = dur
		}

		if !p.NotBefore.IsZero() && !p.NotAfter.IsZero() && p.NotAfter.Before(p.NotBefore) {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
		}

		if len(p.Policies) > 0 {
			for _, policy := range p.Policies {
				for _, qualifier := range policy.Qualifiers {
					if qualifier.Type != "" && qualifier.Type != "id-qt-unotice" && qualifier.Type != "id-qt-cps" {
						return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
							errors.New("invalid policy qualifier type"))
					}
				}
			}
		}
	} else if p.RemoteName != "" {
		log.Debug("match remote in profile to remotes section")
		if p.AuthRemote.RemoteName != "" {
			log.Error("profile has both a remote and an auth remote specified")
			return cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
		}
		if remote := cfg.Remotes[p.RemoteName]; remote != "" {
			if err := p.updateRemote(remote); err != nil {
				return err
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find remote in remotes section"))
		}
	} else {
		log.Debug("match auth remote in profile to remotes section")
		if remote := cfg.Remotes[p.AuthRemote.RemoteName]; remote != "" {
			if err := p.updateRemote(remote); err != nil {
				return err
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find remote in remotes section"))
		}
	}

	if p.AuthKeyName != "" {
		log.Debug("match auth key in profile to auth_keys section")
		if key, ok := cfg.AuthKeys[p.AuthKeyName]; ok == true {
			if key.Type == "standard" {
				p.Provider, err = auth.New(key.Key, nil)
				if err != nil {
					log.Debugf("failed to create new standard auth provider: %v", err)
					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
						errors.New("failed to create new standard auth provider"))
				}
			} else {
				log.Debugf("unknown authentication type %v", key.Type)
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
					errors.New("unknown authentication type"))
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find auth_key in auth_keys section"))
		}
	}

	if p.AuthRemote.AuthKeyName != "" {
		log.Debug("match auth remote key in profile to auth_keys section")
		if key, ok := cfg.AuthKeys[p.AuthRemote.AuthKeyName]; ok == true {
			if key.Type == "standard" {
				p.RemoteProvider, err = auth.New(key.Key, nil)
				if err != nil {
					log.Debugf("failed to create new standard auth provider: %v", err)
					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
						errors.New("failed to create new standard auth provider"))
				}
			} else {
				log.Debugf("unknown authentication type %v", key.Type)
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
					errors.New("unknown authentication type"))
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find auth_remote's auth_key in auth_keys section"))
		}
	}

	if p.NameWhitelistString != "" {
		log.Debug("compiling whitelist regular expression")
		rule, err := regexp.Compile(p.NameWhitelistString)
		if err != nil {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to compile name whitelist section"))
		}
		p.NameWhitelist = rule
	}

	p.ExtensionWhitelist = map[string]bool{}
	for _, oid := range p.AllowedExtensions {
		p.ExtensionWhitelist[asn1.ObjectIdentifier(oid).String()] = true
	}

	return nil
}