Beispiel #1
0
func TestParseTLSWithEnvironmentVariables(t *testing.T) {
	config := configure(fmt.Sprintf(`{
		"server": {
			"tls_cert_file": "%s",
			"client_ca_file": "nosuchfile"
		}
	}`, Cert))

	vars := map[string]string{
		"SERVER_TLS_KEY_FILE":   Key,
		"SERVER_CLIENT_CA_FILE": Root,
	}
	setupEnvironmentVariables(t, vars)
	defer cleanupEnvironmentVariables(t, vars)

	tlsConfig, err := ParseServerTLS(config, true)
	require.NoError(t, err)

	expectedCert, err := tls.LoadX509KeyPair(Cert, Key)
	require.NoError(t, err)

	expectedRoot, err := trustmanager.LoadCertFromFile(Root)
	require.NoError(t, err)

	require.Len(t, tlsConfig.Certificates, 1)
	require.True(t, reflect.DeepEqual(expectedCert, tlsConfig.Certificates[0]))

	subjects := tlsConfig.ClientCAs.Subjects()
	require.Len(t, subjects, 1)
	require.True(t, bytes.Equal(expectedRoot.RawSubject, subjects[0]))
	require.Equal(t, tlsConfig.ClientAuth, tls.RequireAndVerifyClientCert)
}
Beispiel #2
0
func TestParseTLSWithTLS(t *testing.T) {
	config := configure(fmt.Sprintf(`{
		"server": {
			"tls_cert_file": "%s",
			"tls_key_file": "%s",
			"client_ca_file": "%s"
		}
	}`, Cert, Key, Root))

	tlsConfig, err := ParseServerTLS(config, false)
	require.NoError(t, err)

	expectedCert, err := tls.LoadX509KeyPair(Cert, Key)
	require.NoError(t, err)

	expectedRoot, err := trustmanager.LoadCertFromFile(Root)
	require.NoError(t, err)

	require.Len(t, tlsConfig.Certificates, 1)
	require.True(t, reflect.DeepEqual(expectedCert, tlsConfig.Certificates[0]))

	subjects := tlsConfig.ClientCAs.Subjects()
	require.Len(t, subjects, 1)
	require.True(t, bytes.Equal(expectedRoot.RawSubject, subjects[0]))
	require.Equal(t, tlsConfig.ClientAuth, tls.RequireAndVerifyClientCert)
}
Beispiel #3
0
//TODO (diogo): Ask the use if she wants to trust the GUN in the cert
func keysTrust(cmd *cobra.Command, args []string) {
	if len(args) < 1 {
		cmd.Usage()
		fatalf("please provide a URL or filename to a certificate")
	}

	certLocationStr := args[0]
	var cert *x509.Certificate

	// Verify if argument is a valid URL
	url, err := url.Parse(certLocationStr)
	if err == nil && url.Scheme != "" {
		cert, err = trustmanager.GetCertFromURL(certLocationStr)
		if err != nil {
			fatalf("error retrieving certificate from url (%s): %v", certLocationStr, err)
		}
	} else if _, err := os.Stat(certLocationStr); err == nil {
		// Try to load the certificate from the file
		cert, err = trustmanager.LoadCertFromFile(certLocationStr)
		if err != nil {
			fatalf("error adding certificate from file: %v", err)
		}
	} else {
		fatalf("please provide a file location or URL for CA certificate.")
	}

	// Ask for confirmation before adding certificate into repository
	fmt.Printf("Are you sure you want to add trust for: %s? (yes/no)\n", cert.Subject.CommonName)
	confirmed := askConfirm()
	if !confirmed {
		fatalf("aborting action.")
	}

	err = nil
	if cert.IsCA {
		err = caStore.AddCert(cert)
	} else {
		err = certificateStore.AddCert(cert)
	}
	if err != nil {
		fatalf("error adding certificate from file: %v", err)
	}

	fmt.Printf("Adding: ")
	printCert(cert)

}
Beispiel #4
0
func getTransport(gun string, readOnly bool) http.RoundTripper {
	// Attempt to get a root CA from the config file. Nil is the host defaults.
	rootPool := x509.NewCertPool()
	rootCAFile := mainViper.GetString("remote_server.root_ca")
	if rootCAFile != "" {
		// If we haven't been given an Absolute path, we assume it's relative
		// from the configuration directory (~/.notary by default)
		if !filepath.IsAbs(rootCAFile) {
			rootCAFile = filepath.Join(configPath, rootCAFile)
		}
		rootCert, err := trustmanager.LoadCertFromFile(rootCAFile)
		if err != nil {
			fatalf("could not load root ca file. %s", err.Error())
		}
		rootPool.AddCert(rootCert)
	}

	// skipTLSVerify is false by default so verification will
	// be performed.
	tlsConfig := &tls.Config{
		InsecureSkipVerify: mainViper.GetBool("remote_server.skipTLSVerify"),
		MinVersion:         tls.VersionTLS10,
		RootCAs:            rootPool,
	}

	base := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     tlsConfig,
		DisableKeepAlives:   true,
	}

	return tokenAuth(base, gun, readOnly)
}
Beispiel #5
0
func TestCertsToRemove(t *testing.T) {
	// Get a few certificates to test with
	cert1, err := trustmanager.LoadCertFromFile("../fixtures/secure.example.com.crt")
	assert.NoError(t, err)
	cert1KeyID, err := trustmanager.FingerprintCert(cert1)
	assert.NoError(t, err)

	// Get intermediate certificate
	cert2, err := trustmanager.LoadCertFromFile("../fixtures/self-signed_secure.example.com.crt")
	assert.NoError(t, err)
	cert2KeyID, err := trustmanager.FingerprintCert(cert2)
	assert.NoError(t, err)

	// Get leaf certificate
	cert3, err := trustmanager.LoadCertFromFile("../fixtures/self-signed_docker.com-notary.crt")
	assert.NoError(t, err)
	cert3KeyID, err := trustmanager.FingerprintCert(cert3)
	assert.NoError(t, err)

	// Call CertsToRemove with only one old and one new
	oldCerts := []*x509.Certificate{cert1}
	newCerts := []*x509.Certificate{cert2}

	certificates := certsToRemove(oldCerts, newCerts)
	assert.Len(t, certificates, 1)
	_, ok := certificates[cert1KeyID]
	assert.True(t, ok)

	// Call CertsToRemove with two old and one new
	oldCerts = []*x509.Certificate{cert1, cert2}
	newCerts = []*x509.Certificate{cert3}

	certificates = certsToRemove(oldCerts, newCerts)
	assert.Len(t, certificates, 2)
	_, ok = certificates[cert1KeyID]
	assert.True(t, ok)
	_, ok = certificates[cert2KeyID]
	assert.True(t, ok)
	_, ok = certificates[cert3KeyID]
	assert.False(t, ok)

	// Call CertsToRemove with two new and one old
	oldCerts = []*x509.Certificate{cert3}
	newCerts = []*x509.Certificate{cert2, cert1}

	certificates = certsToRemove(oldCerts, newCerts)
	assert.Len(t, certificates, 1)
	_, ok = certificates[cert3KeyID]
	assert.True(t, ok)
	_, ok = certificates[cert1KeyID]
	assert.False(t, ok)
	_, ok = certificates[cert2KeyID]
	assert.False(t, ok)

	// Call CertsToRemove with three old certificates and no new
	oldCerts = []*x509.Certificate{cert1, cert2, cert3}
	newCerts = []*x509.Certificate{}

	certificates = certsToRemove(oldCerts, newCerts)
	assert.Len(t, certificates, 0)
	_, ok = certificates[cert1KeyID]
	assert.False(t, ok)
	_, ok = certificates[cert2KeyID]
	assert.False(t, ok)
	_, ok = certificates[cert3KeyID]
	assert.False(t, ok)

	// Call CertsToRemove with three new certificates and no old
	oldCerts = []*x509.Certificate{}
	newCerts = []*x509.Certificate{cert1, cert2, cert3}

	certificates = certsToRemove(oldCerts, newCerts)
	assert.Len(t, certificates, 0)
	_, ok = certificates[cert1KeyID]
	assert.False(t, ok)
	_, ok = certificates[cert2KeyID]
	assert.False(t, ok)
	_, ok = certificates[cert3KeyID]
	assert.False(t, ok)

}
Beispiel #6
0
func TestValidateRootWithPinnedCA(t *testing.T) {
	var testSignedRoot data.Signed
	var signedRootBytes bytes.Buffer

	// Temporary directory where test files will be created
	tempBaseDir, err := ioutil.TempDir("", "notary-test-")
	defer os.RemoveAll(tempBaseDir)
	require.NoError(t, err, "failed to create a temporary directory: %s", err)

	templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
	templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
	// Unmarshal our signedRoot
	json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
	typedSignedRoot, err := data.RootFromSigned(&testSignedRoot)
	require.NoError(t, err)

	// This call to trustpinning.ValidateRoot will fail because we have an invalid path for the CA
	_, err = trustpinning.ValidateRoot(nil, &testSignedRoot, "docker.com/notary", trustpinning.TrustPinConfig{CA: map[string]string{"docker.com/notary": filepath.Join(tempBaseDir, "nonexistent")}})
	require.Error(t, err)

	// This call to trustpinning.ValidateRoot will fail because we have no valid GUNs to use, and TOFUS is disabled
	_, err = trustpinning.ValidateRoot(nil, &testSignedRoot, "docker.com/notary", trustpinning.TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: true})
	require.Error(t, err)

	// This call to trustpinning.ValidateRoot will succeed because we have no valid GUNs to use and we fall back to enabled TOFUS
	validatedRoot, err := trustpinning.ValidateRoot(nil, &testSignedRoot, "docker.com/notary", trustpinning.TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: false})
	require.NoError(t, err)
	generateRootKeyIDs(typedSignedRoot)
	require.Equal(t, typedSignedRoot, validatedRoot)

	// Write an invalid CA cert (not even a PEM) to the tempDir and ensure validation fails when using it
	invalidCAFilepath := filepath.Join(tempBaseDir, "invalid.ca")
	require.NoError(t, ioutil.WriteFile(invalidCAFilepath, []byte("ABSOLUTELY NOT A PEM"), 0644))

	// Using this invalid CA cert should fail on trustpinning.ValidateRoot
	_, err = trustpinning.ValidateRoot(nil, &testSignedRoot, "docker.com/notary", trustpinning.TrustPinConfig{CA: map[string]string{"docker.com/notary": invalidCAFilepath}, DisableTOFU: true})
	require.Error(t, err)

	validCAFilepath := "../fixtures/root-ca.crt"

	// If we pass an invalid Certs entry in addition to this valid CA entry, since Certs has priority for pinning we will fail
	_, err = trustpinning.ValidateRoot(nil, &testSignedRoot, "docker.com/notary", trustpinning.TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {"invalidID"}}, CA: map[string]string{"docker.com/notary": validCAFilepath}, DisableTOFU: true})
	require.Error(t, err)

	// Now construct a new root with a valid cert chain, such that signatures are correct over the 'notary-signer' GUN.  Pin the root-ca and validate
	leafCert, err := trustmanager.LoadCertFromFile("../fixtures/notary-signer.crt")
	require.NoError(t, err)

	intermediateCert, err := trustmanager.LoadCertFromFile("../fixtures/intermediate-ca.crt")
	require.NoError(t, err)

	pemChainBytes, err := trustmanager.CertChainToPEM([]*x509.Certificate{leafCert, intermediateCert})
	require.NoError(t, err)

	newRootKey := data.NewPublicKey(data.RSAx509Key, pemChainBytes)

	rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{newRootKey.ID()}, nil)
	require.NoError(t, err)

	testRoot, err := data.NewRoot(
		map[string]data.PublicKey{newRootKey.ID(): newRootKey},
		map[string]*data.RootRole{
			data.CanonicalRootRole:      &rootRole.RootRole,
			data.CanonicalTimestampRole: &rootRole.RootRole,
			data.CanonicalTargetsRole:   &rootRole.RootRole,
			data.CanonicalSnapshotRole:  &rootRole.RootRole},
		false,
	)
	testRoot.Signed.Version = 1
	require.NoError(t, err, "Failed to create new root")

	keyReader, err := os.Open("../fixtures/notary-signer.key")
	require.NoError(t, err, "could not open key file")
	pemBytes, err := ioutil.ReadAll(keyReader)
	require.NoError(t, err, "could not read key file")
	privKey, err := trustmanager.ParsePEMPrivateKey(pemBytes, "")
	require.NoError(t, err)

	store, err := trustmanager.NewKeyFileStore(tempBaseDir, passphraseRetriever)
	require.NoError(t, err)
	cs := cryptoservice.NewCryptoService(store)

	err = store.AddKey(trustmanager.KeyInfo{Role: data.CanonicalRootRole, Gun: "notary-signer"}, privKey)
	require.NoError(t, err)

	newTestSignedRoot, err := testRoot.ToSigned()
	require.NoError(t, err)

	err = signed.Sign(cs, newTestSignedRoot, []data.PublicKey{newRootKey}, 1, nil)
	require.NoError(t, err)

	newTypedSignedRoot, err := data.RootFromSigned(newTestSignedRoot)
	require.NoError(t, err)

	// Check that we validate correctly against a pinned CA and provided bundle
	validatedRoot, err = trustpinning.ValidateRoot(nil, newTestSignedRoot, "notary-signer", trustpinning.TrustPinConfig{CA: map[string]string{"notary-signer": validCAFilepath}, DisableTOFU: true})
	require.NoError(t, err)
	generateRootKeyIDs(newTypedSignedRoot)
	require.Equal(t, newTypedSignedRoot, validatedRoot)

	// Add an expired CA for the same gun to our previous pinned bundle, ensure that we still validate correctly
	goodRootCABundle, err := trustmanager.LoadCertBundleFromFile(validCAFilepath)
	require.NoError(t, err)
	memKeyStore := trustmanager.NewKeyMemoryStore(passphraseRetriever)
	cryptoService := cryptoservice.NewCryptoService(memKeyStore)
	testPubKey, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
	require.NoError(t, err)
	testPrivKey, _, err := memKeyStore.GetKey(testPubKey.ID())
	require.NoError(t, err)
	expiredCert, err := generateExpiredTestingCertificate(testPrivKey, "notary-signer")
	require.NoError(t, err)
	bundleWithExpiredCert, err := trustmanager.CertChainToPEM(append(goodRootCABundle, expiredCert))
	require.NoError(t, err)
	bundleWithExpiredCertPath := filepath.Join(tempBaseDir, "bundle_with_expired_cert.pem")
	require.NoError(t, ioutil.WriteFile(bundleWithExpiredCertPath, bundleWithExpiredCert, 0644))

	// Check that we validate correctly against a pinned CA and provided bundle
	validatedRoot, err = trustpinning.ValidateRoot(nil, newTestSignedRoot, "notary-signer", trustpinning.TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithExpiredCertPath}, DisableTOFU: true})
	require.NoError(t, err)
	require.Equal(t, newTypedSignedRoot, validatedRoot)

	testPubKey2, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
	require.NoError(t, err)
	testPrivKey2, _, err := memKeyStore.GetKey(testPubKey2.ID())
	require.NoError(t, err)
	expiredCert2, err := generateExpiredTestingCertificate(testPrivKey2, "notary-signer")
	require.NoError(t, err)
	allExpiredCertBundle, err := trustmanager.CertChainToPEM([]*x509.Certificate{expiredCert, expiredCert2})
	require.NoError(t, err)
	allExpiredCertPath := filepath.Join(tempBaseDir, "all_expired_cert.pem")
	require.NoError(t, ioutil.WriteFile(allExpiredCertPath, allExpiredCertBundle, 0644))
	// Now only use expired certs in the bundle, we should fail
	_, err = trustpinning.ValidateRoot(nil, newTestSignedRoot, "notary-signer", trustpinning.TrustPinConfig{CA: map[string]string{"notary-signer": allExpiredCertPath}, DisableTOFU: true})
	require.Error(t, err)

	// Add a CA cert for a that won't validate against the root leaf certificate
	testPubKey3, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
	require.NoError(t, err)
	testPrivKey3, _, err := memKeyStore.GetKey(testPubKey3.ID())
	require.NoError(t, err)
	validCert, err := cryptoservice.GenerateCertificate(testPrivKey3, "notary-signer", time.Now(), time.Now().AddDate(1, 0, 0))
	require.NoError(t, err)
	bundleWithWrongCert, err := trustmanager.CertChainToPEM([]*x509.Certificate{validCert})
	require.NoError(t, err)
	bundleWithWrongCertPath := filepath.Join(tempBaseDir, "bundle_with_expired_cert.pem")
	require.NoError(t, ioutil.WriteFile(bundleWithWrongCertPath, bundleWithWrongCert, 0644))
	_, err = trustpinning.ValidateRoot(nil, newTestSignedRoot, "notary-signer", trustpinning.TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithWrongCertPath}, DisableTOFU: true})
	require.Error(t, err)
}