You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ro...@apache.org on 2018/09/28 00:12:36 UTC

[trafficcontrol] 01/04: Finish up DS SSL keys endpoints in TO Go

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

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

commit eaffeb59a74b16ecc1e8c3af14102d48548c4b9d
Author: Rawlin Peters <ra...@comcast.com>
AuthorDate: Tue Sep 18 16:44:41 2018 -0600

    Finish up DS SSL keys endpoints in TO Go
    
    Finish out the '-wip' DS sslkeys endpoints and fix up what was already
    there.
---
 lib/go-tc/deliveryservice_ssl_keys.go              |   2 +-
 .../deliveryservice/deliveryservicesv13.go         |   4 +-
 .../traffic_ops_golang/deliveryservice/keys.go     | 220 ++++++++--------
 .../deliveryservice/keys_test.go                   | 284 ++++++++++-----------
 .../traffic_ops_golang/deliveryservice/sslkeys.go  |   4 +-
 traffic_ops/traffic_ops_golang/riaksvc/dsutil.go   |  78 +-----
 traffic_ops/traffic_ops_golang/routes.go           |  11 +-
 7 files changed, 267 insertions(+), 336 deletions(-)

diff --git a/lib/go-tc/deliveryservice_ssl_keys.go b/lib/go-tc/deliveryservice_ssl_keys.go
index 0bfb15c..bab764a 100644
--- a/lib/go-tc/deliveryservice_ssl_keys.go
+++ b/lib/go-tc/deliveryservice_ssl_keys.go
@@ -44,7 +44,7 @@ type DeliveryServiceSSLKeysCertificate struct {
 // DeliveryServiceSSLKeys ...
 type DeliveryServiceSSLKeys struct {
 	CDN             string                            `json:"cdn,omitempty"`
-	DeliveryService string                            `json:"DeliveryService,omitempty"`
+	DeliveryService string                            `json:"deliveryservice,omitempty"`
 	BusinessUnit    string                            `json:"businessUnit,omitempty"`
 	City            string                            `json:"city,omitempty"`
 	Organization    string                            `json:"organization,omitempty"`
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go
index 649afb1..3e2a64f 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go
@@ -652,7 +652,7 @@ func updateSSLKeys(ds *tc.DeliveryServiceNullable, hostName string, tx *sql.Tx,
 	if ds.XMLID == nil {
 		return errors.New("delivery services has no XMLID!")
 	}
-	key, ok, err := riaksvc.GetDeliveryServiceSSLKeysObjTx(*ds.XMLID, "latest", tx, cfg.RiakAuthOptions)
+	key, ok, err := riaksvc.GetDeliveryServiceSSLKeysObj(*ds.XMLID, riaksvc.DSSSLKeyVersionLatest, tx, cfg.RiakAuthOptions)
 	if err != nil {
 		return errors.New("getting SSL key: " + err.Error())
 	}
@@ -661,7 +661,7 @@ func updateSSLKeys(ds *tc.DeliveryServiceNullable, hostName string, tx *sql.Tx,
 	}
 	key.DeliveryService = *ds.XMLID
 	key.Hostname = hostName
-	if err := riaksvc.PutDeliveryServiceSSLKeysObjTx(key, tx, cfg.RiakAuthOptions); err != nil {
+	if err := riaksvc.PutDeliveryServiceSSLKeysObj(key, tx, cfg.RiakAuthOptions); err != nil {
 		return errors.New("putting updated SSL key: " + err.Error())
 	}
 	return nil
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/keys.go b/traffic_ops/traffic_ops_golang/deliveryservice/keys.go
index aac39dc..830ec07 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/keys.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/keys.go
@@ -27,7 +27,6 @@ import (
 	"encoding/json"
 	"encoding/pem"
 	"errors"
-	"fmt"
 	"net/http"
 	"strings"
 
@@ -37,6 +36,10 @@ import (
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
 )
 
+const (
+	PemCertEndMarker = "-----END CERTIFICATE-----"
+)
+
 // AddSSLKeys adds the given ssl keys to the given delivery service.
 func AddSSLKeys(w http.ResponseWriter, r *http.Request) {
 	inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
@@ -46,7 +49,7 @@ func AddSSLKeys(w http.ResponseWriter, r *http.Request) {
 	}
 	defer inf.Close()
 	if !inf.Config.RiakEnabled {
-		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("adding Riak SSL keys for delivery service:: riak is not configured"))
+		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("adding SSL keys to Riak for delivery service: Riak is not configured"))
 		return
 	}
 	keysObj := tc.DeliveryServiceSSLKeys{}
@@ -58,22 +61,28 @@ func AddSSLKeys(w http.ResponseWriter, r *http.Request) {
 		api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
 		return
 	}
-	certChain, err := verifyAndEncodeCertificate(keysObj.Certificate.Crt, "")
+	certChain, err := verifyCertificate(keysObj.Certificate.Crt, "")
 	if err != nil {
 		api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, errors.New("verifying certificate: "+err.Error()), nil)
 		return
 	}
 	keysObj.Certificate.Crt = certChain
+	base64EncodeCertificate(&keysObj.Certificate)
+	if err := riaksvc.PutDeliveryServiceSSLKeysObj(keysObj, inf.Tx.Tx, inf.Config.RiakAuthOptions); err != nil {
+		api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, nil, errors.New("putting SSL keys in Riak for delivery service '"+keysObj.DeliveryService+"': "+err.Error()))
+		return
+	}
+	keysObj.Version = riaksvc.DSSSLKeyVersionLatest
 	if err := riaksvc.PutDeliveryServiceSSLKeysObj(keysObj, inf.Tx.Tx, inf.Config.RiakAuthOptions); err != nil {
-		api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, nil, errors.New("putting Riak SSL keys for delivery service '"+keysObj.DeliveryService+"': "+err.Error()))
+		api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, nil, errors.New("putting latest SSL keys in Riak for delivery service '"+keysObj.DeliveryService+"': "+err.Error()))
 		return
 	}
-	api.WriteRespRaw(w, r, keysObj)
+	api.WriteResp(w, r, "Successfully added ssl keys for "+keysObj.DeliveryService)
 }
 
 // GetSSLKeysByHostName fetches the ssl keys for a deliveryservice specified by the fully qualified hostname
 func GetSSLKeysByHostName(w http.ResponseWriter, r *http.Request) {
-	inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"hostName"}, nil)
+	inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"hostname"}, nil)
 	if userErr != nil || sysErr != nil {
 		api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
 		return
@@ -81,12 +90,11 @@ func GetSSLKeysByHostName(w http.ResponseWriter, r *http.Request) {
 	defer inf.Close()
 
 	if inf.Config.RiakEnabled == false {
-		api.HandleErr(w, r, inf.Tx.Tx, http.StatusServiceUnavailable, errors.New("The RIAK service is unavailable"), errors.New("getting Riak SSL keys by host name: riak is not configured"))
+		api.HandleErr(w, r, inf.Tx.Tx, http.StatusServiceUnavailable, errors.New("the Riak service is unavailable"), errors.New("getting SSL keys from Riak by host name: Riak is not configured"))
 		return
 	}
 
-	version := inf.Params["version"]
-	hostName := inf.Params["hostName"]
+	hostName := inf.Params["hostname"]
 	domainName := ""
 	hostRegex := ""
 	strArr := strings.Split(hostName, ".")
@@ -96,7 +104,7 @@ func GetSSLKeysByHostName(w http.ResponseWriter, r *http.Request) {
 			domainName += strArr[i] + "."
 		}
 		domainName += strArr[ln-1]
-		hostRegex = ".*\\." + strArr[1] + "\\..*"
+		hostRegex = `.*\.` + strArr[1] + `\..*`
 	}
 
 	// lookup the cdnID
@@ -120,36 +128,28 @@ func GetSSLKeysByHostName(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	if userErr, sysErr, errCode := tenant.Check(inf.User, xmlID, inf.Tx.Tx); userErr != nil || sysErr != nil {
-		api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
-		return
-	}
-	keyObj, ok, err := riaksvc.GetDeliveryServiceSSLKeysObj(xmlID, version, inf.Tx.Tx, inf.Config.RiakAuthOptions)
-	if err != nil {
-		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting ssl keys: "+err.Error()))
-		return
-	}
-	if !ok {
-		api.WriteRespAlert(w, r, tc.InfoLevel, "no object found for the specified key")
-		return
-	}
-	api.WriteResp(w, r, keyObj)
+	getSSLKeysByXMLIDHelper(xmlID, inf, w, r)
 }
 
 // GetSSLKeysByXMLID fetches the deliveryservice ssl keys by the specified xmlID.
 func GetSSLKeysByXMLID(w http.ResponseWriter, r *http.Request) {
-	inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"xmlID"}, nil)
+	inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"xmlid"}, nil)
 	if userErr != nil || sysErr != nil {
 		api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
 		return
 	}
 	defer inf.Close()
 	if inf.Config.RiakEnabled == false {
-		api.HandleErr(w, r, inf.Tx.Tx, http.StatusServiceUnavailable, errors.New("The RIAK service is unavailable"), errors.New("getting Riak SSL keys by xml id: riak is not configured"))
+		api.HandleErr(w, r, inf.Tx.Tx, http.StatusServiceUnavailable, errors.New("the Riak service is unavailable"), errors.New("getting SSL keys from Riak by xml id: Riak is not configured"))
 		return
 	}
+	xmlID := inf.Params["xmlid"]
+	getSSLKeysByXMLIDHelper(xmlID, inf, w, r)
+}
+
+func getSSLKeysByXMLIDHelper(xmlID string, inf *api.APIInfo, w http.ResponseWriter, r *http.Request) {
 	version := inf.Params["version"]
-	xmlID := inf.Params["xmlID"]
+	decode := inf.Params["decode"]
 	if userErr, sysErr, errCode := tenant.Check(inf.User, xmlID, inf.Tx.Tx); userErr != nil || sysErr != nil {
 		api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
 		return
@@ -160,29 +160,65 @@ func GetSSLKeysByXMLID(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	if !ok {
-		api.WriteRespAlert(w, r, tc.InfoLevel, "no object found for the specified key")
+		api.WriteRespAlertObj(w, r, tc.InfoLevel, "no object found for the specified key", struct{}{}) // empty response object because Perl
 		return
 	}
+	if decode != "" && decode != "0" { // the Perl version checked the decode string as: if ( $decode )
+		err = base64DecodeCertificate(&keyObj.Certificate)
+		if err != nil {
+			api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting SSL keys for XMLID '"+xmlID+"': "+err.Error()))
+			return
+		}
+	}
 	api.WriteResp(w, r, keyObj)
 }
 
+func base64DecodeCertificate(cert *tc.DeliveryServiceSSLKeysCertificate) error {
+	csrDec, err := base64.StdEncoding.DecodeString(cert.CSR)
+	if err != nil {
+		return errors.New("base64 decoding csr: " + err.Error())
+	}
+	cert.CSR = string(csrDec)
+	crtDec, err := base64.StdEncoding.DecodeString(cert.Crt)
+	if err != nil {
+		return errors.New("base64 decoding crt: " + err.Error())
+	}
+	cert.Crt = string(crtDec)
+	keyDec, err := base64.StdEncoding.DecodeString(cert.Key)
+	if err != nil {
+		return errors.New("base64 decoding key: " + err.Error())
+	}
+	cert.Key = string(keyDec)
+	return nil
+}
+
+func base64EncodeCertificate(cert *tc.DeliveryServiceSSLKeysCertificate) {
+	cert.CSR = base64.StdEncoding.EncodeToString([]byte(cert.CSR))
+	cert.Crt = base64.StdEncoding.EncodeToString([]byte(cert.Crt))
+	cert.Key = base64.StdEncoding.EncodeToString([]byte(cert.Key))
+}
+
 func DeleteSSLKeys(w http.ResponseWriter, r *http.Request) {
-	inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"name"}, nil)
+	inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"xmlid"}, nil)
 	if userErr != nil || sysErr != nil {
 		api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
 		return
 	}
 	defer inf.Close()
 	if inf.Config.RiakEnabled == false {
-		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, userErr, errors.New("deliveryservice.DeleteSSLKeys: Riak is not configured!"))
+		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, userErr, errors.New("deliveryservice.DeleteSSLKeys: Riak is not configured"))
+		return
+	}
+	xmlID := inf.Params["xmlid"]
+	if userErr, sysErr, errCode := tenant.Check(inf.User, xmlID, inf.Tx.Tx); userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
 		return
 	}
-	ds := tc.DeliveryServiceName(inf.Params["name"])
-	if err := riaksvc.DeleteDSSSLKeys(inf.Tx.Tx, inf.Config.RiakAuthOptions, ds, inf.Params["version"]); err != nil {
+	if err := riaksvc.DeleteDSSSLKeys(inf.Tx.Tx, inf.Config.RiakAuthOptions, xmlID, inf.Params["version"]); err != nil {
 		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, userErr, errors.New("deliveryservice.DeleteSSLKeys: deleting SSL keys: "+err.Error()))
 		return
 	}
-	api.WriteResp(w, r, "Successfully deleted ssl keys for "+string(ds))
+	api.WriteResp(w, r, "Successfully deleted ssl keys for "+xmlID)
 }
 
 // returns the cdn_id found by domainname.
@@ -216,86 +252,64 @@ WHERE r.pattern = $2
 }
 
 // verify the server certificate chain and return the
-// certificate and its chain in the proper order. Returns a  verified,
-// ordered, and base64 encoded certificate and CA chain.
-func verifyAndEncodeCertificate(certificate string, rootCA string) (string, error) {
-	var pemEncodedChain string
-	var b64crt string
+// 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) {
+	// decode, verify, and order certs for storage
+	certs := strings.SplitAfter(certificate, PemCertEndMarker)
+	if len(certs) <= 1 {
+		return "", errors.New("no certificate chain to verify")
+	}
 
-	// strip newlines from encoded crt and decode it from base64.
-	crtArr := strings.Split(certificate, "\\n")
-	for i := 0; i < len(crtArr); i++ {
-		b64crt += crtArr[i]
+	// 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")
 	}
-	pemCerts := make([]byte, base64.StdEncoding.EncodedLen(len(b64crt)))
-	_, err := base64.StdEncoding.Decode(pemCerts, []byte(b64crt))
+	cert, err := x509.ParseCertificate(block.Bytes)
 	if err != nil {
-		return "", fmt.Errorf("could not base64 decode the certificate %v", err)
+		return "", 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")
+	}
+	bundle := ""
+	for i := 0; i < len(certs)-1; i++ {
+		bundle += certs[i]
 	}
 
-	// decode, verify, and order certs for storgae
-	var bundle string
-	certs := strings.SplitAfter(string(pemCerts), "-----END CERTIFICATE-----")
-	if len(certs) > 1 {
-		// decode and verify the server certificate
-		block, _ := pem.Decode([]byte(certs[0]))
-		cert, err := x509.ParseCertificate(block.Bytes)
-		if err != nil {
-			return "", fmt.Errorf("could not parse the server certificate %v", err)
-		}
-		if !(cert.KeyUsage&x509.KeyUsageKeyEncipherment > 0) {
-			return "", fmt.Errorf("no key encipherment usage for the server certificate")
-		}
-		for i := 0; i < len(certs)-1; i++ {
-			bundle += certs[i]
-		}
-
-		var opts x509.VerifyOptions
+	intermediatePool := x509.NewCertPool()
+	if !intermediatePool.AppendCertsFromPEM([]byte(bundle)) {
+		return "", errors.New("certificate CA bundle is empty")
+	}
 
+	opts := x509.VerifyOptions{
+		Intermediates: intermediatePool,
+	}
+	if rootCA != "" {
+		// verify the certificate chain.
 		rootPool := x509.NewCertPool()
-		if rootCA != "" {
-			if !rootPool.AppendCertsFromPEM([]byte(rootCA)) {
-				return "", fmt.Errorf("root  CA certificate is empty, %v", err)
-			}
-		}
-
-		intermediatePool := x509.NewCertPool()
-		if !intermediatePool.AppendCertsFromPEM([]byte(bundle)) {
-			return "", fmt.Errorf("certificate CA bundle is empty, %v", err)
-		}
-
-		if rootCA != "" {
-			// verify the certificate chain.
-			opts = x509.VerifyOptions{
-				Intermediates: intermediatePool,
-				Roots:         rootPool,
-			}
-		} else {
-			opts = x509.VerifyOptions{
-				Intermediates: intermediatePool,
-			}
+		if !rootPool.AppendCertsFromPEM([]byte(rootCA)) {
+			return "", errors.New("unable to parse root CA certificate")
 		}
+		opts.Roots = rootPool
+	}
 
-		chain, err := cert.Verify(opts)
-		if err != nil {
-			return "", fmt.Errorf("could verify the certificate chain %v", err)
-		}
-		if len(chain) > 0 {
-			for _, link := range chain[0] {
-				// Only print non-self signed elements of the chain
-				if link.AuthorityKeyId != nil && !bytes.Equal(link.AuthorityKeyId, link.SubjectKeyId) {
-					block := &pem.Block{Type: "CERTIFICATE", Bytes: link.Raw}
-					pemEncodedChain += string(pem.EncodeToMemory(block))
-				}
-			}
-		} else {
-			return "", fmt.Errorf("Can't find valid chain for cert in file in request")
+	chain, err := cert.Verify(opts)
+	if err != nil {
+		return "", 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")
+	}
+	pemEncodedChain := ""
+	for _, link := range chain[0] {
+		// Only print non-self signed elements of the chain
+		if link.AuthorityKeyId != nil && !bytes.Equal(link.AuthorityKeyId, link.SubjectKeyId) {
+			block := &pem.Block{Type: "CERTIFICATE", Bytes: link.Raw}
+			pemEncodedChain += string(pem.EncodeToMemory(block))
 		}
-	} else {
-		return "", fmt.Errorf("ERROR: no certificate chain to verify")
 	}
 
-	base64EncodedStr := base64.StdEncoding.EncodeToString([]byte(pemEncodedChain))
-
-	return base64EncodedStr, nil
+	return pemEncodedChain, nil
 }
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go b/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go
index 8c92aa9..14b30a3 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go
@@ -20,153 +20,143 @@ package deliveryservice
  */
 
 import (
-	"encoding/base64"
 	"strings"
 	"testing"
 )
 
 const (
-	BadData = "This is bad data and it is not base64 encoded"
+	BadData = "This is bad data and it is not pem encoded"
 
 	SelfSigneCertOnly = `
-LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURrakNDQW5vQ0NRQ2Z3ZDIxOUpLcFVEQU5C
-Z2txaGtpRzl3MEJBUXNGQURDQmlqRUxNQWtHQTFVRUJoTUMKVlZNeEVUQVBCZ05WQkFnTUNFTnZi
-Rzl5WVdSdk1ROHdEUVlEVlFRSERBWkVaVzUyWlhJeEVEQU9CZ05WQkFvTQpCME52YldOaGMzUXhE
-akFNQmdOVkJBc01CWFpwY0dWeU1SVXdFd1lEVlFRRERBeDNkM2N1ZEdWemRDNXZjbWN4CkhqQWNC
-Z2txaGtpRzl3MEJDUUVXRDIxcFkydGxlVUIwWlhOMExtOXlaekFlRncweE56RXhNVFl4TmpNNU1U
-TmEKRncweU56RXhNVFF4TmpNNU1UTmFNSUdLTVFzd0NRWURWUVFHRXdKVlV6RVJNQThHQTFVRUNB
-d0lRMjlzYjNKaApaRzh4RHpBTkJnTlZCQWNNQmtSbGJuWmxjakVRTUE0R0ExVUVDZ3dIUTI5dFky
-RnpkREVPTUF3R0ExVUVDd3dGCmRtbHdaWEl4RlRBVEJnTlZCQU1NREhkM2R5NTBaWE4wTG05eVp6
-RWVNQndHQ1NxR1NJYjNEUUVKQVJZUGJXbGoKYTJWNVFIUmxjM1F1YjNKbk1JSUJJakFOQmdrcWhr
-aUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBNm02agppQU1KcExNeFpoSVVFOURyUHZuaTA2
-TmViTFJhaDFSUzgrUjNKM1BOMVhDY2d3d1VaaWZaQnBQZ2FTYXBGWGJ2ClpkamxyZlpGcGtBZmdG
-UVhseUdhZTZCVStuNEN3TmxEZGdvMVhiRWM4cW9HSWRzN2FZSEVrclFadFp5aCtYRlkKMkJSdlM2
-Y2JHR0VjMngwdzVJa1hhMTM2V0NKY0x0QnpkVDdGQVZRSlZodTl4UFBuWGs4aWdUWmc2dEZ0MjdF
-YgplYkhDVWVEQXJHVVJGaUZXZFhtOGRHQ1BVVkNaeFNDdnh1WGxJMTVkZGdmcDlHYkZYeENVUDVW
-UjlQajZCdHFlCjdReW1GUk9zSWtscEN3NDZlYTBBODdpa1ZNYWRQQzIxVHViZmF5VUFNUTh4bDYw
-aW94NVk4OWc0WEZyRWdreWQKV3hobVBXclZwVlFyUERXS2d3SURBUUFCTUEwR0NTcUdTSWIzRFFF
-QkN3VUFBNElCQVFDWlpXNnJsbi9LYkdWbgpVWis3RFY5UFVCNHIyNUI5d3JSQUx5OHJRdzNVQWVQ
-SFJxWmlBT1ZOV3hycjM5Njd6ZFBNYzhkMWtZY2t0K2NHCkcxUFU1QmNiVVZuUzJxRTBUa2Z2cWo2
-citPaWNrcnU2dEtmWERhcU1PRXRmTmFud1Q5dURaQ1RlT2FpU0hCengKRnBQLzlURDA1Z0VZYmQx
-VzRSUnpUNi9TN3lMWTB1WWhWQUhGZGwyZTd6T2podHk0aURQRjA0ZmQrWHlaKzNXUwpJeFNnYU1y
-VHAwMG1hRnRicFBuaFRheElHek1ZdG9kaTZGYVVjT21CZk1scFJHS3lrc04wWjNlSjZSNm5oTWIz
-ClJHSjludUdMS3ZxUzV1OUJnZ2NEd28xcXYyazhNY2RTZzZwbEs2WG9kTHlNZEJWVEI2Szdod1N6
-MXVWcDNtWDEKSFZHRTQrb3UKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=`
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAnoCCQCfwd219JKpUDANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMC
+VVMxETAPBgNVBAgMCENvbG9yYWRvMQ8wDQYDVQQHDAZEZW52ZXIxEDAOBgNVBAoM
+B0NvbWNhc3QxDjAMBgNVBAsMBXZpcGVyMRUwEwYDVQQDDAx3d3cudGVzdC5vcmcx
+HjAcBgkqhkiG9w0BCQEWD21pY2tleUB0ZXN0Lm9yZzAeFw0xNzExMTYxNjM5MTNa
+Fw0yNzExMTQxNjM5MTNaMIGKMQswCQYDVQQGEwJVUzERMA8GA1UECAwIQ29sb3Jh
+ZG8xDzANBgNVBAcMBkRlbnZlcjEQMA4GA1UECgwHQ29tY2FzdDEOMAwGA1UECwwF
+dmlwZXIxFTATBgNVBAMMDHd3dy50ZXN0Lm9yZzEeMBwGCSqGSIb3DQEJARYPbWlj
+a2V5QHRlc3Qub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6m6j
+iAMJpLMxZhIUE9DrPvni06NebLRah1RS8+R3J3PN1XCcgwwUZifZBpPgaSapFXbv
+ZdjlrfZFpkAfgFQXlyGae6BU+n4CwNlDdgo1XbEc8qoGIds7aYHEkrQZtZyh+XFY
+2BRvS6cbGGEc2x0w5IkXa136WCJcLtBzdT7FAVQJVhu9xPPnXk8igTZg6tFt27Eb
+ebHCUeDArGURFiFWdXm8dGCPUVCZxSCvxuXlI15ddgfp9GbFXxCUP5VR9Pj6Btqe
+7QymFROsIklpCw46ea0A87ikVMadPC21TubfayUAMQ8xl60iox5Y89g4XFrEgkyd
+WxhmPWrVpVQrPDWKgwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCZZW6rln/KbGVn
+UZ+7DV9PUB4r25B9wrRALy8rQw3UAePHRqZiAOVNWxrr3967zdPMc8d1kYckt+cG
+G1PU5BcbUVnS2qE0Tkfvqj6r+Oickru6tKfXDaqMOEtfNanwT9uDZCTeOaiSHBzx
+FpP/9TD05gEYbd1W4RRzT6/S7yLY0uYhVAHFdl2e7zOjhty4iDPF04fd+XyZ+3WS
+IxSgaMrTp00maFtbpPnhTaxIGzMYtodi6FaUcOmBfMlpRGKyksN0Z3eJ6R6nhMb3
+RGJ9nuGLKvqS5u9BggcDwo1qv2k8McdSg6plK6XodLyMdBVTB6K7hwSz1uVp3mX1
+HVGE4+ou
+-----END CERTIFICATE-----
+`
 	GoodTLSKeys = `
-LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUYzRENDQThTZ0F3SUJBZ0lDRUFBd0RRWUpL
-b1pJaHZjTkFRRUxCUUF3Z1l3eEN6QUpCZ05WQkFZVEFsVlQKTVJFd0R3WURWUVFJREFoRGIyeHZj
-bUZrYnpFa01DSUdBMVVFQ2d3YlNYQmpaRzRnUTJWeWRHbG1hV05oZEdVZwpRWFYwYUc5eWFYUjVN
-U1F3SWdZRFZRUUxEQnRKY0dOa2JpQkRaWEowYVdacFkyRjBaU0JCZFhSb2IzSnBkSGt4CkhqQWNC
-Z05WQkFNTUZVbHdZMlJ1SUVsdWRHVnliV1ZrYVdGMFpTQkRRVEFlRncweE56RXhNVFl5TURVd01U
-bGEKRncweU5qQXlNREl5TURVd01UbGFNSEF4Q3pBSkJnTlZCQVlUQWxWVE1SRXdEd1lEVlFRSURB
-aERiMnh2Y21GawpiekVQTUEwR0ExVUVCd3dHUkdWdWRtVnlNUTh3RFFZRFZRUUtEQVpKY0dOa2Jp
-QXhFakFRQmdOVkJBc01DVWx3ClkyUnVJR1JsZGpFWU1CWUdBMVVFQXd3UGQzZDNMbVY0WVcxd2JH
-VXVZMjl0TUlJQklqQU5CZ2txaGtpRzl3MEIKQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMWg5Zlh3
-SjE3UVlOTVhNNWpFZ0hlY1Z4V20rQ05QUWJpMk8wYUxtNQpsYUV1b2N0bC94bmNsRGdrT2NWNTBz
-SWdVUlNuYVJYSENNYTkzemI5NXhRZWZUSXZSRi8xa1U5ZTY4bW1Gano4CmZyQWRPYU05MFRkVWYx
-eXYyNlczN25UOUR4MjZDQWlTd0FMWFZkeCs0b1Bvck5IdjIweDNxUGJzKzNjRHVuQWYKL1hWWis2
-dHhuOVZzZzAwb2RIWm9mcVpibUdUdkcveWJRY0dQalJQYVdZSGFMYWZqcERCM3dQc0REdTBMMGJY
-VApITlE4Vld6S3drOFVRdHpndEt4WEFFMlp3TFNkUVdzV0VLSEZGTmthT3F3ZnEyMVVZdmN0NHEy
-cnE5MXREbmJhCmZxTWpOTnNxVmtYZFIyNFdjUDhtZ1YxY3NWTkx1WmhtUWFCTlo2dytoR2l0aVFJ
-REFRQUJvNElCWVRDQ0FWMHcKQ1FZRFZSMFRCQUl3QURBUkJnbGdoa2dCaHZoQ0FRRUVCQU1DQmtB
-d013WUpZSVpJQVliNFFnRU5CQ1lXSkU5dwpaVzVUVTB3Z1IyVnVaWEpoZEdWa0lGTmxjblpsY2lC
-RFpYSjBhV1pwWTJGMFpUQWRCZ05WSFE0RUZnUVVpWmVaCjVVbXdGRjFWQ2dwd1hmM2crcTFGUzZN
-d2djTUdBMVVkSXdTQnV6Q0J1SUFVSVY3aXF0Myt4WWExRngvbll6eGQKMWh4dk53MmhnWnVrZ1pn
-d2daVXhDekFKQmdOVkJBWVRBbFZUTVJFd0R3WURWUVFJREFoRGIyeHZjbUZrYnpFUApNQTBHQTFV
-RUJ3d0dSR1Z1ZG1WeU1TUXdJZ1lEVlFRS0RCdEpjR05rYmlCRFpYSjBhV1pwWTJGMFpTQkJkWFJv
-CmIzSnBkSGt4SkRBaUJnTlZCQXNNRzBsd1kyUnVJRU5sY25ScFptbGpZWFJsSUdGMWRHaHZjbWww
-ZVRFV01CUUcKQTFVRUF3d05TWEJqWkc0Z1VtOXZkQ0JEUVlJQ0VBQXdEZ1lEVlIwUEFRSC9CQVFE
-QWdXZ01CTUdBMVVkSlFRTQpNQW9HQ0NzR0FRVUZCd01CTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElD
-QVFCSFgrWW1PNlRMYk1UWkJ5dXdyZ2lICnV5N3JQenBYVFhTSnZVTSt1cHhTZW5ybXo4SDVmQnp5
-cExmS0UxTk9LNThScjI1T3lBZDFJcWdHMUlkKzh5Y2cKYXRldGpJMXBvYU5DWnZLUFJyNDh3amNU
-VnNmZ3g3SFhXMGZ5a0kwS1QyMzlPazR1c0VNM3VxbWJrbjdBbm5mNwpkYnk4Qkt6NHA5bjF5ZTdl
-SHBpcHUxQTVXeGpCUWVEeW1sUHcvQ005RTB2NUYvaGdpV3hXK2U4bDV1N2g0M2JQCjFCTk82UEpY
-Si9HT05pUWg0YmNMMFI3NjN0TklLR1ZOWUhTZmZXNzF2eW9ZNnJlWGRLQk5uazkxT2dqRndIVE4K
-QUxKdHI5ank1eHk5dktBVFk3Z1RoVldEaFcvdWl2OExVSUN4eFpXbkN1Y0t2aGdCMmJMV2FIeElP
-cjlZeWphWApoRVZkSGdUVlhQbDVjTVhCdytVWkxuM3Z3NUVRSHVNRkFJV1IyWk5JaHJFdmphUG9u
-NXFhRXZlUUNEc2RhMzl3CnJUcjNsaGV5QkdNaFRubUE0d05WK2xOU0xJbUFjMm83OGFldGUwY1Rz
-SjYxOXNuR09EVW85UU8yWVovazd2UFMKbUhlSzBWclp2bkU4dWtsRkpVVERheUxvRCtTbnN4enRS
-SVR2ay9FdVJheTJQMWZHMS9xWm43UVVJZytaTTRhVgpTOHZQcmZJOXJ3dThDUmd4bVRUdFg1Wk1l
-ejg5Znk2RmxWRElUalZOaFJyVkljMm0zeEwwM0FTVGI2TmFua0pvCkVuK01MUXBDRlZLeVF5OU43
-MlJaTno2OEtpUEgvZnJhQWRxNG1MNU5BY1I0UC82R2c3U24rcWpuZi80bDQzeloKKzd1enFqd2hk
-dFUvWUhKOWo4L2Nvdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJU
-SUZJQ0FURS0tLS0tCk1JSUdCVENDQSsyZ0F3SUJBZ0lDRUFBd0RRWUpLb1pJaHZjTkFRRUxCUUF3
-Z1pVeEN6QUpCZ05WQkFZVEFsVlQKTVJFd0R3WURWUVFJREFoRGIyeHZjbUZrYnpFUE1BMEdBMVVF
-Qnd3R1JHVnVkbVZ5TVNRd0lnWURWUVFLREJ0SgpjR05rYmlCRFpYSjBhV1pwWTJGMFpTQkJkWFJv
-YjNKcGRIa3hKREFpQmdOVkJBc01HMGx3WTJSdUlFTmxjblJwClptbGpZWFJsSUdGMWRHaHZjbWww
-ZVRFV01CUUdBMVVFQXd3TlNYQmpaRzRnVW05dmRDQkRRVEFlRncweE56RXgKTVRZeU1ETTRNVFZh
-RncweU56RXhNVFF5TURNNE1UVmFNSUdNTVFzd0NRWURWUVFHRXdKVlV6RVJNQThHQTFVRQpDQXdJ
-UTI5c2IzSmhaRzh4SkRBaUJnTlZCQW9NRzBsd1kyUnVJRU5sY25ScFptbGpZWFJsSUVGMWRHaHZj
-bWwwCmVURWtNQ0lHQTFVRUN3d2JTWEJqWkc0Z1EyVnlkR2xtYVdOaGRHVWdRWFYwYUc5eWFYUjVN
-UjR3SEFZRFZRUUQKREJWSmNHTmtiaUJKYm5SbGNtMWxaR2xoZEdVZ1EwRXdnZ0lpTUEwR0NTcUdT
-SWIzRFFFQkFRVUFBNElDRHdBdwpnZ0lLQW9JQ0FRREtreFE5aGRNdFN3Zk5FQnFHUEFLenU3Q1Bo
-SCt4dTNrTDRlK3JKMDlFQisrZnhHOTA1bXdNClltOHMxR0MvaTFWMWhQYk9rK3pMV1hjY1podEM0
-OUJ0dHNEQlZSbWFndDRxNmVlRDEyQXh6VkJveldqNFluRnkKWkUwNENpWmxBSU4zcU40VG5OVC9P
-M2l5dm1qNThRRElGVk81MVlOU3JyN2oyZFFSTHBveVM2czg3a3B3OUE2VAoyNEwxcExrbUZ1QWdD
-TE1GUEc1SFpXeVpTU3RwWE96T2M3TElUWlFYUXp1bndMYXpOOVo0QXo4ellDOWlsTzZWCnROTk5j
-K1k3TXBGclRhRUZGU3NNMitSRWV4dVB0Q090VC9aRWNPd1A4ODRUNkFDY1VTVHY4NmlFL0VGT1Bn
-WmgKdlRLMkQwTnphdDNaVHNjNU4ydnZOMGVabTZDT25WQXZZTndyVFdHNHYzWVV0THIvUEVvRm05
-bXRQZFNBK1RzaQpMa0dGUmp3QW9BbmhWaWVGQUZ1bFFuc3diWkFhSlJjL3hTN0JKdnRzLzNKOWk3
-bDFvcHF1MEVibTZMOGpMZUh2CnAvb3AxVEQ4TElRa2NwN0dkc1hrNExZSDZWb3BhTk9pOHlvYUVm
-S1d3clhoeEJkQ2hISGxZQ2NmZWN5RDhPMzkKOGV1b0dRMHppL2VhQ3IzTUhZVTErYTIrNVRSUGR6
-SHgvbC8zVjF3eFg5aG1PR2Nyd1RDdGNZUnpSanphMlVsRQpVYWNtd0JxR3lmYTFHbi9pT3RvOXlx
-dFJ2V2xQR3E5ekpOUXpOQko2aVdSN2d5YjB0ODIwanBkdG1GeU5CNVB2CkpjZUh5VnlpeC83c0JV
-QjVHd01PMGlHbkxQcFk5SXg4N25ZUDNpdE4zamtxYWhUclQ3dEh1d0lEQVFBQm8yWXcKWkRBZEJn
-TlZIUTRFRmdRVUlWN2lxdDMreFlhMUZ4L25ZenhkMWh4dk53MHdId1lEVlIwakJCZ3dGb0FVV2Nk
-SQpCUjZ0M044dzd5VXQvVE9mWHdtdWJBZ3dFZ1lEVlIwVEFRSC9CQWd3QmdFQi93SUJBREFPQmdO
-VkhROEJBZjhFCkJBTUNBWVl3RFFZSktvWklodmNOQVFFTEJRQURnZ0lCQUtiZDhuS0ExaGx4Q1Rj
-elRnOVBIU2RxSFZFWVdxUkQKZHpyb09uejBLY0lnSkY0bmNSYU4zbm5hNzR3SW0zbkpEL1d1d2RG
-OGRWYnBENFlhZVpLaFFnbVhtWWdnVkgwbAo4SUlrZEMzcVlOVERqNHhoZzdxWkMzcHpLdU5JZzd5
-SHYzQXhyL3JiOUJ2cFVKeGJLby9hbG4vRzZQcmJOb1F4CjR4YjZ4bEs2V2NZT1JCL1VnekY2aktN
-NUNCWGFVdDJRUW1XdHM3TWdub056WjRreHNZYnV3ajNyT1B6SElnUlkKWXdKdCtraDV0bHloSFBr
-Z2p3VVRiTWcvTXYvb21melozK1hNQkQyWjY5ZU5kOVJIRTlYUzZBZE1LdERpcHJoZwpUTHUrOXRP
-Vmx5ZFFqWmszS3NxRnY1Ny8xVHdLcnQ5SkZqWGsvUFBRYWxYb1Azb3lrb2l2aWFjZDRNeWlCbWFX
-Cmk1V2J0Y3hHUDV2d2FObjI2N09HbGliZlFtUWdBMVZJZ0RxZnRyUXdlNlQvWndPS1hxRnFiNTZn
-cWRXNFZkT1UKNWJHTjB1TFhlbXJpdU5Rb2xUcFZtaE51MGJOSTVXQ2lZN2MzMFhOMk01ZWJjQldE
-SE9yNERPQ2crbW1YK3RKVApHaTFqdmZtQTZMT1lueVE4eEFWMDgwdVZlMzVOUTEwZTlteTZMdVhN
-aVE3dWJ2SFVTNU53YVFDRnBMREl2YmhmCjJYVmM0Nk5kMFYvYm9sTTIzQVFSbHp1bzBJU3NEU2VX
-U1FWTSt1UVorcExlOUc1bjJNeHFGZDg0VnU0ODlhdWMKMDJJOWNIaU5haFd5WFB0dm52TVd3SW1J
-QjMwQ1loaDVCeUdXbmVEbzNkNVpqMkhBQTZGd082N0xsSWhTZTdxegpheER0Y000bk8zUUgKLS0t
-LS1FTkQgQ0VSVElGSUNBVEUtLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJR0Vq
-Q0NBL3FnQXdJQkFnSUpBTDJWMWhuTFd1emdNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1JR1ZNUXN3Q1FZ
-RApWUVFHRXdKVlV6RVJNQThHQTFVRUNBd0lRMjlzYjNKaFpHOHhEekFOQmdOVkJBY01Ca1JsYm5a
-bGNqRWtNQ0lHCkExVUVDZ3diU1hCalpHNGdRMlZ5ZEdsbWFXTmhkR1VnUVhWMGFHOXlhWFI1TVNR
-d0lnWURWUVFMREJ0SmNHTmsKYmlCRFpYSjBhV1pwWTJGMFpTQmhkWFJvYjNKcGRIa3hGakFVQmdO
-VkJBTU1EVWx3WTJSdUlGSnZiM1FnUTBFdwpIaGNOTVRjeE1URTJNakF4T1RJMFdoY05NamN4TVRF
-ME1qQXhPVEkwV2pDQmxURUxNQWtHQTFVRUJoTUNWVk14CkVUQVBCZ05WQkFnTUNFTnZiRzl5WVdS
-dk1ROHdEUVlEVlFRSERBWkVaVzUyWlhJeEpEQWlCZ05WQkFvTUcwbHcKWTJSdUlFTmxjblJwWm1s
-allYUmxJRUYxZEdodmNtbDBlVEVrTUNJR0ExVUVDd3diU1hCalpHNGdRMlZ5ZEdsbQphV05oZEdV
-Z1lYVjBhRzl5YVhSNU1SWXdGQVlEVlFRRERBMUpjR05rYmlCU2IyOTBJRU5CTUlJQ0lqQU5CZ2tx
-CmhraUc5dzBCQVFFRkFBT0NBZzhBTUlJQ0NnS0NBZ0VBMkhzTGtubTl3eDFWMzN6dHRNV24xc0ZF
-SnlMTk1lZVcKaEEwZHdlS0NocURWdzVsQXlJaWQwbHFqbmpJRWl2bEFNOHpkMk5BUFpUSEZHOUJU
-M3VuZHVOY0RjV3VSZ2gzMwptbHlzc0VoYXJXdEU2VTdsenc4Uk1HV2t5V1FrSjJFMFN4akUvVm1L
-UWpIMy80QWs4U2hoVFpGS0VadXdlUmRnCmoyMThxVWVtc09WK0VOVHNuR1V4b0FQcHI1Y0dHbzRp
-Z2ZPOXRwSTFnN1BXbmtZclZGdHdzUG95MkNLeHFoL0kKM0Y2N0VacTJ5Uk9CeTlnQmhDNUZ1Wmh1
-dmdwdHZTYWtOUXkvdys5YnVSZmZzaGI2OXdMc2JxUWF5aGpsTHFjUQpYa2NoNHk2Y0c4WWxnK2hy
-cXptRzN2RzRxMDNZRno4UHVNZC91TnhlSlFBYlpKL3NYaDdqVlFOSml0Z2k2b095CmoxeFZ6TktV
-cWIxTXgyNURoQnkxMjUvbDh3R0Jkc0NSVVlSNnI3ME5BWlJuZGprUUtWNGwzdFRRNCtvMnJkamQK
-Qy8yU2syL2JIVmJ5dE1xNEl6KzFzT3NJVVYzTGErUitEV2NMQTZVb25wRW9jTmI4YnQ1YnU0SmhS
-RHJuSndQaQo0alJhSCtLZ3hwQlRJbFozYUZuU3MwSTN3a1BPZ0EzRHJJNkxXeGd0M0JmUHVLOURQ
-bWExcmM0QjFjd1NRVE5rCnl5VVkyYm9Yc25MTU1QZWJGM2Rqd2J0WUVkcUFhaXh4enpRQ1ZZbGhm
-Q0VRanFjZVNkNlRKMlNkekg0STNKN3gKT3NMejFMai85MmFEZWVxNzdxL2M5RmlkbmZOZTc1ekI3
-Z1hOL2JUdGI1NVpjVFRPOFhBRXZlZ3hjcnc1Q25PMQpNbkZ3NnhEZisrVUNBd0VBQWFOak1HRXdI
-UVlEVlIwT0JCWUVGRm5IU0FVZXJkemZNTzhsTGYwem4xOEpybXdJCk1COEdBMVVkSXdRWU1CYUFG
-Rm5IU0FVZXJkemZNTzhsTGYwem4xOEpybXdJTUE4R0ExVWRFd0VCL3dRRk1BTUIKQWY4d0RnWURW
-UjBQQVFIL0JBUURBZ0dHTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElDQVFCK2FZV1poKy9nQ21GeQpv
-STU4MkFDNSs1NGM3eGVMUm10UVBtRnBBQTJZNGlUU2VHeWp2Mmc1TTlhZ1E0SXh3dWU1RGx1UWxz
-RGNEc0p3CmxzWFZIeUFsQ2Y2bkRiSk9wZjVtNml4ZnZCRitRekVlWGpVRzc0aVNDV3JBcFlGbXNO
-c0NybHNNL0VQSm9ncXUKN2NnR3ZId1dZTmpQenV3b1UwQVdITzlGZ0liRHozTWMxNVpsSElRMlQv
-aXh4eUJmcElQYzVEOTFrNHUvWldTYgpoTzZsc00xaUVBdnY5VG9VWGtLdHRDUTBmTjM0QndZWDQ3
-QXhDNzF0U3Q5L1ZLSURJRVhqenFKSnBiSmRCR1NtCld1aVpIV3dCelZ3N2s1eStTK3dNNXZaL09N
-dzB0aEwrSTUzem1reEdFZjN0TUg0UE9lS3ZYL3UxOW4wVEZrLzEKOTZjenRWbVRCNlc2N21iOXpa
-OHlTZUp0RDl1WEU0NHljeGs5M2dUbmFya0lHZFRmOFhvbkNWbGtIR3BiNlRXTQo1RTdhV0NvVmJx
-UVJrRjFycVB6YThoUkpHSDFFR2ttZGJrdXlVTUxtUTFGSks5Zi94RkljcmRCR3BNbHh5T29MCk1T
-ZUZlYWdvU0xOcTV4emp1Y0YvNm1rQVVKOFVaQXhyU0dtYURFYVN0MS9xSlJIb3ZIY3QyYjVGV1pM
-dVJ0MGcKZkRzR29LVDhJRnVhcFNzbUZFSW52RDBXS1hEU1BsVThyVHkxWkJEbENxcDNlTkg0dENm
-TGFoazd2TEEwSmJmNwpVTHJ0RG5yTmZqeFVZRmNGMFJjYXVSMWRsclFRUkFzMzFRT3pYK0pPcjRn
-VUc3eVhhM2o2NG54Mkc1TXBMZ1NvCk9FVWpmYWtLNzErVi9IYlF0NDc3elI0azdjUmJpQT09Ci0t
-LS0tRU5EIENFUlRJRklDQVRFLS0tLS0K`
-
+-----BEGIN CERTIFICATE-----
+MIIF3DCCA8SgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgYwxCzAJBgNVBAYTAlVT
+MREwDwYDVQQIDAhDb2xvcmFkbzEkMCIGA1UECgwbSXBjZG4gQ2VydGlmaWNhdGUg
+QXV0aG9yaXR5MSQwIgYDVQQLDBtJcGNkbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkx
+HjAcBgNVBAMMFUlwY2RuIEludGVybWVkaWF0ZSBDQTAeFw0xNzExMTYyMDUwMTla
+Fw0yNjAyMDIyMDUwMTlaMHAxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhDb2xvcmFk
+bzEPMA0GA1UEBwwGRGVudmVyMQ8wDQYDVQQKDAZJcGNkbiAxEjAQBgNVBAsMCUlw
+Y2RuIGRldjEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA1h9fXwJ17QYNMXM5jEgHecVxWm+CNPQbi2O0aLm5
+laEuoctl/xnclDgkOcV50sIgURSnaRXHCMa93zb95xQefTIvRF/1kU9e68mmFjz8
+frAdOaM90TdUf1yv26W37nT9Dx26CAiSwALXVdx+4oPorNHv20x3qPbs+3cDunAf
+/XVZ+6txn9Vsg00odHZofqZbmGTvG/ybQcGPjRPaWYHaLafjpDB3wPsDDu0L0bXT
+HNQ8VWzKwk8UQtzgtKxXAE2ZwLSdQWsWEKHFFNkaOqwfq21UYvct4q2rq91tDnba
+fqMjNNsqVkXdR24WcP8mgV1csVNLuZhmQaBNZ6w+hGitiQIDAQABo4IBYTCCAV0w
+CQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBkAwMwYJYIZIAYb4QgENBCYWJE9w
+ZW5TU0wgR2VuZXJhdGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUiZeZ
+5UmwFF1VCgpwXf3g+q1FS6MwgcMGA1UdIwSBuzCBuIAUIV7iqt3+xYa1Fx/nYzxd
+1hxvNw2hgZukgZgwgZUxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhDb2xvcmFkbzEP
+MA0GA1UEBwwGRGVudmVyMSQwIgYDVQQKDBtJcGNkbiBDZXJ0aWZpY2F0ZSBBdXRo
+b3JpdHkxJDAiBgNVBAsMG0lwY2RuIENlcnRpZmljYXRlIGF1dGhvcml0eTEWMBQG
+A1UEAwwNSXBjZG4gUm9vdCBDQYICEAAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQM
+MAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQBHX+YmO6TLbMTZByuwrgiH
+uy7rPzpXTXSJvUM+upxSenrmz8H5fBzypLfKE1NOK58Rr25OyAd1IqgG1Id+8ycg
+atetjI1poaNCZvKPRr48wjcTVsfgx7HXW0fykI0KT239Ok4usEM3uqmbkn7Annf7
+dby8BKz4p9n1ye7eHpipu1A5WxjBQeDymlPw/CM9E0v5F/hgiWxW+e8l5u7h43bP
+1BNO6PJXJ/GONiQh4bcL0R763tNIKGVNYHSffW71vyoY6reXdKBNnk91OgjFwHTN
+ALJtr9jy5xy9vKATY7gThVWDhW/uiv8LUICxxZWnCucKvhgB2bLWaHxIOr9YyjaX
+hEVdHgTVXPl5cMXBw+UZLn3vw5EQHuMFAIWR2ZNIhrEvjaPon5qaEveQCDsda39w
+rTr3lheyBGMhTnmA4wNV+lNSLImAc2o78aete0cTsJ619snGODUo9QO2YZ/k7vPS
+mHeK0VrZvnE8uklFJUTDayLoD+SnsxztRITvk/EuRay2P1fG1/qZn7QUIg+ZM4aV
+S8vPrfI9rwu8CRgxmTTtX5ZMez89fy6FlVDITjVNhRrVIc2m3xL03ASTb6NankJo
+En+MLQpCFVKyQy9N72RZNz68KiPH/fraAdq4mL5NAcR4P/6Gg7Sn+qjnf/4l43zZ
++7uzqjwhdtU/YHJ9j8/cow==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGBTCCA+2gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZUxCzAJBgNVBAYTAlVT
+MREwDwYDVQQIDAhDb2xvcmFkbzEPMA0GA1UEBwwGRGVudmVyMSQwIgYDVQQKDBtJ
+cGNkbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxJDAiBgNVBAsMG0lwY2RuIENlcnRp
+ZmljYXRlIGF1dGhvcml0eTEWMBQGA1UEAwwNSXBjZG4gUm9vdCBDQTAeFw0xNzEx
+MTYyMDM4MTVaFw0yNzExMTQyMDM4MTVaMIGMMQswCQYDVQQGEwJVUzERMA8GA1UE
+CAwIQ29sb3JhZG8xJDAiBgNVBAoMG0lwY2RuIENlcnRpZmljYXRlIEF1dGhvcml0
+eTEkMCIGA1UECwwbSXBjZG4gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR4wHAYDVQQD
+DBVJcGNkbiBJbnRlcm1lZGlhdGUgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDKkxQ9hdMtSwfNEBqGPAKzu7CPhH+xu3kL4e+rJ09EB++fxG905mwM
+Ym8s1GC/i1V1hPbOk+zLWXccZhtC49BttsDBVRmagt4q6eeD12AxzVBozWj4YnFy
+ZE04CiZlAIN3qN4TnNT/O3iyvmj58QDIFVO51YNSrr7j2dQRLpoyS6s87kpw9A6T
+24L1pLkmFuAgCLMFPG5HZWyZSStpXOzOc7LITZQXQzunwLazN9Z4Az8zYC9ilO6V
+tNNNc+Y7MpFrTaEFFSsM2+REexuPtCOtT/ZEcOwP884T6ACcUSTv86iE/EFOPgZh
+vTK2D0Nzat3ZTsc5N2vvN0eZm6COnVAvYNwrTWG4v3YUtLr/PEoFm9mtPdSA+Tsi
+LkGFRjwAoAnhVieFAFulQnswbZAaJRc/xS7BJvts/3J9i7l1opqu0Ebm6L8jLeHv
+p/op1TD8LIQkcp7GdsXk4LYH6VopaNOi8yoaEfKWwrXhxBdChHHlYCcfecyD8O39
+8euoGQ0zi/eaCr3MHYU1+a2+5TRPdzHx/l/3V1wxX9hmOGcrwTCtcYRzRjza2UlE
+UacmwBqGyfa1Gn/iOto9yqtRvWlPGq9zJNQzNBJ6iWR7gyb0t820jpdtmFyNB5Pv
+JceHyVyix/7sBUB5GwMO0iGnLPpY9Ix87nYP3itN3jkqahTrT7tHuwIDAQABo2Yw
+ZDAdBgNVHQ4EFgQUIV7iqt3+xYa1Fx/nYzxd1hxvNw0wHwYDVR0jBBgwFoAUWcdI
+BR6t3N8w7yUt/TOfXwmubAgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E
+BAMCAYYwDQYJKoZIhvcNAQELBQADggIBAKbd8nKA1hlxCTczTg9PHSdqHVEYWqRD
+dzroOnz0KcIgJF4ncRaN3nna74wIm3nJD/WuwdF8dVbpD4YaeZKhQgmXmYggVH0l
+8IIkdC3qYNTDj4xhg7qZC3pzKuNIg7yHv3Axr/rb9BvpUJxbKo/aln/G6PrbNoQx
+4xb6xlK6WcYORB/UgzF6jKM5CBXaUt2QQmWts7MgnoNzZ4kxsYbuwj3rOPzHIgRY
+YwJt+kh5tlyhHPkgjwUTbMg/Mv/omfzZ3+XMBD2Z69eNd9RHE9XS6AdMKtDiprhg
+TLu+9tOVlydQjZk3KsqFv57/1TwKrt9JFjXk/PPQalXoP3oykoiviacd4MyiBmaW
+i5WbtcxGP5vwaNn267OGlibfQmQgA1VIgDqftrQwe6T/ZwOKXqFqb56gqdW4VdOU
+5bGN0uLXemriuNQolTpVmhNu0bNI5WCiY7c30XN2M5ebcBWDHOr4DOCg+mmX+tJT
+Gi1jvfmA6LOYnyQ8xAV080uVe35NQ10e9my6LuXMiQ7ubvHUS5NwaQCFpLDIvbhf
+2XVc46Nd0V/bolM23AQRlzuo0ISsDSeWSQVM+uQZ+pLe9G5n2MxqFd84Vu489auc
+02I9cHiNahWyXPtvnvMWwImIB30CYhh5ByGWneDo3d5Zj2HAA6FwO67LlIhSe7qz
+axDtcM4nO3QH
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGEjCCA/qgAwIBAgIJAL2V1hnLWuzgMA0GCSqGSIb3DQEBCwUAMIGVMQswCQYD
+VQQGEwJVUzERMA8GA1UECAwIQ29sb3JhZG8xDzANBgNVBAcMBkRlbnZlcjEkMCIG
+A1UECgwbSXBjZG4gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSQwIgYDVQQLDBtJcGNk
+biBDZXJ0aWZpY2F0ZSBhdXRob3JpdHkxFjAUBgNVBAMMDUlwY2RuIFJvb3QgQ0Ew
+HhcNMTcxMTE2MjAxOTI0WhcNMjcxMTE0MjAxOTI0WjCBlTELMAkGA1UEBhMCVVMx
+ETAPBgNVBAgMCENvbG9yYWRvMQ8wDQYDVQQHDAZEZW52ZXIxJDAiBgNVBAoMG0lw
+Y2RuIENlcnRpZmljYXRlIEF1dGhvcml0eTEkMCIGA1UECwwbSXBjZG4gQ2VydGlm
+aWNhdGUgYXV0aG9yaXR5MRYwFAYDVQQDDA1JcGNkbiBSb290IENBMIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2HsLknm9wx1V33zttMWn1sFEJyLNMeeW
+hA0dweKChqDVw5lAyIid0lqjnjIEivlAM8zd2NAPZTHFG9BT3unduNcDcWuRgh33
+mlyssEharWtE6U7lzw8RMGWkyWQkJ2E0SxjE/VmKQjH3/4Ak8ShhTZFKEZuweRdg
+j218qUemsOV+ENTsnGUxoAPpr5cGGo4igfO9tpI1g7PWnkYrVFtwsPoy2CKxqh/I
+3F67EZq2yROBy9gBhC5FuZhuvgptvSakNQy/w+9buRffshb69wLsbqQayhjlLqcQ
+Xkch4y6cG8Ylg+hrqzmG3vG4q03YFz8PuMd/uNxeJQAbZJ/sXh7jVQNJitgi6oOy
+j1xVzNKUqb1Mx25DhBy125/l8wGBdsCRUYR6r70NAZRndjkQKV4l3tTQ4+o2rdjd
+C/2Sk2/bHVbytMq4Iz+1sOsIUV3La+R+DWcLA6UonpEocNb8bt5bu4JhRDrnJwPi
+4jRaH+KgxpBTIlZ3aFnSs0I3wkPOgA3DrI6LWxgt3BfPuK9DPma1rc4B1cwSQTNk
+yyUY2boXsnLMMPebF3djwbtYEdqAaixxzzQCVYlhfCEQjqceSd6TJ2SdzH4I3J7x
+OsLz1Lj/92aDeeq77q/c9FidnfNe75zB7gXN/bTtb55ZcTTO8XAEvegxcrw5CnO1
+MnFw6xDf++UCAwEAAaNjMGEwHQYDVR0OBBYEFFnHSAUerdzfMO8lLf0zn18JrmwI
+MB8GA1UdIwQYMBaAFFnHSAUerdzfMO8lLf0zn18JrmwIMA8GA1UdEwEB/wQFMAMB
+Af8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQB+aYWZh+/gCmFy
+oI582AC5+54c7xeLRmtQPmFpAA2Y4iTSeGyjv2g5M9agQ4Ixwue5DluQlsDcDsJw
+lsXVHyAlCf6nDbJOpf5m6ixfvBF+QzEeXjUG74iSCWrApYFmsNsCrlsM/EPJogqu
+7cgGvHwWYNjPzuwoU0AWHO9FgIbDz3Mc15ZlHIQ2T/ixxyBfpIPc5D91k4u/ZWSb
+hO6lsM1iEAvv9ToUXkKttCQ0fN34BwYX47AxC71tSt9/VKIDIEXjzqJJpbJdBGSm
+WuiZHWwBzVw7k5y+S+wM5vZ/OMw0thL+I53zmkxGEf3tMH4POeKvX/u19n0TFk/1
+96cztVmTB6W67mb9zZ8ySeJtD9uXE44ycxk93gTnarkIGdTf8XonCVlkHGpb6TWM
+5E7aWCoVbqQRkF1rqPza8hRJGH1EGkmdbkuyUMLmQ1FJK9f/xFIcrdBGpMlxyOoL
+MSeFeagoSLNq5xzjucF/6mkAUJ8UZAxrSGmaDEaSt1/qJRHovHct2b5FWZLuRt0g
+fDsGoKT8IFuapSsmFEInvD0WKXDSPlU8rTy1ZBDlCqp3eNH4tCfLahk7vLA0Jbf7
+ULrtDnrNfjxUYFcF0RcauR1dlrQQRAs31QOzX+JOr4gUG7yXa3j64nx2G5MpLgSo
+OEUjfakK71+V/HbQt477zR4k7cRbiA==
+-----END CERTIFICATE-----
+`
 	rootCA = `
 -----BEGIN CERTIFICATE-----
 MIIGEjCCA/qgAwIBAgIJAL2V1hnLWuzgMA0GCSqGSIb3DQEBCwUAMIGVMQswCQYD
@@ -209,32 +199,26 @@ OEUjfakK71+V/HbQt477zR4k7cRbiA==
 func TestVerifyAndEncodeCertificate(t *testing.T) {
 
 	// should fail bad base64 data
-	dat, err := verifyAndEncodeCertificate(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 = verifyAndEncodeCertificate(SelfSigneCertOnly, rootCA)
+	dat, err = verifyCertificate(SelfSigneCertOnly, rootCA)
 	if err == nil {
 		t.Errorf("Unexpected result, a certificate verification error should have occured")
 	}
 
 	// should pass
-	dat, err = verifyAndEncodeCertificate(GoodTLSKeys, rootCA)
+	dat, err = verifyCertificate(GoodTLSKeys, rootCA)
 	if err != nil {
 		t.Errorf("Test failure: %s", err)
 	}
 
-	pemCerts := make([]byte, base64.StdEncoding.EncodedLen(len(dat)))
-	_, err = base64.StdEncoding.Decode(pemCerts, []byte(dat))
-	if err != nil {
-		t.Errorf("Test failure: bad retrun value from verifyAndEncodeCertificate(): %v", err)
-	}
-
-	certs := strings.SplitAfter(string(pemCerts), "-----END CERTIFICATE-----")
+	certs := strings.SplitAfter(dat, PemCertEndMarker)
 	length := len(certs) - 1
 	if length != 2 {
-		t.Errorf("Test failure: expected 2 certs from verifyAndEncodeCertificate(), got: %d ", length)
+		t.Errorf("Test failure: expected 2 certs from verifyCertificate(), got: %d ", length)
 	}
 }
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/sslkeys.go b/traffic_ops/traffic_ops_golang/deliveryservice/sslkeys.go
index d313608..16b87cf 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/sslkeys.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/sslkeys.go
@@ -75,12 +75,12 @@ func generatePutRiakKeys(req tc.DeliveryServiceSSLKeysReq, tx *sql.Tx, cfg *conf
 		}
 		dsSSLKeys.Certificate = tc.DeliveryServiceSSLKeysCertificate{Crt: string(crt), Key: string(key), CSR: string(csr)}
 	}
-	if err := riaksvc.PutDeliveryServiceSSLKeysObjTx(dsSSLKeys, tx, cfg.RiakAuthOptions); err != nil {
+	if err := riaksvc.PutDeliveryServiceSSLKeysObj(dsSSLKeys, tx, cfg.RiakAuthOptions); err != nil {
 		return errors.New("putting riak keys: " + err.Error())
 	}
 
 	dsSSLKeys.Version = riaksvc.DSSSLKeyVersionLatest
-	if err := riaksvc.PutDeliveryServiceSSLKeysObjTx(dsSSLKeys, tx, cfg.RiakAuthOptions); err != nil {
+	if err := riaksvc.PutDeliveryServiceSSLKeysObj(dsSSLKeys, tx, cfg.RiakAuthOptions); err != nil {
 		return errors.New("putting latest riak keys: " + err.Error())
 	}
 	return nil
diff --git a/traffic_ops/traffic_ops_golang/riaksvc/dsutil.go b/traffic_ops/traffic_ops_golang/riaksvc/dsutil.go
index 24f3d57..1ad1b57 100644
--- a/traffic_ops/traffic_ops_golang/riaksvc/dsutil.go
+++ b/traffic_ops/traffic_ops_golang/riaksvc/dsutil.go
@@ -56,35 +56,6 @@ func GetDeliveryServiceSSLKeysObj(xmlID string, version string, tx *sql.Tx, auth
 			return nil // not found
 		}
 		if err := json.Unmarshal(ro[0].Value, &key); err != nil {
-			return errors.New("unmarshalling Riak result: " + err.Error())
-		}
-		found = true
-		return nil
-	})
-	if err != nil {
-		return key, false, err
-	}
-	return key, found, nil
-}
-
-func GetDeliveryServiceSSLKeysObjTx(xmlID string, version string, tx *sql.Tx, authOpts *riak.AuthOptions) (tc.DeliveryServiceSSLKeys, bool, error) {
-	key := tc.DeliveryServiceSSLKeys{}
-	if version == "" {
-		xmlID += "-latest"
-	} else {
-		xmlID += "-" + version
-	}
-	found := false
-	err := WithClusterTx(tx, authOpts, func(cluster StorageCluster) error {
-		// get the deliveryservice ssl keys by xmlID and version
-		ro, err := FetchObjectValues(xmlID, DeliveryServiceSSLKeysBucket, cluster)
-		if err != nil {
-			return err
-		}
-		if len(ro) == 0 {
-			return nil // not found
-		}
-		if err := json.Unmarshal(ro[0].Value, &key); err != nil {
 			log.Errorf("failed at unmarshaling sslkey response: %s\n", err)
 			return errors.New("unmarshalling Riak result: " + err.Error())
 		}
@@ -118,27 +89,6 @@ func PutDeliveryServiceSSLKeysObj(key tc.DeliveryServiceSSLKeys, tx *sql.Tx, aut
 	return err
 }
 
-func PutDeliveryServiceSSLKeysObjTx(key tc.DeliveryServiceSSLKeys, tx *sql.Tx, authOpts *riak.AuthOptions) error {
-	keyJSON, err := json.Marshal(&key)
-	if err != nil {
-		return errors.New("marshalling key: " + err.Error())
-	}
-	err = WithClusterTx(tx, authOpts, func(cluster StorageCluster) error {
-		obj := &riak.Object{
-			ContentType:     "text/json",
-			Charset:         "utf-8",
-			ContentEncoding: "utf-8",
-			Key:             MakeDSSSLKeyKey(key.DeliveryService, string(key.Version)),
-			Value:           []byte(keyJSON),
-		}
-		if err = SaveObject(obj, DeliveryServiceSSLKeysBucket, cluster); err != nil {
-			return errors.New("saving Riak object: " + err.Error())
-		}
-		return nil
-	})
-	return err
-}
-
 func Ping(tx *sql.Tx, authOpts *riak.AuthOptions) (tc.RiakPingResp, error) {
 	servers, err := GetRiakServers(tx)
 	if err != nil {
@@ -235,28 +185,14 @@ func GetBucketKey(tx *sql.Tx, authOpts *riak.AuthOptions, bucket string, key str
 	return val, found, nil
 }
 
-func DeleteDSSSLKeys(tx *sql.Tx, authOpts *riak.AuthOptions, ds tc.DeliveryServiceName, version string) error {
-	if version == "" {
-		version = "latest"
-	}
-	key := string(ds) + "-" + version
-
-	cluster, err := GetRiakClusterTx(tx, authOpts)
-	if err != nil {
-		return errors.New("getting riak cluster: " + err.Error())
-	}
-	if err = cluster.Start(); err != nil {
-		return errors.New("starting riak cluster: " + err.Error())
-	}
-	defer func() {
-		if err := cluster.Stop(); err != nil {
-			log.Errorln("stopping Riak cluster: " + err.Error())
+func DeleteDSSSLKeys(tx *sql.Tx, authOpts *riak.AuthOptions, xmlID string, version string) error {
+	err := WithClusterTx(tx, authOpts, func(cluster StorageCluster) error {
+		if err := DeleteObject(MakeDSSSLKeyKey(xmlID, version), DeliveryServiceSSLKeysBucket, cluster); err != nil {
+			return errors.New("deleting SSL keys: " + err.Error())
 		}
-	}()
-	if err := DeleteObject(key, DeliveryServiceSSLKeysBucket, cluster); err != nil {
-		return errors.New("deleting SSL keys: " + err.Error())
-	}
-	return nil
+		return nil
+	})
+	return err
 }
 
 // GetURLSigConfigFileName returns the filename of the Apache Traffic Server URLSig config file
diff --git a/traffic_ops/traffic_ops_golang/routes.go b/traffic_ops/traffic_ops_golang/routes.go
index f9c2c84..72e7d05 100644
--- a/traffic_ops/traffic_ops_golang/routes.go
+++ b/traffic_ops/traffic_ops_golang/routes.go
@@ -361,13 +361,6 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) {
 		{1.1, http.MethodPut, `cdns/{id}/snapshot/?$`, crconfig.SnapshotHandler, auth.PrivLevelOperations, Authenticated, nil},
 		{1.1, http.MethodPut, `snapshot/{cdn}/?$`, crconfig.SnapshotHandler, auth.PrivLevelOperations, Authenticated, nil},
 
-		//SSLKeys deliveryservice endpoints here that are marked  marked as '-wip' need to have tenancy checks added
-
-		{1.3, http.MethodGet, `deliveryservices-wip/xmlId/{xmlID}/sslkeys$`, deliveryservice.GetSSLKeysByXMLID, auth.PrivLevelAdmin, Authenticated, nil},
-		{1.3, http.MethodGet, `deliveryservices-wip/hostname/{hostName}/sslkeys$`, deliveryservice.GetSSLKeysByHostName, auth.PrivLevelAdmin, Authenticated, nil},
-		{1.3, http.MethodPost, `deliveryservices-wip/hostname/{hostName}/sslkeys/add$`, deliveryservice.AddSSLKeys, auth.PrivLevelAdmin, Authenticated, nil},
-		{1.3, http.MethodGet, `deliveryservices/xmlId/{name}/sslkeys/delete$`, deliveryservice.DeleteSSLKeys, auth.PrivLevelAdmin, Authenticated, nil},
-
 		////DeliveryServices
 		{1.3, http.MethodGet, `deliveryservices/?(\.json)?$`, api.ReadHandler(deliveryservice.GetTypeV13Factory()), auth.PrivLevelReadOnly, Authenticated, nil},
 		{1.1, http.MethodGet, `deliveryservices/?(\.json)?$`, api.ReadHandler(deliveryservice.GetTypeV12Factory()), auth.PrivLevelReadOnly, Authenticated, nil},
@@ -381,6 +374,10 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) {
 		{1.1, http.MethodDelete, `deliveryservices/{id}/?(\.json)?$`, api.DeleteHandler(deliveryservice.GetTypeV12Factory()), auth.PrivLevelOperations, Authenticated, nil},
 		{1.1, http.MethodGet, `deliveryservices/{id}/servers/eligible/?(\.json)?$`, deliveryservice.GetServersEligible, auth.PrivLevelReadOnly, Authenticated, nil},
 
+		{1.1, http.MethodGet, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.GetSSLKeysByXMLID, auth.PrivLevelAdmin, Authenticated, nil},
+		{1.1, http.MethodGet, `deliveryservices/hostname/{hostname}/sslkeys$`, deliveryservice.GetSSLKeysByHostName, auth.PrivLevelAdmin, Authenticated, nil},
+		{1.1, http.MethodPost, `deliveryservices/sslkeys/add$`, deliveryservice.AddSSLKeys, auth.PrivLevelAdmin, Authenticated, nil},
+		{1.1, http.MethodGet, `deliveryservices/xmlId/{xmlid}/sslkeys/delete$`, deliveryservice.DeleteSSLKeys, auth.PrivLevelOperations, Authenticated, nil},
 		{1.1, http.MethodPost, `deliveryservices/sslkeys/generate/?(\.json)?$`, deliveryservice.GenerateSSLKeys, auth.PrivLevelOperations, Authenticated, nil},
 		{1.1, http.MethodPost, `deliveryservices/xmlId/{name}/urlkeys/copyFromXmlId/{copy-name}/?(\.json)?$`, deliveryservice.CopyURLKeys, auth.PrivLevelOperations, Authenticated, nil},
 		{1.1, http.MethodPost, `deliveryservices/xmlId/{name}/urlkeys/generate/?(\.json)?$`, deliveryservice.GenerateURLKeys, auth.PrivLevelOperations, Authenticated, nil},