You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ne...@apache.org on 2018/12/07 20:49:12 UTC

[trafficcontrol] branch master updated: Emit warning when adding self-signed certs using the API (#3072)

This is an automated email from the ASF dual-hosted git repository.

neuman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new e4b07c8  Emit warning when adding self-signed certs using the API (#3072)
e4b07c8 is described below

commit e4b07c8401345475089d1ffb22e30b6b2cdbe2ac
Author: Rawlin Peters <Ra...@gmail.com>
AuthorDate: Fri Dec 7 13:49:08 2018 -0700

    Emit warning when adding self-signed certs using the API (#3072)
    
    Rather than prohibit adding self-signed certs via the API, emit a
    warning to indicate that self-signed certs were detected and might not
    be completely valid.
---
 lib/go-tc/constants.go                             |  2 +-
 .../traffic_ops_golang/deliveryservice/keys.go     | 31 ++++++++++++++--------
 .../deliveryservice/keys_test.go                   | 19 +++++++++----
 .../common/api/DeliveryServiceSslKeysService.js    |  2 +-
 4 files changed, 36 insertions(+), 18 deletions(-)

diff --git a/lib/go-tc/constants.go b/lib/go-tc/constants.go
index a72aefb..9f7cee8 100644
--- a/lib/go-tc/constants.go
+++ b/lib/go-tc/constants.go
@@ -42,7 +42,7 @@ const (
 	ErrorLevel
 )
 
-var alertLevels = [4]string{"success", "info", "warn", "error"}
+var alertLevels = [4]string{"success", "info", "warning", "error"}
 
 func (a AlertLevel) String() string {
 	return alertLevels[a]
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/keys.go b/traffic_ops/traffic_ops_golang/deliveryservice/keys.go
index 0c5a1a9..3dd2577 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/keys.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/keys.go
@@ -60,7 +60,7 @@ func AddSSLKeys(w http.ResponseWriter, r *http.Request) {
 		api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
 		return
 	}
-	certChain, err := verifyCertificate(req.Certificate.Crt, "")
+	certChain, isUnknownAuth, err := verifyCertificate(req.Certificate.Crt, "")
 	if err != nil {
 		api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, errors.New("verifying certificate: "+err.Error()), nil)
 		return
@@ -83,6 +83,10 @@ func AddSSLKeys(w http.ResponseWriter, r *http.Request) {
 		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("adding SSL keys to delivery service '"+*req.DeliveryService+"': "+err.Error()))
 		return
 	}
+	if isUnknownAuth {
+		api.WriteRespAlert(w, r, tc.WarnLevel, "WARNING: SSL keys were successfully added for '"+*req.DeliveryService+"', but the certificate is signed by an unknown authority and may be invalid")
+		return
+	}
 	api.WriteResp(w, r, "Successfully added ssl keys for "+*req.DeliveryService)
 }
 
@@ -268,24 +272,26 @@ WHERE r.pattern = $2
 // verify the server certificate chain and return the
 // certificate and its chain in the proper order. Returns a verified
 // and ordered certificate and CA chain.
-func verifyCertificate(certificate string, rootCA string) (string, error) {
+// If the cert verification returns UnknownAuthorityError, return true to
+// indicate that the certs are signed by an unknown authority (e.g. self-signed).
+func verifyCertificate(certificate string, rootCA string) (string, bool, error) {
 	// decode, verify, and order certs for storage
 	certs := strings.SplitAfter(certificate, PemCertEndMarker)
 	if len(certs) <= 1 {
-		return "", errors.New("no certificate chain to verify")
+		return "", false, errors.New("no certificate chain to verify")
 	}
 
 	// decode and verify the server certificate
 	block, _ := pem.Decode([]byte(certs[0]))
 	if block == nil {
-		return "", errors.New("could not decode pem-encoded server certificate")
+		return "", false, errors.New("could not decode pem-encoded server certificate")
 	}
 	cert, err := x509.ParseCertificate(block.Bytes)
 	if err != nil {
-		return "", errors.New("could not parse the server certificate: " + err.Error())
+		return "", false, errors.New("could not parse the server certificate: " + err.Error())
 	}
 	if !(cert.KeyUsage&x509.KeyUsageKeyEncipherment > 0) {
-		return "", errors.New("no key encipherment usage for the server certificate")
+		return "", false, errors.New("no key encipherment usage for the server certificate")
 	}
 	bundle := ""
 	for i := 0; i < len(certs)-1; i++ {
@@ -294,7 +300,7 @@ func verifyCertificate(certificate string, rootCA string) (string, error) {
 
 	intermediatePool := x509.NewCertPool()
 	if !intermediatePool.AppendCertsFromPEM([]byte(bundle)) {
-		return "", errors.New("certificate CA bundle is empty")
+		return "", false, errors.New("certificate CA bundle is empty")
 	}
 
 	opts := x509.VerifyOptions{
@@ -304,17 +310,20 @@ func verifyCertificate(certificate string, rootCA string) (string, error) {
 		// verify the certificate chain.
 		rootPool := x509.NewCertPool()
 		if !rootPool.AppendCertsFromPEM([]byte(rootCA)) {
-			return "", errors.New("unable to parse root CA certificate")
+			return "", false, errors.New("unable to parse root CA certificate")
 		}
 		opts.Roots = rootPool
 	}
 
 	chain, err := cert.Verify(opts)
 	if err != nil {
-		return "", errors.New("could not verify the certificate chain: " + err.Error())
+		if _, ok := err.(x509.UnknownAuthorityError); ok {
+			return certificate, true, nil
+		}
+		return "", false, errors.New("could not verify the certificate chain: " + err.Error())
 	}
 	if len(chain) < 1 {
-		return "", errors.New("can't find valid chain for cert in file in request")
+		return "", false, errors.New("can't find valid chain for cert in file in request")
 	}
 	pemEncodedChain := ""
 	for _, link := range chain[0] {
@@ -325,5 +334,5 @@ func verifyCertificate(certificate string, rootCA string) (string, error) {
 		}
 	}
 
-	return pemEncodedChain, nil
+	return pemEncodedChain, false, nil
 }
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go b/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go
index 14b30a3..1bc2bd2 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go
@@ -27,7 +27,7 @@ import (
 const (
 	BadData = "This is bad data and it is not pem encoded"
 
-	SelfSigneCertOnly = `
+	SelfSignedCertOnly = `
 -----BEGIN CERTIFICATE-----
 MIIDkjCCAnoCCQCfwd219JKpUDANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMC
 VVMxETAPBgNVBAgMCENvbG9yYWRvMQ8wDQYDVQQHDAZEZW52ZXIxEDAOBgNVBAoM
@@ -199,19 +199,28 @@ OEUjfakK71+V/HbQt477zR4k7cRbiA==
 func TestVerifyAndEncodeCertificate(t *testing.T) {
 
 	// should fail bad base64 data
-	dat, err := verifyCertificate(BadData, "")
+	dat, _, err := verifyCertificate(BadData, "")
 	if err == nil {
 		t.Errorf("Unexpected result, there should have been a base64 decoding failure")
 	}
 
-	// should fail, can't verify self signed cert
-	dat, err = verifyCertificate(SelfSigneCertOnly, rootCA)
+	// should fail, can't verify self signed cert against this rootCA
+	dat, _, err = verifyCertificate(SelfSignedCertOnly, rootCA)
 	if err == nil {
 		t.Errorf("Unexpected result, a certificate verification error should have occured")
 	}
 
+	// should pass, unknown authority is just a warning not an error
+	dat, unknownAuth, err := verifyCertificate(GoodTLSKeys, "")
+	if err != nil {
+		t.Errorf("Test failure: %s", err)
+	}
+	if !unknownAuth {
+		t.Errorf("Unexpected result, certificate verification should have detected unknown authority")
+	}
+
 	// should pass
-	dat, err = verifyCertificate(GoodTLSKeys, rootCA)
+	dat, _, err = verifyCertificate(GoodTLSKeys, rootCA)
 	if err != nil {
 		t.Errorf("Test failure: %s", err)
 	}
diff --git a/traffic_portal/app/src/common/api/DeliveryServiceSslKeysService.js b/traffic_portal/app/src/common/api/DeliveryServiceSslKeysService.js
index 46a8ec0..31f1631 100644
--- a/traffic_portal/app/src/common/api/DeliveryServiceSslKeysService.js
+++ b/traffic_portal/app/src/common/api/DeliveryServiceSslKeysService.js
@@ -60,7 +60,7 @@ var DeliveryServiceSslKeysService = function($http, $q, locationUtils, messageMo
         $http.post(ENV.api['root'] + "deliveryservices/sslkeys/add", sslKeys)
         .then(
             function(result) {
-            	messageModel.setMessages([ { level: 'success', text: 'SSL Keys updated for ' + deliveryService.xmlId } ], false);
+                messageModel.setMessages(result.data.alerts, false);
                 request.resolve(result.data.response);
             },
             function(fault) {