You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ra...@apache.org on 2019/04/03 15:41:21 UTC

[trafficcontrol] branch master updated: Add enhanced X509 Certificate/Private RSA Key validation to Traffic Ops (AddSSLKeys Endpoint) (#3382)

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

rawlin 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 55690d7  Add enhanced X509 Certificate/Private RSA Key validation to Traffic Ops (AddSSLKeys Endpoint) (#3382)
55690d7 is described below

commit 55690d7497e87a5496db21243df252ee10e3e9ab
Author: Jeffrey Bevill <40...@users.noreply.github.com>
AuthorDate: Wed Apr 3 09:41:15 2019 -0600

    Add enhanced X509 Certificate/Private RSA Key validation to Traffic Ops (AddSSLKeys Endpoint) (#3382)
    
    * Fix add sslkeys endpoint to always use the input certificate
    
    Sometimes, the Certificate.Verify method will remove elements from a
    valid certificate chain. Instead of using the output of that method,
    always use the user input certificate and return a warning if the input
    certificate does not match the output of the Certificate.Verify method.
    
    Fixes #3398
    
    (cherry picked from commit dde742ec2a9c6fff5477b5a982a6ac4a58cd83a1)
    
    * Combine PR #3382 with PR #3417 and add ECDSA support for DNS delivery services
    
    * Update unit tests to fail faster
    
    * Update comments related to RSA/ECDSA key mismatch verification
    
    * Make decoding ECDSA PEM blocks more readable
    
    * Add Unit tests for ECDSA privateKey decoding with and without param pem block
    
    * Rename Unit test methods.
    Add unit test for encrypted ECDSA private key
    
    * Add unit test to verify DSA signed x509 certificates are rejected
    
    * Gofmt
    
    * Fix ECDSA unit tests
    Add ECDSA mismatched cert/key unit test
    Update error messages to be more meaningful
    
    * Add more unit tests related to critical x509 cert/key validation
    Missing RSA keyEncipherment unit test
    Missing ECDSA digitalSignature unit test
    Missing serverAuth extendedKeyUsage (x509v3 only) unit test
    
    * Add self-signed x509v1 server certificate unit test.
    
    * Remove redundant error message header.
    
    * Revert change, gofmt
    
    * Use getDSType() to permit ECDSA keys for only DNS* DS types.
    
    * Update tc.DSType.IsDNS() method to only include DNS DS types.
    
    * Use updated tc.DSType.isDNS() method to determine if DS is a DNS type.
    
    * Check errors returned from rsa/ecdsa private key decoding methods
    Minor changes to error message formatting and string comparison
    Re-sort go import statements
---
 lib/go-tc/enum.go                                  |    2 -
 .../traffic_ops_golang/deliveryservice/keys.go     |  343 ++++-
 .../deliveryservice/keys_test.go                   | 1434 +++++++++++++++++---
 3 files changed, 1583 insertions(+), 196 deletions(-)

diff --git a/lib/go-tc/enum.go b/lib/go-tc/enum.go
index de7a4ad..ce1e4fb 100644
--- a/lib/go-tc/enum.go
+++ b/lib/go-tc/enum.go
@@ -495,8 +495,6 @@ func (t DSType) IsHTTP() bool {
 // IsDNS returns whether the DSType is a DNS category.
 func (t DSType) IsDNS() bool {
 	switch t {
-	case DSTypeHTTPNoCache:
-		fallthrough
 	case DSTypeDNS:
 		fallthrough
 	case DSTypeDNSLive:
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/keys.go b/traffic_ops/traffic_ops_golang/deliveryservice/keys.go
index 7a82014..2923b41 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/keys.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/keys.go
@@ -20,15 +20,20 @@ package deliveryservice
  */
 
 import (
+	"bytes"
+	"crypto/ecdsa"
+	"crypto/rsa"
 	"crypto/x509"
 	"database/sql"
 	"encoding/base64"
 	"encoding/pem"
 	"errors"
+	"fmt"
 	"net/http"
 	"strings"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
+	"github.com/apache/trafficcontrol/lib/go-util"
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/riaksvc"
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
@@ -59,12 +64,23 @@ func AddSSLKeys(w http.ResponseWriter, r *http.Request) {
 		api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
 		return
 	}
-	certChain, isUnknownAuth, err := verifyCertificate(req.Certificate.Crt, "")
+
+	// ECDSA keys support is only permitted for DNS delivery services
+	// Traffic Router (HTTP* delivery service types) do not support ECDSA keys
+	dsType, dsFound, err := getDSType(inf.Tx.Tx, *req.Key)
+	allowEC := false
+	if err == nil && dsFound && dsType.IsDNS() {
+		allowEC = true
+	}
+
+	certChain, certPrivateKey, isUnknownAuth, isVerifiedChainNotEqual, err := verifyCertKeyPair(req.Certificate.Crt, req.Certificate.Key, "", allowEC)
 	if err != nil {
 		api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, errors.New("verifying certificate: "+err.Error()), nil)
 		return
 	}
 	req.Certificate.Crt = certChain
+	req.Certificate.Key = certPrivateKey
+
 	base64EncodeCertificate(req.Certificate)
 	dsSSLKeys := tc.DeliveryServiceSSLKeys{
 		CDN:             *req.CDN,
@@ -83,7 +99,11 @@ func AddSSLKeys(w http.ResponseWriter, r *http.Request) {
 		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")
+		api.WriteRespAlert(w, r, tc.WarnLevel, "WARNING: SSL keys were successfully added for '"+*req.DeliveryService+"', but the input certificate may be invalid (certificate is signed by an unknown authority)")
+		return
+	}
+	if isVerifiedChainNotEqual {
+		api.WriteRespAlert(w, r, tc.WarnLevel, "WARNING: SSL keys were successfully added for '"+*req.DeliveryService+"', but the input certificate may be invalid (certificate verification produced a different chain)")
 		return
 	}
 	api.WriteResp(w, r, "Successfully added ssl keys for "+*req.DeliveryService)
@@ -272,26 +292,111 @@ WHERE r.pattern = $2
 // certificate and its chain in the proper order. Returns a verified
 // and ordered certificate and CA chain.
 // 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) {
+// indicate that the certs are signed by an unknown authority (e.g. self-signed). Otherwise, return false.
+// If the chain returned from Certificate.Verify() does not match the input chain,
+// return true. Otherwise, return false.
+func verifyCertKeyPair(pemCertificate string, pemPrivateKey string, rootCA string, allowEC bool) (string, string, bool, bool, error) {
 	// decode, verify, and order certs for storage
-	certs := strings.SplitAfter(certificate, PemCertEndMarker)
+	cleanPemPrivateKey := ""
+	certs := strings.SplitAfter(pemCertificate, PemCertEndMarker)
 	if len(certs) <= 1 {
-		return "", false, errors.New("no certificate chain to verify")
+		return "", "", false, false, errors.New("no certificate chain to verify")
 	}
 
 	// decode and verify the server certificate
 	block, _ := pem.Decode([]byte(certs[0]))
 	if block == nil {
-		return "", false, errors.New("could not decode pem-encoded server certificate")
+		return "", "", false, false, errors.New("could not decode pem-encoded server certificate")
 	}
 	cert, err := x509.ParseCertificate(block.Bytes)
 	if err != nil {
-		return "", false, errors.New("could not parse the server certificate: " + err.Error())
+		return "", "", false, false, errors.New("could not parse the server certificate: " + err.Error())
 	}
-	if !(cert.KeyUsage&x509.KeyUsageKeyEncipherment > 0) {
-		return "", false, errors.New("no key encipherment usage for the server certificate")
+
+	// Common x509 certificate validation
+	err = commonX509CertificateValidation(cert)
+	if err != nil {
+		return "", "", false, false, err
 	}
+
+	switch cert.PublicKeyAlgorithm {
+	case x509.RSA:
+		var rsaPrivateKey *rsa.PrivateKey
+
+		// RSA is both a digital signature and encryption algorithm, hence the key encipherment
+		// usage must be indicated in the certificate.
+		// The keyUsage and extended Key Usage does not exist in version 1 of the x509 specificication.
+		if cert.Version > 1 && !(cert.KeyUsage&x509.KeyUsageKeyEncipherment > 0) {
+			return "", "", false, false, errors.New("cert/key (rsa) validation: no keyEncipherment keyUsage extension present in x509v3 server certificate")
+		}
+
+		// Extract the RSA public key from the x509 certificate
+		certPublicKey, ok := cert.PublicKey.(*rsa.PublicKey)
+		if !ok || certPublicKey == nil {
+			return "", "", false, false, errors.New("cert/key (rsa) validation error: could not extract public RSA key from certificate")
+		}
+
+		// Attempt to decode the RSA private key
+		rsaPrivateKey, cleanPemPrivateKey, err = decodeRSAPrivateKey(pemPrivateKey)
+		if err != nil {
+			return "", "", false, false, err
+		}
+
+		// Check RSA private key modulus against the x509 RSA public key modulus
+		if rsaPrivateKey != nil && certPublicKey != nil && !bytes.Equal(rsaPrivateKey.N.Bytes(), certPublicKey.N.Bytes()) {
+			return "", "", false, false, errors.New("cert/key (rsa) mismatch error: RSA public N modulus value mismatch")
+		}
+
+	case x509.ECDSA:
+		var ecdsaPrivateKey *ecdsa.PrivateKey
+
+		// Only permit ECDSA support for DNS* DSTypes until the Traffic Router can support it
+		if !allowEC {
+			return "", "", false, false, errors.New("cert/key validation error: ECDSA public key algorithm unsupported for non-DNS delivery service type")
+		}
+
+		// DSA and ECDSA is not an encryption algorithm and only a signing algorithm, hence the
+		// certificate only needs to have the DigitalSignature KeyUsage indicated.
+		if cert.Version > 1 && !(cert.KeyUsage&x509.KeyUsageDigitalSignature > 0) {
+			return "", "", false, false, errors.New("cert/key (ecdsa) validation error: no digitalSignature keyUsage extension present in x509v3 server certificate")
+		}
+
+		// Attempt to decode the ECDSA private key
+		ecdsaPrivateKey, cleanPemPrivateKey, err = decodeECDSAPrivateKey(pemPrivateKey)
+		if err != nil {
+			return "", "", false, false, err
+		}
+
+		// Extract the ECDSA public key from the x509 certificate
+		certPublicKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
+		if !ok || certPublicKey == nil {
+			return "", "", false, false, errors.New("cert/key (ecdsa) validation error: could not get extract public ECDSA key from certificate")
+		}
+
+		// Compare the ECDSA curve name contained within the x509.PublicKey against the curve name indicated in the private key
+		if certPublicKey.Params().Name != ecdsaPrivateKey.Params().Name {
+			return "", "", false, false, errors.New("cert/key (ecdsa) mismatch error: ECDSA curve name in cert does not match curve name in private key")
+		}
+
+		// Verify that ECDSA public value X matches in both the cert.PublicKey and the private key.
+		if !bytes.Equal(certPublicKey.X.Bytes(), ecdsaPrivateKey.X.Bytes()) {
+			return "", "", false, false, errors.New("cert/key (ecdsa) mismatch error: ECDSA public X value mismatch")
+		}
+
+		// Verify that ECDSA public value Y matches in both the cert.PublicKey and the private key.
+		if !bytes.Equal(certPublicKey.Y.Bytes(), ecdsaPrivateKey.Y.Bytes()) {
+			return "", "", false, false, errors.New("cert/key (ecdsa) mismatch error: ECDSA public Y value mismatch")
+		}
+
+	case x509.DSA:
+		return "", "", false, false, errors.New("cert/key validation error: DSA public key algorithm unsupported")
+
+	case x509.UnknownPublicKeyAlgorithm:
+		fallthrough
+	default:
+		return "", "", false, false, errors.New("cert/key validation error: Unknown public key algorithm")
+	}
+
 	bundle := ""
 	for i := 0; i < len(certs)-1; i++ {
 		bundle += certs[i]
@@ -299,17 +404,18 @@ func verifyCertificate(certificate string, rootCA string) (string, bool, error)
 
 	intermediatePool := x509.NewCertPool()
 	if !intermediatePool.AppendCertsFromPEM([]byte(bundle)) {
-		return "", false, errors.New("certificate CA bundle is empty")
+		return "", "", false, false, errors.New("certificate CA bundle is empty")
 	}
 
 	opts := x509.VerifyOptions{
 		Intermediates: intermediatePool,
 	}
+
 	if rootCA != "" {
 		// verify the certificate chain.
 		rootPool := x509.NewCertPool()
 		if !rootPool.AppendCertsFromPEM([]byte(rootCA)) {
-			return "", false, errors.New("unable to parse root CA certificate")
+			return "", "", false, false, errors.New("unable to parse root CA certificate")
 		}
 		opts.Roots = rootPool
 	}
@@ -317,12 +423,12 @@ func verifyCertificate(certificate string, rootCA string) (string, bool, error)
 	chain, err := cert.Verify(opts)
 	if err != nil {
 		if _, ok := err.(x509.UnknownAuthorityError); ok {
-			return certificate, true, nil
+			return pemCertificate, cleanPemPrivateKey, true, false, nil
 		}
-		return "", false, errors.New("could not verify the certificate chain: " + err.Error())
+		return "", "", false, false, errors.New("could not verify the certificate chain: " + err.Error())
 	}
 	if len(chain) < 1 {
-		return "", false, errors.New("can't find valid chain for cert in file in request")
+		return "", "", false, false, errors.New("can't find valid chain for cert in file in request")
 	}
 	pemEncodedChain := ""
 	for _, link := range chain[0] {
@@ -332,8 +438,211 @@ func verifyCertificate(certificate string, rootCA string) (string, bool, error)
 	}
 
 	if len(pemEncodedChain) < 1 {
-		return "", false, errors.New("Invalid empty certicate chain in request")
+		return "", "", false, false, errors.New("invalid empty certificate chain in request")
+	}
+
+	if pemEncodedChain != pemCertificate {
+		return pemCertificate, cleanPemPrivateKey, false, true, nil
+	}
+
+	return pemCertificate, cleanPemPrivateKey, false, false, nil
+}
+
+func commonX509CertificateValidation(cert *x509.Certificate) error {
+
+	// validate certificate is a server auth certificate if the extension is present
+	if cert.Version > 1 {
+		serverAuthExtKeyUsageFound := false
+		for _, certExtKeyUsage := range cert.ExtKeyUsage {
+			if certExtKeyUsage == x509.ExtKeyUsageServerAuth {
+				serverAuthExtKeyUsageFound = true
+				break
+			}
+		}
+
+		if !serverAuthExtKeyUsageFound {
+			return errors.New("certificate (x509v3) validation error: server certificate missing 'serverAuth' extended key usage")
+		}
+	}
+
+	// ensure that the certificate uses a supported PKI algorithm and a public key is present.
+	if cert.PublicKey == nil {
+		return errors.New("certificate validation error: no PKI public key found")
+	}
+	if cert.PublicKeyAlgorithm == x509.UnknownPublicKeyAlgorithm {
+		return errors.New("certificate validation error: unknown PKI algorithm")
+	}
+
+	// ensure that the certificate is signed with supported algorithm
+	if len(cert.Signature) == 0 {
+		return errors.New("certificate validation error: no signature found")
+	}
+	if cert.SignatureAlgorithm == x509.UnknownSignatureAlgorithm {
+		return errors.New("certificate validation error: unknown signature algorithm")
+	}
+
+	return nil
+}
+
+// Common privateKey validation logic.
+// Reject unsupported encrypted private keys
+func commonPrivateKeyValidation(block *pem.Block) error {
+
+	if block == nil {
+		return errors.New("private key validation error: could not decode pem-encoded private key")
+	}
+
+	// Check for encrypted keys or other unsupported key types
+	if strings.Contains(block.Type, "ENCRYPTED") {
+		return errors.New("private key validation error: encrypted private key not supported - block type: " + block.Type)
+	}
+
+	// Check block headers for encryption.
+	for _, value := range block.Headers {
+		if strings.Contains(value, "ENCRYPTED") {
+			return errors.New("private key validation error: encrypted private key not supported - header: " + value)
+		}
+	}
+
+	return nil
+}
+
+// decode the private key
+// check for proper algorithm.
+// check for correct number of keys
+// return private key object, cleaned private key PEM, or any errors.
+func decodeRSAPrivateKey(pemPrivateKey string) (*rsa.PrivateKey, string, error) {
+
+	// Remove any white space before decoding
+	var trimmedPrivateKey = strings.TrimSpace(pemPrivateKey)
+
+	// Capture all key decode errors and collapse them at the end
+	var decodeErrors = make([]error, 0)
+
+	// RSA Private Key
+	var rsaPrivateKey *rsa.PrivateKey = nil
+
+	// Check for proper key count before attempting to decode.
+	blockCount := strings.Count(trimmedPrivateKey, "\n-----END")
+	if blockCount < 1 {
+		return nil, "", errors.New("private key validation error: no RSA private key PEM blocks found")
+	}
+	if blockCount > 1 {
+		return nil, "", errors.New("private key validation error: multiple private key PEM blocks found")
+	}
+
+	// Attempt to decode pem encoded text into PEM block.
+	block, _ := pem.Decode([]byte(trimmedPrivateKey))
+
+	// Check that the key was decoded and validate key isn't encrypted and
+	// other common validation shared between PKI algorithms
+	err := commonPrivateKeyValidation(block)
+	if err != nil {
+		return nil, "", err
+	}
+
+	// Decode PKCS#8 - RSA Private Key
+	privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+	if err != nil {
+		decodeErrors = append(decodeErrors, errors.New("private key validation error: parse pkcs#8 error: "+err.Error()))
+	}
+
+	// Determine if the privateKey is of the correct type
+	rsaPrivateKey, ok := privateKey.(*rsa.PrivateKey)
+	if !ok || rsaPrivateKey == nil {
+		decodeErrors = append(decodeErrors, fmt.Errorf("private key validation error: incorrect private key type: %T", privateKey))
+	} else {
+		return rsaPrivateKey, trimmedPrivateKey, nil
+	}
+
+	// Decode PKCS#1 - RSA Private Key
+	rsaPrivateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
+	if err != nil || rsaPrivateKey == nil {
+		decodeErrors = append(decodeErrors, errors.New("private key validation error: parse pkcs#1 error: "+err.Error()))
+		return nil, "", util.JoinErrsSep(decodeErrors, ", ")
+	}
+
+	return rsaPrivateKey, trimmedPrivateKey, nil
+}
+
+// decode the private key
+// check for proper algorithm.
+// check for correct number of keys
+// return private key object, cleaned private key PEM, or any errors.
+func decodeECDSAPrivateKey(pemPrivateKey string) (*ecdsa.PrivateKey, string, error) {
+
+	var ecdsaPrivateKey *ecdsa.PrivateKey = nil
+
+	// Remove any white space before decoding
+	var trimmedPrivateKey = strings.TrimSpace(pemPrivateKey)
+
+	// Capture all key decode errors and collapse them at the end
+	var decodeErrors = make([]error, 0)
+
+	// Check for proper key count before attempting to decode.
+	// ECDSA keys can have 1 or 2 PEM blocks if the 'EC PARAM' block is included.
+	var blockCount = strings.Count(trimmedPrivateKey, "\n-----END")
+
+	if blockCount < 1 {
+		return nil, "", errors.New("private key validation error: no EC private key PEM blocks found")
+	}
+
+	if blockCount > 2 {
+		return nil, "", errors.New("private key validation error: too many EC related PEM blocks found")
+	}
+
+	// Attempt to decode pem encoded text into PEM block.
+	var pemData = []byte(trimmedPrivateKey)
+	for len(pemData) > 0 {
+		var block *pem.Block = nil
+
+		// Check for at least one END marker
+		if strings.Count(string(pemData), "\n-----END") == 0 {
+			break
+		}
+
+		// Attempt to decode the first PEM Block
+		block, pemData = pem.Decode(pemData)
+		if block == nil {
+			return nil, "", errors.New("private key validation error: could not decode pem-encoded block")
+		}
+
+		// Check that the key was decoded and validate key isn't encrypted and
+		// other common validation shared between PKI algorithms
+		err := commonPrivateKeyValidation(block)
+		if err != nil {
+			return nil, "", err
+		}
+
+		// Check if this pem block has 'KEY' contained in the type and try to decode it.
+		if !strings.Contains(block.Type, "KEY") {
+			continue
+		}
+
+		// First try to parse an EC key the normal way, before attempting PKCS8
+		ecdsaPrivateKey, err = x509.ParseECPrivateKey(block.Bytes)
+		if ecdsaPrivateKey == nil || err != nil {
+			decodeErrors = append(decodeErrors, errors.New("private key validation error: failed to parse EC ANSI X9.62: "+err.Error()))
+		} else {
+			return ecdsaPrivateKey, trimmedPrivateKey, nil
+		}
+
+		// Second, try to parse PEM block as a PKCS#8 formatted RSA Private Key.
+		privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+		if err != nil {
+			decodeErrors = append(decodeErrors, errors.New("private key validation error: parse pkcs#8 error: %s"+err.Error()))
+			return nil, "", util.JoinErrsSep(decodeErrors, ", ")
+		}
+
+		// Make sure the privateKey is of the correct type (ecdsa.PrivateKey)
+		ecdsaPrivateKey, ok := privateKey.(*ecdsa.PrivateKey)
+		if !ok || ecdsaPrivateKey == nil {
+			decodeErrors = append(decodeErrors, fmt.Errorf("private key validation error: incorrect private key type: %T", privateKey))
+			return nil, "", util.JoinErrsSep(decodeErrors, ", ")
+		}
+
+		return ecdsaPrivateKey, trimmedPrivateKey, nil
 	}
 
-	return pemEncodedChain, false, nil
+	return nil, "", errors.New("private key validation error: no ECDSA private keys found")
 }
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go b/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go
index 659d221..096a414 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/keys_test.go
@@ -1,5 +1,11 @@
 package deliveryservice
 
+import (
+	"encoding/pem"
+	"strings"
+	"testing"
+)
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -19,215 +25,1289 @@ package deliveryservice
  * under the License.
  */
 
-import (
-	"strings"
-	"testing"
-)
-
 const (
-	BadData = "This is bad data and it is not pem encoded"
+	BadCertData = "This is bad cert data and it is not pem encoded"
+	BadKeyData  = "This is bad private key data and it is not pem encoded"
 
-	SelfSignedCertOnly = `
+	PrivateKeyPKCS1RSA2048 = `
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEApIye2g6c0irFgoMAztPeEuV4ZX8NdORRsV2Ddi4kV9gKYiDk
+xQ9eOal3Nea9kDEaUpRvk2nuVl5jbFG3sOore9Vs6YUsCvICDKCUPl5OrxURJ6BS
+iC2l0jVE6FVhXf9pLX+OR8lZmMZ9GKbw1nlGGKwdF3T76gOZFSHQfT57vNFsI0Q+
+8NhWbDclNo/AnPpQuBs6ocah83BAVQk3gTRMHO3+rMLuvXVppBBqD+P5OU+LRROr
+joDulub2QUPiR0Q5DczqMCjDIQB96LReryN4dx/p4x4P62SLQB6dd2vHvJNmpfl/
+CBzAdSLBRna9mSV6xw429tu5b9Z48Da5gp9igQIDAQABAoIBABoepDyS4zvNREri
+RqeOJAs117WsxFMQxxLzeCGzU1uKVKOc+xN4zAk1KFIrDV4tHTOMkmWBBC87jmas
+Vg9ELKDckQxEcmhOYBrnBoEb8TuDiZSTs2YgcNj8UbLbkrgcCfMJ82jbwlgo8cSP
+A13YJFNYRsnpbO+JoKwlEPZAi92901MrwH5r6kf/D+q6SwLpABVvVux9UzlhKh/G
+hGUcB1GhLIq1axwAtlKahkutxyUWabiTu2hGlaY8Q7JGid0t4GZHCvZ0cqQbS/bE
+M2x8zskgWQrOPLneuxCYVLtpMaPdrJFSghcD39/Qw5kDiSw83m3VjrlluZG868+X
+aooOOBECgYEA0YmSG09MppC2fQlmwZzbiZreygiKkrSwDvYwOwbn2z0DYwSqnJ3V
+bHI0MIX4479s+1Lt3Rsr308GRIDmnx/u0gDlrAIZqh5Xoy3p2azQzCEUghr4csIp
+sGEPE1FKzFL7UdQvJ3K/QeM2Xux11aF5B+jZh+2LrN3GStpZLyhyUdUCgYEAyQlK
+5BzfUC6+c1Kuv6EO4YhlDy23AnTBoeGNEMOe8SQ3h4Fcz2TaOpWs2zXOLGoSoIHs
+OTN5VYq3R8AQL4w75OS1Au9+nr4m0o7ix1YI3cBMwseMqQtR0OvrzOSZSm2fQZtO
+SBeLPnLNg+XsR6Adxy7r2qSz9aYbXQA0WvHw9/0CgYEAxDbpJL27b3awDKKTINb8
+Ff16hwI8kWi2PSx4ua2bzIdz9nNWONbsFmNTT+UEznBhY2+i4pwhFznvCpMSYwwK
+HYlNiSdmVRGYy2uhQn87/wszIyqSYRRE6a/Z6CMFwhQq19O0XGJtiwtzzKvtJCHT
+Ln7zxP/C/hunJk0Vmr1rYAkCgYEAkPvCpwCrjIgpkcHvhQQCV2SmfWvasErD2ptv
+wMdTuVUFNxR0ep2hRN7s6qrDJgTZqigI1LfqqWaBB53cDm50Q38tjBBsoM9B8Fhb
+9KZ3fnVQ5qhDKSaguqtqQzoZ0zN7xzTaH+Pa6A6jaJxI6t7umtecAPMHVgGVelzL
+ZUtXHYECgYEAyOZQ9HevD5jaWE//wXggjdASE3CFu5QkKJ1MEhEz3O9DconflKh0
+e2TVphH64nagLC8G3ta9aSHch56r4frnZ7wc6xX2sORP/PCg3iAmvEtzaevQHQue
+T5BkD3zmC6RQIDOYN5DzpokgXZLuTCUl95evqAsIZ6Cd3tqNCqrJIfg=
+-----END RSA PRIVATE KEY-----
+`
+	PrivateKeyPKCS8RSA2048 = `
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCkjJ7aDpzSKsWC
+gwDO094S5Xhlfw105FGxXYN2LiRX2ApiIOTFD145qXc15r2QMRpSlG+Tae5WXmNs
+Ubew6it71WzphSwK8gIMoJQ+Xk6vFREnoFKILaXSNUToVWFd/2ktf45HyVmYxn0Y
+pvDWeUYYrB0XdPvqA5kVIdB9Pnu80WwjRD7w2FZsNyU2j8Cc+lC4GzqhxqHzcEBV
+CTeBNEwc7f6swu69dWmkEGoP4/k5T4tFE6uOgO6W5vZBQ+JHRDkNzOowKMMhAH3o
+tF6vI3h3H+njHg/rZItAHp13a8e8k2al+X8IHMB1IsFGdr2ZJXrHDjb227lv1njw
+NrmCn2KBAgMBAAECggEAGh6kPJLjO81ESuJGp44kCzXXtazEUxDHEvN4IbNTW4pU
+o5z7E3jMCTUoUisNXi0dM4ySZYEELzuOZqxWD0QsoNyRDERyaE5gGucGgRvxO4OJ
+lJOzZiBw2PxRstuSuBwJ8wnzaNvCWCjxxI8DXdgkU1hGyels74mgrCUQ9kCL3b3T
+UyvAfmvqR/8P6rpLAukAFW9W7H1TOWEqH8aEZRwHUaEsirVrHAC2UpqGS63HJRZp
+uJO7aEaVpjxDskaJ3S3gZkcK9nRypBtL9sQzbHzOySBZCs48ud67EJhUu2kxo92s
+kVKCFwPf39DDmQOJLDzebdWOuWW5kbzrz5dqig44EQKBgQDRiZIbT0ymkLZ9CWbB
+nNuJmt7KCIqStLAO9jA7BufbPQNjBKqcndVscjQwhfjjv2z7Uu3dGyvfTwZEgOaf
+H+7SAOWsAhmqHlejLenZrNDMIRSCGvhywimwYQ8TUUrMUvtR1C8ncr9B4zZe7HXV
+oXkH6NmH7Yus3cZK2lkvKHJR1QKBgQDJCUrkHN9QLr5zUq6/oQ7hiGUPLbcCdMGh
+4Y0Qw57xJDeHgVzPZNo6lazbNc4sahKggew5M3lVirdHwBAvjDvk5LUC736evibS
+juLHVgjdwEzCx4ypC1HQ6+vM5JlKbZ9Bm05IF4s+cs2D5exHoB3HLuvapLP1phtd
+ADRa8fD3/QKBgQDENukkvbtvdrAMopMg1vwV/XqHAjyRaLY9LHi5rZvMh3P2c1Y4
+1uwWY1NP5QTOcGFjb6LinCEXOe8KkxJjDAodiU2JJ2ZVEZjLa6FCfzv/CzMjKpJh
+FETpr9noIwXCFCrX07RcYm2LC3PMq+0kIdMufvPE/8L+G6cmTRWavWtgCQKBgQCQ
++8KnAKuMiCmRwe+FBAJXZKZ9a9qwSsPam2/Ax1O5VQU3FHR6naFE3uzqqsMmBNmq
+KAjUt+qpZoEHndwObnRDfy2MEGygz0HwWFv0pnd+dVDmqEMpJqC6q2pDOhnTM3vH
+NNof49roDqNonEjq3u6a15wA8wdWAZV6XMtlS1cdgQKBgQDI5lD0d68PmNpYT//B
+eCCN0BITcIW7lCQonUwSETPc70Nyid+UqHR7ZNWmEfridqAsLwbe1r1pIdyHnqvh
++udnvBzrFfaw5E/88KDeICa8S3Np69AdC55PkGQPfOYLpFAgM5g3kPOmiSBdku5M
+JSX3l6+oCwhnoJ3e2o0Kqskh+A==
+-----END PRIVATE KEY-----
+`
+	PrivateKeyEncryptedRSA2048 = `
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,A6E695C7D7038524
+
+YMB2rcNobMEfCRzLcGV5uSF5g1hMIuHlJjZHG0QYNpeFdP2pONtgGLH+NIVWbb7B
+2dYHUbofywcJTGPigSIm0RUEHquz/+seauRXs0jvN0cEKgEyWVaQZB9yem+V5sJx
+guicvKmbWfiV9u004n9G4ue9IxpWwoZp1KixOrJ7GOmRhJsNL8E9MUpJ8kD1eOIY
+n8RBuo/sQMyDKinL7npk5IYE3N1tQuVAxpEn2KVXjDIIrl0SeCO5pfJdXA40Sw8Q
+6bEF8GogDuEaibw2XzOfqzJsmQRks1STtCqKVnN7b7HjpY3pPgYqMqc9BVKWL3PF
+a8G5BSGjjosu3SPuzIIlADlQm65O8Qi/6eZ9thByfGBtXcanSdYZtoprreEikhgC
+MYnID949McXvnJTjB1snWni2FYhrWuH6iK4/7/UevFg74She5qKfwuw/YXe+p2pP
+Z0ON4olUgG68/aReRoICqDurDW88zklbq8c18ECI8ppBy3tDB85Sey+ybwTliSd7
+FLBhwk/vLuhBlX6kVba8CkBUHqu8T9zECyLK2f7geDUjsw6EVXYy7whJE9LL1Sq0
+cSUpyMb5I6RXOe90zj59sBJddEsllSn2KTMhrJa2LPj+j6Df4PuwmsKdPz+DWo5r
+TTAvc3iN9sZbXGjwbjiJulzapNPsfOYXrSlN9KrlkHxvmJQq0Y83ZZqmGE+Z54Z4
+TMfA/rKULJ60BSaBIwVb/NyQC+6iKUpiLDMdWhVEqKXtes7fpHnrHwHYPtTMRc6S
+EG+txT5gtUKKuddBTx01UZA67L40RyC6gwbg3zipOY5XFChLQ8O4hjSaDZuQEgik
+ewZhJ4ExH17+f3GaNAgPE8OtafSF86jcqt2lowrXbPi1CV9BHSriD/2G1WQycjma
+Z8tFSb40fxvWHTiuDs9AyymN3OKpVX/IBm8gFxeitryxSYZ4ZOtsI7fTH+hH74C9
+ceKwu/3iPednzj1NvTpBdQvuEHRzgN/YfABXdJ71WiYRwVtE+hsdPJkKAdNYRXVs
+YWJU5Ry5CAyaKZ//XsqqXM6PeACbRfWt6lqHSxnuaJuuh6dn2btJj4hX4Do81bh/
+qwKUwzIVmJCtyEaO1VsslQk7CnLZ2dErIWGnRVkeLY0wMW4qspIZUx7ikgJZZ0sz
+XFMwByTkVOtzz24nX3DdhxXfClqk1wrUI50erG6XbCjbuN/XEWbKZNLKUrfxkNys
+1GjCXr1qagz6s8igxAHNmK2I9N8lyZSLrqKZf6m5CjyLMHSqj95jEeXL8pw29FLs
+0BQnpfuqqTQfonYDSxdHgMPZfT2y+iX5LyIaozTJuQjsDAKXhFbytrSZ9as/kmtB
+ne8L04gDLiHcX3K0anLSZN/0N06LiIa9O3qygfBHdtB3iIlBnE+yuGMZGPo2KXSe
+4HnU/9E6Sayh3hHEqYtDnfVtNSQhJEwGr+HgX2+wvfQYJCUX/x+2gSN40/aYQ1jI
+h9gynY7NK8WybupP8JsjJ8t0UOaFwfXC2har1kq/uChOGnsBI+E+Lkx9mOPkpQ0M
++NkN+HYuZC6dqUJAUZmHdzGPgh5MPZiIwusaW7frswmKko32y9VDfg==
+-----END RSA PRIVATE KEY-----
+`
+	PrivateKeyECDSANISTPrime256V1 = `
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIM1u5X+fmuna0jK5NoBO8CRWJiTzopg9xzqjs34dB3osoAoGCCqGSM49
+AwEHoUQDQgAEq0gH7B1q2cWMDvYTmFr+xNmbrJBMK9ERmZkSfRfaDmzxqvE56FrB
+p3aue/xDiaFp9yniuM8lqbTWHwyopraMlA==
+-----END EC PRIVATE KEY-----
+`
+	PrivateKeyECDSANISTPrime256V1WithoutParams = `
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIM1u5X+fmuna0jK5NoBO8CRWJiTzopg9xzqjs34dB3osoAoGCCqGSM49
+AwEHoUQDQgAEq0gH7B1q2cWMDvYTmFr+xNmbrJBMK9ERmZkSfRfaDmzxqvE56FrB
+p3aue/xDiaFp9yniuM8lqbTWHwyopraMlA==
+-----END EC PRIVATE KEY-----
+`
+	PrivateKeyECDSANISTSecP384R1 = `
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDB563eEBAdLcLBpgUi3WOszJS6JOHkAcAePAWX/fvguKP56brbIsZnl
+/IlujyM6RACgBwYFK4EEACKhZANiAAStW0BfZ2KCkmBQv9Cc8GT9hoGDRuJvfbj0
+cmgIRz1yhqHy1Psw3/z8FhhBkhm1Y0InJ7xxt0CsOYs2/faAOmNcKt3mwwthLcEy
+9XVZrwbog5s76datlz/7iVd4Jo7vS88=
+-----END EC PRIVATE KEY-----
+`
+	PrivateKeyECDSANISTSecP384R1WithoutParams = `
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDB563eEBAdLcLBpgUi3WOszJS6JOHkAcAePAWX/fvguKP56brbIsZnl
+/IlujyM6RACgBwYFK4EEACKhZANiAAStW0BfZ2KCkmBQv9Cc8GT9hoGDRuJvfbj0
+cmgIRz1yhqHy1Psw3/z8FhhBkhm1Y0InJ7xxt0CsOYs2/faAOmNcKt3mwwthLcEy
+9XVZrwbog5s76datlz/7iVd4Jo7vS88=
+-----END EC PRIVATE KEY-----
+`
+	PrivateKeyECDSANISTSecP384R1Encrypted = `
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,0B0F937007A25C35FBB3DEC9F09C0343
+
+KIRWqbmNfP3xnnDE8f9Ndx/aaNvQBPCucQrVHc6ZYpImPnVmIzH/eOZMyio7HQkZ
+tH2ggwwI+zSg3cJWTehJaR9j9qiFtPH+UDEA03co2QyIyERk1wI5ev4hv822tmtl
+/TrYpdjqNkfDZUcZscuf1VHkjSrAwn+3K0NV5hUGfdhWryZ7B16iKyCJrSrbde4x
+E34vrABCPJZtg/O7SbXQL8cURtVoEdbT+AveW3qoh5g=
+-----END EC PRIVATE KEY-----
+`
+	SelfSignedRSACertificate = `
+-----BEGIN CERTIFICATE-----
+MIIEIjCCAwqgAwIBAgIJAKfsBagyQeuuMA0GCSqGSIb3DQEBCwUAMIGFMQswCQYD
+VQQGEwJVUzELMAkGA1UECAwCQ08xHzAdBgNVBAcMFkFwYWNoZSBUcmFmZmljIENv
+bnRyb2wxFDASBgNVBAoMC1RyYWZmaWMgT3BzMRUwEwYDVQQLDAxVbml0IFRlc3Rp
+bmcxGzAZBgNVBAMMEiouaW52YWxpZDIuaW52YWxpZDAeFw0xOTAzMDYxNzA4NDRa
+Fw0zOTAzMDExNzA4NDRaMIGFMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xHzAd
+BgNVBAcMFkFwYWNoZSBUcmFmZmljIENvbnRyb2wxFDASBgNVBAoMC1RyYWZmaWMg
+T3BzMRUwEwYDVQQLDAxVbml0IFRlc3RpbmcxGzAZBgNVBAMMEiouaW52YWxpZDIu
+aW52YWxpZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOXU/IY3uIA
+Kb0QjlWC0eEEGQAVBTOWqXclb+Ov2fZbJ+DGfrRmmBRk4Sz3H5p/l79mVDd5+Npm
+UchWSut9o/lYm9zbZ6HDAyE7O9vtO7uNGq+Odg3lUzh3QSZzh+vaMeYRMzodGK+7
+6vkZ6jxGJRMazZO2LghuLH7g3ft0Dbd/QFGOQHkP/y2KeNt7jeuE4OT6jjA6OdSG
++q/gXAtFADQKkx814pEAyp1T4K59rteN2KoCbRiNrgxuewgkeu3VOGTagkwbyav1
+o3uxE+wfc3r0TOdW+2xLUO9KlaG3pioT8Vh1YcwZvghe+mkueyod1VldKl4vgH0N
+sUEMpi5zB68CAwEAAaOBkjCBjzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIEMDAT
+BgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUJguFG8ibiS0+orhtIBPDUPAT
+jL4wHwYDVR0jBBgwFoAUJguFG8ibiS0+orhtIBPDUPATjL4wHQYDVR0RBBYwFIIS
+Ki5pbnZhbGlkMi5pbnZhbGlkMA0GCSqGSIb3DQEBCwUAA4IBAQB1th3ZUxczr5ZS
+5Yem4KGLAAQck0o71cvmIMLXs4u0ioehM6UDxNrOwy5XaxLweZebIuUgZ44+KZU/
+UerqSinWE3zsNpHbV+7j60aFjuCKAj+9WtJVVa/A2KLPVMYaoGITgdohHeYLKqWO
+6io1VvLiahXa6G1nElPhRwdBU5qnJ651I821xf9TKeIUZM+bmYyqDE2FKHbZ+hBB
+AGrT265gN3/aZKi5C5s2YFZ3Oc7dlZ1ZUhZqiLeTr8cmc9bZAdNY9ppDn3xs8ThI
+GQlQzUI4o2FE3OdwA28PO78/DvnZ8oVeF/KD19oExJ9tj6dzLZIrkxaRDu7CD70S
+41PQLy8Q
+-----END CERTIFICATE-----
+`
+	SelfSignedRSAPrivateKey = `
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDl1PyGN7iACm9
+EI5VgtHhBBkAFQUzlql3JW/jr9n2Wyfgxn60ZpgUZOEs9x+af5e/ZlQ3efjaZlHI
+VkrrfaP5WJvc22ehwwMhOzvb7Tu7jRqvjnYN5VM4d0Emc4fr2jHmETM6HRivu+r5
+Geo8RiUTGs2Tti4Ibix+4N37dA23f0BRjkB5D/8tinjbe43rhODk+o4wOjnUhvqv
+4FwLRQA0CpMfNeKRAMqdU+Cufa7XjdiqAm0Yja4MbnsIJHrt1Thk2oJMG8mr9aN7
+sRPsH3N69EznVvtsS1DvSpWht6YqE/FYdWHMGb4IXvppLnsqHdVZXSpeL4B9DbFB
+DKYucwevAgMBAAECggEBAIwTGVx9sUmbokizzaux58tFmv3zD+mVUcJxfkNK0kdb
+myCgJ2fdPbcFVDpWtTx5elzp1RBx+uW2d4WJP1iNf1x4uA8g1oQD3H71I/ZqXOgB
+swXdefCTttjulysJfGNNvYSt9sj8w4w/gZVqmNUXyz92Z5oM08TX2mf3dSK7R4OM
+jk3hgGYXbgLg9ZMy3DuiZlkzIUY5sk/574j3pYaSaA+ufeIINzovod7zfqIT+5HY
+nmoHKJqEjd7gZ2U0EVn3n39NXV9+eBsjuqC5aFB/oGYvH6rkXa+10vILImNoJEl2
+PRMIWggvKyG+rFn714Y5QnPwLP/So71Hq00XSMTOCUECgYEA8MVfyRuA8/d0Jyas
+NZv0lbtsN1XyZ5MRsNND4DkZR4Gz3Z5JT6mXwlzTLFMl6RKxPwkxLowYGeJQnEnK
+5navmcvjr9EbMrAiebmCam1PWfUKxvLVWgw4sLrscD2YlB/ylm3CugLB6p2eS5HV
+7bqGhrS56PtjibZbU0dBHIc7Ek8CgYEAz/Zjw8GBV4bh9dqpKB0Kv9VF05d8maLH
+X6ybRSacJ24u/icYijq1vIlz5P7fM1enVkIKF3K8V2aToMjFShnAkdWxk1Ss6UrA
+DsuRq1WAf9vSIsSDao8Cl4We7M9mbnGj3pEmxdN+Fh5l9Gs09cb8v75UacDrQ3AA
+x/izdR9ePKECgYA5uCdZT9WfJuBajmPUSjndN1we++Srvc8M4+iutSGBSe+znkGW
+7mIqPxSE2L4K3OdO5EY9EWqpsd5/SRVyIFvCc+V2fZuWkDEDm1xPZTsTprHZtdc9
+yhZBD96kna+ZOvtt4ow/CXAxbW3IUgLGBeRAIM08tB9NoUDNexR54VVg8wKBgAhU
+ZSCVIpof4/MWBAqAR0rxvu8/tRTuSTAS2NFHP5/wsN8rL7dxrI/VrZexgb0ruJ8i
+3AaeaN7TU/xvrj9OksEEny04igh6HwE4tCf5r8DvTBZqap0dB0yMZJY1pHOuB5NF
+mxj3ZKh8JTdKCAAELWF8vSLTQFkeJlncI0wAqqShAoGAR/iDslDHU0M/CjvqN+le
+m91MxJsaFi3FZ2Pv60ghqG27X8uPbgvGXkTmmcqgAaR/Fh8b1UH+yqOnPUiremxO
+oIuOOmvkBAyy0cHT/BSunqxiFOWcu9yb+2MfSWaHHxNj3kteif8Oai1lL84JOucC
+/FZTue8KxnrjBcbGYYtwPCU=
+-----END PRIVATE KEY-----
+`
+	SelfSignedRSACertificateNoServerAuthExtKeyUsage = `
+-----BEGIN CERTIFICATE-----
+MIIEiTCCA3GgAwIBAgIUK/LEzHDA/Hf2aGdnDSka1jov0uswDQYJKoZIhvcNAQEL
+BQAwgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhDb2xvcmFkbzEPMA0GA1UEBxMG
+RGVudmVyMRUwEwYDVQQKEwxDRE4taW4tYS1Cb3gxFTATBgNVBAsTDENETi1pbi1h
+LUJveDEnMCUGA1UEAxQeKi5ub3NlcnZlcmF1dGgubXljZG4uY2lhYi50ZXN0MScw
+JQYJKoZIhvcNAQkBFhhuby1yZXBseUBpbmZyYS5jaWFiLnRlc3QwHhcNMTkwMzMw
+MTkyNDMwWhcNMTkwNDI5MTkyNDMwWjCBsTELMAkGA1UEBhMCVVMxETAPBgNVBAgT
+CENvbG9yYWRvMQ8wDQYDVQQHEwZEZW52ZXIxFTATBgNVBAoTDENETi1pbi1hLUJv
+eDEVMBMGA1UECxMMQ0ROLWluLWEtQm94MScwJQYDVQQDFB4qLm5vc2VydmVyYXV0
+aC5teWNkbi5jaWFiLnRlc3QxJzAlBgkqhkiG9w0BCQEWGG5vLXJlcGx5QGluZnJh
+LmNpYWIudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKfcO00F
+XWEnW9cWYSvw/SzmFB02q8ILFyfbFmkxbDDIZyCmiZIoc5xQdgOU9ZcwwS4Xc6Ae
+mVbvLn+L/nw50/w7+cX7BSAwMbcANKrgr0OSqHrmvXSZ7xpn7DWb3nrbphnIzRMf
+CiQs76cygXV23u8NO4Qed/mlapUYux+SA4t8wVr3ZN8gcoal4f4kv2dZ/nZAXjPY
+EAugZxP+hsKF6IhlADOFDssOBUWXB+TE54z9wdUVwovOSOQoPOpoVsc8rcVGHkGm
+pjXnd5CcgLv9M1k7gS7nEElUwNWGAY4e0RJqDy32ft9PlGaTVLNxAKzSC49GQBWu
+hJGZ7AmgyRIqfB8CAwEAAaOBljCBkzAMBgNVHRMEBTADAQH/MBEGCWCGSAGG+EIB
+AQQEAwIGQDAOBgNVHQ8BAf8EBAMCAiQwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwMw
+HQYDVR0OBBYEFGGKXpBZaG8HuUnjoI6cqZenJdwVMCkGA1UdEQQiMCCCHioubm9z
+ZXJ2ZXJhdXRoLm15Y2RuLmNpYWIudGVzdDANBgkqhkiG9w0BAQsFAAOCAQEAU99E
+B0FUyyB90tlGQuMcl3FPRGXwfzSZgqTzdVDAtYNoYO0iqUgzjPhdZyV8Ai8zXbzI
+qBiJfqbfu9hsR3l7snjxgXgEXhfYpZO1xyA0TJNrWWmcw/HRTndBclzhBgo8qunF
+euO8CSUuZ1QY+cjptM8AQFlgj3PYNOEN2horwCl08Z3K858kOaH8CQ1mHBEonlaj
+mGCqKyoQftLi8bmA/PZMOQoIGdgsIsGtt0p4cOJ2+fEwJ1Y0uGT84cOtq8zcHaRl
+xqG7Q0ClQAeUC8PuCOZ37tRDdSJ+P/7RGJsiXCA3U8mRJg7nv4pCMEwJUkbhMoXz
+RW/yw0YwdzYB21veHQ==
+-----END CERTIFICATE-----
+`
+	SelfSignedRSAPrivateKeyNoServerAuthExtKeyUsage = `
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAp9w7TQVdYSdb1xZhK/D9LOYUHTarwgsXJ9sWaTFsMMhnIKaJ
+kihznFB2A5T1lzDBLhdzoB6ZVu8uf4v+fDnT/Dv5xfsFIDAxtwA0quCvQ5Koeua9
+dJnvGmfsNZveetumGcjNEx8KJCzvpzKBdXbe7w07hB53+aVqlRi7H5IDi3zBWvdk
+3yByhqXh/iS/Z1n+dkBeM9gQC6BnE/6GwoXoiGUAM4UOyw4FRZcH5MTnjP3B1RXC
+i85I5Cg86mhWxzytxUYeQaamNed3kJyAu/0zWTuBLucQSVTA1YYBjh7REmoPLfZ+
+30+UZpNUs3EArNILj0ZAFa6EkZnsCaDJEip8HwIDAQABAoIBAGWau9ZaGfS1szSV
+GkpTu5uSxLgOIJb6yZBZX85amQdKNoof5AOxMpF6boSqhKF4ZGY20cko3F4vtrCD
+l42wHy19TCnXUHn0UhNYL4kDKXM4cXy68BCFIKKWJvcoGtm43GidD+y0DBprjMBi
+pNPqGPUPyGenXa2hv8rxxkpMwpKJ/JHdONq0m+eTu3lCRdxhVVHbOn1xQmJTgP2B
+CyrtmBD7rJ5AhDNYQ7GfL9WwVf1UeFNaOuAOEK9T7Weqm3Ak5Pd1dJUwukXk/vND
+Rcu+cWhklNTVIUw9XwXawPpFm03iZiTcFurAcrShXrtW7aY38S1e7w1fRSSxhrfQ
+GroShXECgYEA3rjHANz5dx/Z0EUQ3rK6MgOuKpsS4rAmpydqY7PFfNkSgQzsUwot
+o4VRIiKd16voodvT9CZausgCut6ZqCpVgwZY0Mg9FBEBXfxPIOg5oRNmje7RHAfD
+Q9I2yiEgBZ6exi3m4lZKgWSNvKkocY/HLIwsDz4kEq4ux3Gr2+zkIacCgYEAwPD5
+N0R25aO06gI/eeYOV0P0Y0h3OKCtF0b/PwU4tKSuqQiojeIvmoJspbCZJbg+D6Da
+0kXgEhybchVBSzgeOggZb+sZl0Odg1eqJea/kbz7JyO0NcZu3t7wg5AVynssF6s0
+JUcDFxELfW9GYLtdzR8LeWvgaezSwZBeYmV1cMkCgYBtri1CPZAUm/jV2c1O/lE3
+ZByXGrsYK4s9cemwo80ziGrWZpjS5AZJqtOjrcxxc1UisHEWoPS5WtoNUKX27LIj
+zjJazuFVSnKT6DbHi9Ulf7pXVy5fUWtVsOYOcHWmjtC948j52Wjjg7NRHzStiBKb
+24OvFfkJwgGDcnUh3u0RrQKBgG7ZxAVp03nKXYXY9sk9UN34T+++0ah6QBhQlROL
+F3JJ74N0Uwr5eeompu9nEAYo3ZczDqWiucMOJo0cAyCJRGyI/LxdcZ2Dnnq4oiwW
+b9f2oMFy9PW0ZTytD7g2zx4/OCz9Ev+b1f2psFVH2kJ3Q8Q24uvG++8/vjKxlFip
+/BhpAoGAJmo5n5fR9+q1Zwb4Gs9i/gquxcJsWo9eaCgQpt+IK0oqqgi/8xx61PCW
+Xeg+Gf0gAv5J/WfbYpBCLD4K8o1COm7ZqZGqG3kFTWYjh0jRm8hLQF+8kkn0Fby5
+ohq7Fw9P96opYCnxqau5nfiHExfyfLNQZlj7dPHZZPCEhUFYSSo=
+-----END RSA PRIVATE KEY-----
+`
+	SelfSignedRSACertificateNoKeyEnciphermentKeyUsage = `
+-----BEGIN CERTIFICATE-----
+MIIEojCCA4qgAwIBAgIUXy/RKN+PEOQwwlsQYJ4FR7HUZn0wDQYJKoZIhvcNAQEL
+BQAwgbYxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhDb2xvcmFkbzEPMA0GA1UEBxMG
+RGVudmVyMRUwEwYDVQQKEwxDRE4taW4tYS1Cb3gxFTATBgNVBAsTDENETi1pbi1h
+LUJveDEsMCoGA1UEAxQjKi5ub2tleWVuY2lwaGVybWVudC5teWNkbi5jaWFiLnRl
+c3QxJzAlBgkqhkiG9w0BCQEWGG5vLXJlcGx5QGluZnJhLmNpYWIudGVzdDAeFw0x
+OTAzMzAxOTI5MTZaFw0xOTA0MjkxOTI5MTZaMIG2MQswCQYDVQQGEwJVUzERMA8G
+A1UECBMIQ29sb3JhZG8xDzANBgNVBAcTBkRlbnZlcjEVMBMGA1UEChMMQ0ROLWlu
+LWEtQm94MRUwEwYDVQQLEwxDRE4taW4tYS1Cb3gxLDAqBgNVBAMUIyoubm9rZXll
+bmNpcGhlcm1lbnQubXljZG4uY2lhYi50ZXN0MScwJQYJKoZIhvcNAQkBFhhuby1y
+ZXBseUBpbmZyYS5jaWFiLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCiOfGhT8EgpDoMLq088R5HR0MXfgwc9XoFZmB5oyZvTDcQkGJH48Z2tFFt
+d3qoa5sbyiu5/I8j/J4+NXvYBLLaTNMTz4fFknFmlssyR3CXUjvh3wlzWVJ0SkA+
+GLfnZdX1zJ+35Grf/bILeV0kl/WKoFEyI9CZW7VbTaRluoCxrINlGtLzi+K+kHRc
+lxv4EZ6TcgJZ0lT47OSxUTTTDKH4L2rF6dOltmGiGdsMyhZsIswKbM+eEliEYA6Q
+3CT5s/3FwihS27gWJq+ORAKuz77Rl+n3epzWaAfD0M/P+eCPNFEqJgMVw72x7SlD
+9eyiNns0iq2OvevjMdiBvy+34jNbAgMBAAGjgaUwgaIwDAYDVR0TBAUwAwEB/zAR
+BglghkgBhvhCAQEEBAMCBkAwDgYDVR0PAQH/BAQDAgIEMCAGA1UdJQEB/wQWMBQG
+CCsGAQUFBwMBBggrBgEFBQcDAzAdBgNVHQ4EFgQUtUhWjz+wVZTK5DXkyiqEGVp4
+tvgwLgYDVR0RBCcwJYIjKi5ub2tleWVuY2lwaGVybWVudC5teWNkbi5jaWFiLnRl
+c3QwDQYJKoZIhvcNAQELBQADggEBAFClaIKSL0wdeXP94UAcsruRaQyQiOxcx8uu
+k3MvMyUXyyTZIMUkKdIetc9uDfcEELJ0QfAKQPNzSEDHniq7b/Tlp5BnmfhMcWFQ
+zmegfM/J3xAsJE02IHEKOuyUw9Vm96mzVQ2QfoHcJaBRpl62oHr0PD6R168aSqTe
+eqnBe9O03+2WA99Fr6SZDVsOoZFoWYiMBqphKtLDEBvc40v0Tk9oSjOnRNnvPEW2
+JLO38D82IakS2TNQh49tYGwZmLqbXzqLCJ4hqMHsk5lgOzXwc20wM5864fpb+fp0
+eO1J8sGqqiTmh8bnyo6O3Ru4qIs16LXpW8KLgAohSQej0p6tzlo=
+-----END CERTIFICATE-----
+`
+	SelfSignedRSAPrivateKeyNoKeyEnciphermentKeyUsage = `
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAojnxoU/BIKQ6DC6tPPEeR0dDF34MHPV6BWZgeaMmb0w3EJBi
+R+PGdrRRbXd6qGubG8orufyPI/yePjV72ASy2kzTE8+HxZJxZpbLMkdwl1I74d8J
+c1lSdEpAPhi352XV9cyft+Rq3/2yC3ldJJf1iqBRMiPQmVu1W02kZbqAsayDZRrS
+84vivpB0XJcb+BGek3ICWdJU+OzksVE00wyh+C9qxenTpbZhohnbDMoWbCLMCmzP
+nhJYhGAOkNwk+bP9xcIoUtu4FiavjkQCrs++0Zfp93qc1mgHw9DPz/ngjzRRKiYD
+FcO9se0pQ/XsojZ7NIqtjr3r4zHYgb8vt+IzWwIDAQABAoIBAEm+Kz+XwIO1A4oM
+IcXFGW1vUGk6bAkx8TDJM+u3JT6Ml69Y4sQpH0tQdn9bQ4+RsqV0RmI6E1tZdxly
+OISexiqDp6Omv+IoypHG1EFbxiuTPxNSzrn3jYq9Qey4UcjHOvaL+MKf+5EsgqXC
+mnuK9Bv6+k3fh/BehtclOSjhGaUpvBj4FFpVm5aQT1PlrfsSJsY8AhAsqyO3mO0Z
+ndfSd2u3/T795h7XVyarJlZquaExlAe+rsrmdCciU+0l27Wh9HzY145sDtuzSPGm
+A8hWredHQ6qVwz4EpVZUj3HDowHi3krqlQitc144CBA/PejTV7jby0piKAZ8agKK
+pCiRvxECgYEAzvBKma1oJWVa3oM1sYsan8RcquqHRQoE2q0xDmKgQPa4mihyXfCV
+iPDPc2jw+0/M6fNgFlhVppMVqJyvScIELKH0HsRtoZyDiaoVkmQY/EG4xkS9N3zK
+6OXs9y/1nHHFwsKe3EDHuPKWJAHDAx+x9OrQ5o67Vc9MDwmwt4bJiDkCgYEAyK/u
+3UNWrBVQuT4k8klI485HCJCV6AO2egONw/dGFeZJ9W20Uw/eWAAuphT6HKqwSlBt
+0EwTpjL9dnuoTrS2TcTLq7UwTN9Gw/1VhE1of+nbsa0kWAqDqhpCFMZQ2/X9ehDv
+cqFemW4HE1la3E9izwlKGU3ehpHwWjRhJbH8kDMCgYB+uS2l4EgHpoK4AneuCrY6
+ImBxFf/SKmmAlFCXM5RZU/0GAkDPABZCbt1LGneAHoUouy4bYOrKgAXiZFj/fP1b
+a6337WgJcLQoaGyfYgbe60xAtjV9NkF3z92GHet1a0KkmtP3ov/rZTrGQAHw9sbe
+abGVjtBvous7xj5elP7zGQKBgQC2TtRwHi8LLmXhkemgTCCyCX6P8kCrv0uyNa5A
+Gk6JsGT5VopcdmrmiGvYJfA7wHdbWwsXETU8Ys/MJXN05EdECIV426UgACjZ/DYG
+dQd8Q+Z21rHQZOTMzwO+uZVU7Hcyv1W2TY+RU9mLoz2eK2O4bljo+csvdj3gw/qI
+ctLb7wKBgFOwu2jZJE66DJ2AUz5XgeY0EOSH8ZIpdEtRQriE8R397KHb8Pmt75fJ
+F+nJV58mV+vR/r3qlMViq8Cfb8cZz47Dn00Q2udMoOLKLiKgu1yP2pdCs24VbwLF
+7FDXBcacw5kMQfw5DxWDqgXqbwl4cdS62m8kRA/idZNqdHtCmICA
+-----END RSA PRIVATE KEY-----
+`
+	SelfSignedNOSKIAKIRSACertificate = `
+-----BEGIN CERTIFICATE-----
+MIID4DCCAsigAwIBAgIJAI84W5tsR3z4MA0GCSqGSIb3DQEBCwUAMIGFMQswCQYD
+VQQGEwJVUzELMAkGA1UECAwCQ08xHzAdBgNVBAcMFkFwYWNoZSBUcmFmZmljIENv
+bnRyb2wxFDASBgNVBAoMC1RyYWZmaWMgT3BzMRUwEwYDVQQLDAxVbml0IFRlc3Rp
+bmcxGzAZBgNVBAMMEiouaW52YWxpZDIuaW52YWxpZDAeFw0xOTAzMDYxNzExMTZa
+Fw0zOTAzMDExNzExMTZaMIGFMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xHzAd
+BgNVBAcMFkFwYWNoZSBUcmFmZmljIENvbnRyb2wxFDASBgNVBAoMC1RyYWZmaWMg
+T3BzMRUwEwYDVQQLDAxVbml0IFRlc3RpbmcxGzAZBgNVBAMMEiouaW52YWxpZDIu
+aW52YWxpZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2yyphDlkc0
+AmpxPAp0GZkPiGM5PgkahtafnIMCWXC5JkWz1Qk7dSgKUNl6hXg3I1dBJ/Kej461
+XwRSPNVFp1ehUsl7+D6QJy7+WEuk4Ea3s6/btMByH6+7S5EvJJGivavXlaLfqXnD
+2vRKW+6EuabNpeNVplYrZQYQ2aHYIsY+HYInzqdpb/qx6BSbuvuV74N6KcI7dbpC
+551y87hq2U/Mftka1TmfT/ll7bKdZ4q192ME14/USGqmyy8HHAiFvsgRjmqUUe3N
+6+O0VOjjTDByL1naMw5MlSIhcIOM4O+rklAiKVzL9ONc1rz1U38JrNeUjD6pEleD
+cPPBR1ge8DcCAwEAAaNRME8wDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBDAwEwYD
+VR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0RBBYwFIISKi5pbnZhbGlkMi5pbnZhbGlk
+MA0GCSqGSIb3DQEBCwUAA4IBAQBtkA0rtyLblXFDOntBY68gpcgaa1KjUo9YNfku
+VywCVan7ZoxiJkCsirIonugJDan1Q+meMsA2tO9UXoxShXSyh6pEcqEa4uSelj1M
+IysFFdtCwcUOzL3OwAY1TecC3rRadJD/hWM1F3iHPpG3BGB1LDkEZVCQdi+Gtq/C
+UCHb6g1lluLt/pxHuicS4etEd1zTb1oh2CbcijMLFSGimPqkqmSBOkgO6/283xA3
+MOSm/w7yrLylq/N7/g5c6kLZSWkYpoxA5PgImJEsOwoFF9VrMzC4JPLdR3zjLq/T
+wBmyIzcVFJ2g4V0iS5Ufi6uHwc7A03PVA50g7p7JUVRx5q/B
+-----END CERTIFICATE-----
+`
+	SelfSignedNOSKIAKIRSAPrivateKey = `
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9ssqYQ5ZHNAJq
+cTwKdBmZD4hjOT4JGobWn5yDAllwuSZFs9UJO3UoClDZeoV4NyNXQSfyno+OtV8E
+UjzVRadXoVLJe/g+kCcu/lhLpOBGt7Ov27TAch+vu0uRLySRor2r15Wi36l5w9r0
+SlvuhLmmzaXjVaZWK2UGENmh2CLGPh2CJ86naW/6segUm7r7le+DeinCO3W6Qued
+cvO4atlPzH7ZGtU5n0/5Ze2ynWeKtfdjBNeP1EhqpssvBxwIhb7IEY5qlFHtzevj
+tFTo40wwci9Z2jMOTJUiIXCDjODvq5JQIilcy/TjXNa89VN/CazXlIw+qRJXg3Dz
+wUdYHvA3AgMBAAECggEBALZkgyEV0xdRLYV0rJsMeFRPt/5XWotcQwt3WgApMSAO
+FXttZkdDMOk3yfbhNBWbRlKt5iAETtmTD/HStIUHPNgn17a8iLp21gX8LZ9FvxKf
+rJhI8ikbUdYgio7kug+BX0cruMdqr8PRCeRa3rueR/bWwkqr3ov5m1/Ssb5IV18t
+UFj7c2nV9JMB0Wq30Awa2RcAFwC2zBkNcyZ72bR6x2DxV+QHG+xDzLO5y/PTuLEF
+GBc3a9ExByC8RtUlC1n2YCwe6HSZBPALoaCIloo2isEpLpAy2ihxxaJ+tJh6iScB
+t9RAvffPNN6AgRIM5qfWaoGR8E60yFBPrkHPTgCiICkCgYEA30yqVmU3zxbTvNQH
+gmRCJrUW++ReLsa7xnaZmN4Pn72tGzdpmhajUWgw7LXdZ6TtHQ3UzZzt4pU5NoXa
+BgE+4XKewW90GoCW66yQpg80OD0UUl5JNT/GM2cVYqROEioFg+7/rEzhF1tv2JAe
++I2uxMJoMlA82giwLJ2qDqctDZsCgYEA2XpyRHVk3GZnQ/q9tK1VyVfUkFJh0FnQ
+q7uzWysi3UCOzuJYauM300LhkP5gWsB0J3osBlreNMg9MTOIy1xi7tNXdOq07Hhr
+4KsP8TkDhCmQDepx1V++qVBDTlAofCO5V530Ut1+wWDBlcycAz5MIy6j5TeAWrjm
+s0sisOrk35UCgYEAlQyWcn6zht6kzNj2fjmv0ih0RATGPRDYS/vkQJ6Q7T5taspN
+CdZsgy054vbt53216/vMfMZwHxseCl/EDNgOAexBPbrIU9xbYMpZ7w4c/CEBDI30
+7b847By1sJcdqZA1CECiln7mjHGzMWnZ0my4KIvfgx390EeWWOGQnqFGOFsCgYBs
+OEZMUq6SDlMsvMVR9z9NJeuctaH+7/KqwoiJwXlj6BAoWvHsnozVD973K93+yu4C
+BwWJVAZm9Y2dwis8JwkEFx7aC0FkurfT4MvaGajqR1Rr2FI0/6P81PfpLHI48/3y
+36MI6Td+OwuZ42tvIbz5dOgR1ACHJKOIbMciioDB0QKBgCtqIx4aMteQEOvXlx8E
+mmD5qNBhcWUgxexqdqrvyqLScGHuhuUHny4ytTzNMulG3S8DEC2ULrq64OZuIdyT
+XkhQHb96BsPSpUioe5MLzr5EnDLLV8Hptf4mmJctkd0eczgvtlX9QyFp9LpeqAMQ
+FA21NyLKatm942vrWMsBGrcS
+-----END PRIVATE KEY-----
+`
+	SelfSignedECDSACertificateNoDigitalSignatureKeyUsage = `
+-----BEGIN CERTIFICATE-----
+MIICiTCCAi+gAwIBAgIJAKVi77tebfBPMAoGCCqGSM49BAMCMIGFMQswCQYDVQQG
+EwJVUzELMAkGA1UECAwCQ08xHzAdBgNVBAcMFkFwYWNoZSBUcmFmZmljIENvbnRy
+b2wxFDASBgNVBAoMC1RyYWZmaWMgT3BzMRUwEwYDVQQLDAxVbml0IFRlc3Rpbmcx
+GzAZBgNVBAMMEiouaW52YWxpZDIuaW52YWxpZDAeFw0xOTAzMDYxNzM3MjNaFw0z
+OTAzMDExNzM3MjNaMIGFMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xHzAdBgNV
+BAcMFkFwYWNoZSBUcmFmZmljIENvbnRyb2wxFDASBgNVBAoMC1RyYWZmaWMgT3Bz
+MRUwEwYDVQQLDAxVbml0IFRlc3RpbmcxGzAZBgNVBAMMEiouaW52YWxpZDIuaW52
+YWxpZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIOpnfYOa2+Fxhxl996A5cvU
+OUrpY1/oy6uUdBmgo0Rfal9lv5NiMRhgg7s++jr2yf8ls2zLIosNPShIVLJl9Sej
+gYUwgYIwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4E
+FgQUcjdTM122v7VK7gWXexBLg+1fCu0wHwYDVR0jBBgwFoAUcjdTM122v7VK7gWX
+exBLg+1fCu0wHQYDVR0RBBYwFIISKi5pbnZhbGlkMi5pbnZhbGlkMAoGCCqGSM49
+BAMCA0gAMEUCIDybXtWSTIeyETgLBGitveWAYh8dmBK/Wt3+Jdj/5GF6AiEA95I8
+96/cXDmduClIg4CnYLGbkDPsC+3nENEIr92WqgE=
+-----END CERTIFICATE-----
+`
+	SelfSignedECDSAPrivateKeyNoDigitalSignatureKeyUsage = `
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIPrjdSmSp6D/M6KBOwwz7u/NzO70nBT0U74QSCBWmwAOoAoGCCqGSM49
+AwEHoUQDQgAEg6md9g5rb4XGHGX33oDly9Q5SuljX+jLq5R0GaCjRF9qX2W/k2Ix
+GGCDuz76OvbJ/yWzbMsiiw09KEhUsmX1Jw==
+-----END EC PRIVATE KEY-----
+`
+	SelfSignedECDSACertificate = `
+-----BEGIN CERTIFICATE-----
+MIIC/jCCAqSgAwIBAgIUXHzSgl46W/BuBZ+Vf8qyBa/qVZwwCgYIKoZIzj0EAwIw
+ga4xCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhDb2xvcmFkbzEPMA0GA1UEBxMGRGVu
+dmVyMRUwEwYDVQQKEwxDRE4taW4tYS1Cb3gxFTATBgNVBAsTDENETi1pbi1hLUJv
+eDEkMCIGA1UEAxQbKi5lY2RzYXRlc3QubXljZG4uY2lhYi50ZXN0MScwJQYJKoZI
+hvcNAQkBFhhuby1yZXBseUBpbmZyYS5jaWFiLnRlc3QwHhcNMTkwMzMwMTgyMTIx
+WhcNMTkwNDI5MTgyMTIxWjCBrjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCENvbG9y
+YWRvMQ8wDQYDVQQHEwZEZW52ZXIxFTATBgNVBAoTDENETi1pbi1hLUJveDEVMBMG
+A1UECxMMQ0ROLWluLWEtQm94MSQwIgYDVQQDFBsqLmVjZHNhdGVzdC5teWNkbi5j
+aWFiLnRlc3QxJzAlBgkqhkiG9w0BCQEWGG5vLXJlcGx5QGluZnJhLmNpYWIudGVz
+dDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABB1UpeDr4LCoxdYwziBAWpNJGeUK
+3ikfqHn9dFr/p9I3j24yo9lJcvjGB7LP0euKr0Qjnsgm1cq6xR2meFEfutGjgZ0w
+gZowDAYDVR0TBAUwAwEB/zARBglghkgBhvhCAQEEBAMCBkAwDgYDVR0PAQH/BAQD
+AgKEMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAzAdBgNVHQ4EFgQU
+ASswQL7PBDEAWVySy/6K3UBrP8owJgYDVR0RBB8wHYIbKi5lY2RzYXRlc3QubXlj
+ZG4uY2lhYi50ZXN0MAoGCCqGSM49BAMCA0gAMEUCIFS0uTwkNybSS/m+DbkDAi0j
+FueoHu2+4E9uF4iy6g9jAiEA5IQfSN4S4Oyr6fQkFZx7OrymvechwOXjHcxa7BmB
+zo8=
+-----END CERTIFICATE-----
+`
+	SelfSignedECDSAPrivateKey = `
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEINVb8yaaCT14CVhYVaOv3fmGpEVuXvTclOQYIZq793svoAoGCCqGSM49
+AwEHoUQDQgAEHVSl4OvgsKjF1jDOIEBak0kZ5QreKR+oef10Wv+n0jePbjKj2Uly
++MYHss/R64qvRCOeyCbVyrrFHaZ4UR+60Q==
+-----END EC PRIVATE KEY-----
+`
+	SelfSignedECDSAPrivateKeyWithoutParams = `
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEINVb8yaaCT14CVhYVaOv3fmGpEVuXvTclOQYIZq793svoAoGCCqGSM49
+AwEHoUQDQgAEHVSl4OvgsKjF1jDOIEBak0kZ5QreKR+oef10Wv+n0jePbjKj2Uly
++MYHss/R64qvRCOeyCbVyrrFHaZ4UR+60Q==
+-----END EC PRIVATE KEY-----
+`
+	SelfSignedDSACertificate = `
 -----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
+MIIF6TCCBY6gAwIBAgIUHRv+ycqq+/HTUnXc3uMefnW3qrowCwYJYIZIAWUDBAMC
+MIGsMQswCQYDVQQGEwJVUzERMA8GA1UECBMIQ29sb3JhZG8xDzANBgNVBAcTBkRl
+bnZlcjEVMBMGA1UEChMMQ0ROLWluLWEtQm94MRUwEwYDVQQLEwxDRE4taW4tYS1C
+b3gxIjAgBgNVBAMUGSouZHNhdGVzdC5teWNkbi5jaWFiLnRlc3QxJzAlBgkqhkiG
+9w0BCQEWGG5vLXJlcGx5QGluZnJhLmNpYWIudGVzdDAeFw0xOTAzMzAwNDUxMzha
+Fw0xOTA0MjkwNDUxMzhaMIGsMQswCQYDVQQGEwJVUzERMA8GA1UECBMIQ29sb3Jh
+ZG8xDzANBgNVBAcTBkRlbnZlcjEVMBMGA1UEChMMQ0ROLWluLWEtQm94MRUwEwYD
+VQQLEwxDRE4taW4tYS1Cb3gxIjAgBgNVBAMUGSouZHNhdGVzdC5teWNkbi5jaWFi
+LnRlc3QxJzAlBgkqhkiG9w0BCQEWGG5vLXJlcGx5QGluZnJhLmNpYWIudGVzdDCC
+A0YwggI5BgcqhkjOOAQBMIICLAKCAQEAkypAr0SzwNcEKDm2kiAx7joazQBU1thr
+8eIUZAiMpSnpUH6svCPUilYjqhQVIR2F5Pekh/NcnuGGHkZyCKGbS9xKZnndZ2V4
+TA3HDyvTBv8jnfSfah7QYD77E5ju9A050KVxTZpYhNfboRv0PWg1x/WCzqWtYWPP
+s7DFEBPhKZcMRTmnELwbM94pPIyFEEDJLL50k1sqbK35mOc+APDioly1EyUGXj/8
+qsCnFDv8EKH6UG5bO9Q1fGEPTqgCcQKWFrbdc6UYZKu+gScMEyax4YktirTEeX46
+o3VnGKXUwslEZhj+HdAnhJzKOUs3xdwzqVjZ4xxh6oY3oEuxarcXmwIhAMYi2lmV
++b4aP6cuzi3dHEKzm/Z70yQi5F+w5S/g2IvxAoIBAEUB1+oPc59wsNjx7NhmlxXx
+IR5Hya+6KHlOP/lK1/s/kcCzDvf7uAMFepgKL2geA1y36fllGPL9wImFh9uZprtK
+WA1n6Xt1bTsrfoEdrYhYyo5zSliGVuiZ6VLA3egb8WAoyGe8js8Qd+NWkJrjoQfn
+QymLv2Q9rFYpzc73OVMuNJfYmbkCOwqx4NxXuR41tV4o4WFpp+2h4VtES69FdT/y
+GAFgYm62qnqgjTvR6/8Pi0mjjps6RBlK6NucKwbd2E3wI/2lIfImEaRANMhbpUaa
+grrqTsDBsxRykKS1UdjyZniV4TOV4Xjdc0RF8w9JbvRyKbA+KAgv9p4qGxexrDcD
+ggEFAAKCAQA8/GqhpKc6AX1ssmo1EQcMWQo+od7LbVEXYRwi/L6BU3CPUIHSz4bw
+AtzlwDvSLI8Tbp1Qzs2VBkcT4KbOiIRw4xAsuW+hHBJast2cA7grCP2c0aTe81FU
+Kz7KMoH4Xu/cYgd9TOCvLUT5fqJzjI8Sk5z/eJ0q/3kO57GDNgLi/WHFY9Abn7yb
+6MpkNc53mi6glMRc0D0d/W5MrSIrq/w+7lwM685pQ9TbPR0Xoimm4rur4/w92P9Z
+ydMp9uDeijwl+qFiUBzne66IWx5GH88FQtuWL4cDuyfxRPs4E2vC3pk37zi1b6qJ
+1pmcYSbUKMbENbqLuW9jfNdisVUQByPQo4GbMIGYMAwGA1UdEwQFMAMBAf8wEQYJ
+YIZIAYb4QgEBBAQDAgZAMA4GA1UdDwEB/wQEAwIChDAgBgNVHSUBAf8EFjAUBggr
+BgEFBQcDAQYIKwYBBQUHAwMwHQYDVR0OBBYEFJ5U5dSqX0eUO8VuLqSYRtvQbMs/
+MCQGA1UdEQQdMBuCGSouZHNhdGVzdC5teWNkbi5jaWFiLnRlc3QwCwYJYIZIAWUD
+BAMCA0gAMEUCIBCA3RYYn4DK/nzKK4cTbtmj6V72Ywoh6YJ3taZ18iYIAiEAxV5u
+qL6kmx7XWFAhA3NKMW79Cz6hmhDo0ZFPf1G258Q=
 -----END CERTIFICATE-----
 `
-	GoodTLSKeys = `
+	SelfSignedDSAPrivateKey = `
+-----BEGIN DSA PARAMETERS-----
+MIICLAKCAQEAkypAr0SzwNcEKDm2kiAx7joazQBU1thr8eIUZAiMpSnpUH6svCPU
+ilYjqhQVIR2F5Pekh/NcnuGGHkZyCKGbS9xKZnndZ2V4TA3HDyvTBv8jnfSfah7Q
+YD77E5ju9A050KVxTZpYhNfboRv0PWg1x/WCzqWtYWPPs7DFEBPhKZcMRTmnELwb
+M94pPIyFEEDJLL50k1sqbK35mOc+APDioly1EyUGXj/8qsCnFDv8EKH6UG5bO9Q1
+fGEPTqgCcQKWFrbdc6UYZKu+gScMEyax4YktirTEeX46o3VnGKXUwslEZhj+HdAn
+hJzKOUs3xdwzqVjZ4xxh6oY3oEuxarcXmwIhAMYi2lmV+b4aP6cuzi3dHEKzm/Z7
+0yQi5F+w5S/g2IvxAoIBAEUB1+oPc59wsNjx7NhmlxXxIR5Hya+6KHlOP/lK1/s/
+kcCzDvf7uAMFepgKL2geA1y36fllGPL9wImFh9uZprtKWA1n6Xt1bTsrfoEdrYhY
+yo5zSliGVuiZ6VLA3egb8WAoyGe8js8Qd+NWkJrjoQfnQymLv2Q9rFYpzc73OVMu
+NJfYmbkCOwqx4NxXuR41tV4o4WFpp+2h4VtES69FdT/yGAFgYm62qnqgjTvR6/8P
+i0mjjps6RBlK6NucKwbd2E3wI/2lIfImEaRANMhbpUaagrrqTsDBsxRykKS1Udjy
+ZniV4TOV4Xjdc0RF8w9JbvRyKbA+KAgv9p4qGxexrDc=
+-----END DSA PARAMETERS-----
+-----BEGIN DSA PRIVATE KEY-----
+MIIDVQIBAAKCAQEAkypAr0SzwNcEKDm2kiAx7joazQBU1thr8eIUZAiMpSnpUH6s
+vCPUilYjqhQVIR2F5Pekh/NcnuGGHkZyCKGbS9xKZnndZ2V4TA3HDyvTBv8jnfSf
+ah7QYD77E5ju9A050KVxTZpYhNfboRv0PWg1x/WCzqWtYWPPs7DFEBPhKZcMRTmn
+ELwbM94pPIyFEEDJLL50k1sqbK35mOc+APDioly1EyUGXj/8qsCnFDv8EKH6UG5b
+O9Q1fGEPTqgCcQKWFrbdc6UYZKu+gScMEyax4YktirTEeX46o3VnGKXUwslEZhj+
+HdAnhJzKOUs3xdwzqVjZ4xxh6oY3oEuxarcXmwIhAMYi2lmV+b4aP6cuzi3dHEKz
+m/Z70yQi5F+w5S/g2IvxAoIBAEUB1+oPc59wsNjx7NhmlxXxIR5Hya+6KHlOP/lK
+1/s/kcCzDvf7uAMFepgKL2geA1y36fllGPL9wImFh9uZprtKWA1n6Xt1bTsrfoEd
+rYhYyo5zSliGVuiZ6VLA3egb8WAoyGe8js8Qd+NWkJrjoQfnQymLv2Q9rFYpzc73
+OVMuNJfYmbkCOwqx4NxXuR41tV4o4WFpp+2h4VtES69FdT/yGAFgYm62qnqgjTvR
+6/8Pi0mjjps6RBlK6NucKwbd2E3wI/2lIfImEaRANMhbpUaagrrqTsDBsxRykKS1
+UdjyZniV4TOV4Xjdc0RF8w9JbvRyKbA+KAgv9p4qGxexrDcCggEAPPxqoaSnOgF9
+bLJqNREHDFkKPqHey21RF2EcIvy+gVNwj1CB0s+G8ALc5cA70iyPE26dUM7NlQZH
+E+CmzoiEcOMQLLlvoRwSWrLdnAO4Kwj9nNGk3vNRVCs+yjKB+F7v3GIHfUzgry1E
++X6ic4yPEpOc/3idKv95DuexgzYC4v1hxWPQG5+8m+jKZDXOd5ouoJTEXNA9Hf1u
+TK0iK6v8Pu5cDOvOaUPU2z0dF6IppuK7q+P8Pdj/WcnTKfbg3oo8JfqhYlAc53uu
+iFseRh/PBULbli+HA7sn8UT7OBNrwt6ZN+84tW+qidaZnGEm1CjGxDW6i7lvY3zX
+YrFVEAcj0AIgQGLEWrKD5SwnFfhG5QNOjFO6RN/bNB8SanXrnzDUnkE=
+-----END DSA PRIVATE KEY-----
+`
+	SelfSignedX509v1Certificate = `
 -----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==
+MIID6TCCAtECFCs7N+H5AQ4SN7lVyK+bHTrKgwOGMA0GCSqGSIb3DQEBCwUAMIGw
+MQswCQYDVQQGEwJVUzERMA8GA1UECBMIQ29sb3JhZG8xDzANBgNVBAcTBkRlbnZl
+cjEVMBMGA1UEChMMQ0ROLWluLWEtQm94MRUwEwYDVQQLEwxDRE4taW4tYS1Cb3gx
+JjAkBgNVBAMUHSoueDUwOXYxLXRlc3QubXljZG4uY2lhYi50ZXN0MScwJQYJKoZI
+hvcNAQkBFhhuby1yZXBseUBpbmZyYS5jaWFiLnRlc3QwHhcNMTkwMzMxMDM1MDU4
+WhcNMTkwNDMwMDM1MDU4WjCBsDELMAkGA1UEBhMCVVMxETAPBgNVBAgTCENvbG9y
+YWRvMQ8wDQYDVQQHEwZEZW52ZXIxFTATBgNVBAoTDENETi1pbi1hLUJveDEVMBMG
+A1UECxMMQ0ROLWluLWEtQm94MSYwJAYDVQQDFB0qLng1MDl2MS10ZXN0Lm15Y2Ru
+LmNpYWIudGVzdDEnMCUGCSqGSIb3DQEJARYYbm8tcmVwbHlAaW5mcmEuY2lhYi50
+ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzXMtRmZ4SVYpO4yf
+00kKJD7MKCVzjTOKJNiOyJn++RYNX64gZU7a8LRefvruv6wO1Ic4IR7xvZ58t/sg
+He6AoHW3Uz9XJ4knZ1BHNFHYsaELSDUkPNRowQprzJmAf3yDrn6kWrLVgX0iWrQh
+T5UJxgS7L1iNibqAKFGkr0tRMk0rwjBzm5CGGyt1WS/J1W3h/R05BaDXukSCoSlo
+cx1XgmldCQE27de+WXusITZse5h+Giei/hGkHdJJr1aROP3y+czeOF1YOr24p/0T
+HPrir0iesWV2+bA/Tdj5hVWipt1OJBwOvfull9fZTvC1RRdhIyUJauWr4iwD2gpn
+UI8OywIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBaEUQcKbLhlcyEE0OfcKTmHdwl
+uhUpE55FkVJP9TN5nNAziYW+KRWiSyRdn/35s5Z+bFplbzT7Au5tZw6kTtkmtim3
+i6v7nNLES0hnj+zRybut4yEw9Ma0p/exiT0+qqVynBdgtpVwOcYIvgYlGgVUttNN
+b/nKxOXZ9qDkqBDgMbXmYHCI5txFnqblLP8dW0CeFYIL0RuBx2qS5edYw8oTZPOL
+b/CpL85+xi6pd+bOQ3UXbTaa78HEwcP1nX3IKzuMjtxUmZ5d2Gbo6TihuXiWCJHW
+i/LiVIfp1/TNdiOvLRXYZV5itIKpgmr8nYCX8QRUewtP9Ex4RRcoEKQdVRpI
 -----END CERTIFICATE-----
+`
+	SelfSignedX509v1PrivateKey = `
+-
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDNcy1GZnhJVik7
+jJ/TSQokPswoJXONM4ok2I7Imf75Fg1friBlTtrwtF5++u6/rA7UhzghHvG9nny3
++yAd7oCgdbdTP1cniSdnUEc0UdixoQtINSQ81GjBCmvMmYB/fIOufqRastWBfSJa
+tCFPlQnGBLsvWI2JuoAoUaSvS1EyTSvCMHObkIYbK3VZL8nVbeH9HTkFoNe6RIKh
+KWhzHVeCaV0JATbt175Ze6whNmx7mH4aJ6L+EaQd0kmvVpE4/fL5zN44XVg6vbin
+/RMc+uKvSJ6xZXb5sD9N2PmFVaKm3U4kHA69+6WX19lO8LVFF2EjJQlq5aviLAPa
+CmdQjw7LAgMBAAECggEAQUsFbIZMXCJB4GcEtEVWL8a1Y1zjqFBk6ujYF/C5E7hq
+b6oLKacx9aWdEoX1Mn0gCXMf54bKFRU1VdM9lcWio1xF8vMCY9I276KXvoz0bR9d
+UolxBtQKpq8FK3TtXZbY0q/0085aBFkcfe8ZVw1qmcAPLTDbapYW/LlVuVAacf16
+Ism+oVlpGosrG8pVe2nkxRLkA+FBsFNeliX8YucgvOcQWMjcJ1VPYgfA/7b8q4b7
+cVxfs7l+SrtMMYNNOM695b3AEW2Tve5JwNGEvaOJsHqS+VNHZ9T4NAr+ZAU6C237
+rM6dfPMqb/177Yvz32Bq6vbYVoeb2iDnMVbjgRQvYQKBgQD8nkXLguq+MkkhhW4c
+xPYIHxZBQ948fFn1O2JKgmDR5bjQPbbXA/0Ko/l/yJ0ikNKeLC0/wXvUcQiuurIh
+gFGgOU9uzaXgThZUsv35S9fiTuT4VamcQKOA42LTbxCk9O80fz4qR/mkMFz1KtoD
+4cghfFRG/ZWpZ8ESSHOz8jzmJwKBgQDQM0HoBXkPZURj90jpg+oO4SD2ZTeAIfpM
+YiHxI/jNV8Np8DLDne0a9ncsG1cCmPekVoEV5kliekak4H211CgWIERVOOSJumH5
+VHuqLK2BoUiEiMpAKQrG3Bc7MNK1BY8G4MUu//Sj508WJzyU1OBOHRVzc6fJ0bmK
+o8EFYBg8vQKBgCufVSQYflrLqi88sFANfwLWA2zPwG+ndY1QbN+69ecpCSoEji9B
+BBAzUqFLTj8qzQP9Uu8AhVahEkPB/4KjevT1EI9suakrMtX7drn269erkgSEHl7a
+FqHqIiWqtzAVD717/4sjlKtSoqq/dJhZA8ssgg0kOxTe0stKcZhwSy3fAoGBAMxs
+R53lIcR4DfqJZtHBcCND8PV81E2/Dt/IysLWKwiTz49JBM8FVTVQIhrwjTJDt4No
+XD6AajWDEbH5qfTKZsGy1OVIgzyoAGKrDPE+BO5uyaE4Hj15DtfKahT4DysmVhTO
+xU0si6wTBZge1mDb05FfBRzixjBm9+KkfnUksSeRAoGAfVxTz3PDE3oigzh3uOtu
+3vB0xiUVGLsw6ZN1MJj/tkx631ejPV512uwMMTiP36zvYRgzbtNsFolz+jnfsZjp
+JebgC1b0m89GkINe4oO3WGhIi7hsGGFP+CvWwQnALLX0aT+05OEbfBgoVm0ywTCf
++AQpUpVQ/mLB6W1mx9AuMeY=
+-----END PRIVATE KEY-----
+`
+	CASignedRSACertificateChain = `
 -----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
+MIIE+zCCA+OgAwIBAgIFFVGJEGcwDQYJKoZIhvcNAQELBQAwga0xCzAJBgNVBAYT
+AlVTMREwDwYDVQQIEwhDb2xvcmFkbzEPMA0GA1UEBxMGRGVudmVyMRQwEgYDVQQK
+EwtUcmFmZmljIE9wczEUMBIGA1UECxMLVHJhZmZpYyBPcHMxJDAiBgNVBAMTG1Ry
+YWZmaWMgT3BzIEludGVybWVkaWF0ZSBDQTEoMCYGCSqGSIb3DQEJARYZbm8tcmVw
+bHlAaW52YWxpZDIuaW52YWxpZDAeFw0xOTAzMDYxNjUxMTNaFw0zOTAzMDExNjUx
+MTNaMGkxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhDb2xvcmFkbzEPMA0GA1UEBwwG
+RGVudmVyMRQwEgYDVQQKDAtUcmFmZmljIE9wczEgMB4GA1UEAwwXKi50ZXN0Lmlu
+dmFsaWQyLmludmFsaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDE
+oCEYaEl1mrEOJy6jO8+QXXmlb8mYAWQL+lSOPYRvzuPWOvnfvW/BkDYpvzosfDZg
+HNS106ROtWFe+kQZTTrm+xPTWMl/JIyn5ka1ZnJMAey0Oxyn2PgSmly++6esOiKH
+CZm9Zhx2p7/d/fkYhu6G0X08SKVwZdtkerfKHqPEuEEcWm1H+IbMVweKDjiAqrEe
+pcWKr/+i8NmOERCYvPFL6/Kf8/U4MrDM/3vh70DFKWZ3x5xWG7TWl3vCS4I+y/m7
+xEEQgF2vofcQO0CD09s4iRKCqbVM2vofWZVhYj63BgfbIXHYCFPyIpaTwc3u4fRW
+pnWIUp9BFUy8PqXjh9vfAgMBAAGjggFjMIIBXzAJBgNVHRMEAjAAMBEGCWCGSAGG
++EIBAQQEAwIGQDAdBgNVHQ4EFgQU8RrF6qwRsTAtsdHUDUe//WnjNskwgdYGA1Ud
+IwSBzjCBy4AUwVR9U/f9JDLi179Jc1qudzjYjhehgaukgagwgaUxCzAJBgNVBAYT
+AlVTMREwDwYDVQQIEwhDb2xvcmFkbzEPMA0GA1UEBxMGRGVudmVyMRQwEgYDVQQK
+EwtUcmFmZmljIE9wczEUMBIGA1UECxMLVHJhZmZpYyBPcHMxHDAaBgNVBAMTE1Ry
+YWZmaWMgT3BzIFJvb3QgQ0ExKDAmBgkqhkiG9w0BCQEWGW5vLXJlcGx5QGludmFs
+aWQyLmludmFsaWSCBRVRiRBmMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr
+BgEFBQcDATAiBgNVHREEGzAZghcqLnRlc3QuaW52YWxpZDIuaW52YWxpZDANBgkq
+hkiG9w0BAQsFAAOCAQEAbcOigHR11zFrPXHS7ZGG6Dro708QVrECofZJkVAKOUbZ
+kWP2h4T+xSS6WEqk/1hKKo2RhiL7UlGwdtqNZ6lk9cwQORmeuIXEgy2BsbR5H4vy
+L/2LhZzCSDYfeSbByhFdvLCNJMSGK+o49NUESD1zEJFPDDtMj/NLAgkLCSGi/8iF
+VVJpJT3zP1I/C9Zmt8eFf6sjEdoIg6PPReJzu1hcEJLz/jqLuzoGasxea/k2k06k
+Rj3GV8f3BZryN3+TKa7IiNsT7SGiZMiPWUvML/dp8aTgCNA/GlhGqzQPnDXBvgTN
+JfDXiQDnR1svJZNHEfQDPIEeY6ECBAEaU0rgH9/iZg==
 -----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==
+MIIEOTCCAyGgAwIBAgIFFVGJEGYwDQYJKoZIhvcNAQELBQAwgaUxCzAJBgNVBAYT
+AlVTMREwDwYDVQQIEwhDb2xvcmFkbzEPMA0GA1UEBxMGRGVudmVyMRQwEgYDVQQK
+EwtUcmFmZmljIE9wczEUMBIGA1UECxMLVHJhZmZpYyBPcHMxHDAaBgNVBAMTE1Ry
+YWZmaWMgT3BzIFJvb3QgQ0ExKDAmBgkqhkiG9w0BCQEWGW5vLXJlcGx5QGludmFs
+aWQyLmludmFsaWQwHhcNMTkwMzA2MTY1MTEwWhcNMzkwMzAxMTY1MTEwWjCBrTEL
+MAkGA1UEBhMCVVMxETAPBgNVBAgTCENvbG9yYWRvMQ8wDQYDVQQHEwZEZW52ZXIx
+FDASBgNVBAoTC1RyYWZmaWMgT3BzMRQwEgYDVQQLEwtUcmFmZmljIE9wczEkMCIG
+A1UEAxMbVHJhZmZpYyBPcHMgSW50ZXJtZWRpYXRlIENBMSgwJgYJKoZIhvcNAQkB
+Fhluby1yZXBseUBpbnZhbGlkMi5pbnZhbGlkMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAsu3xVwphWUz/josArTjldncVgAZHVa+NVKgJpohoyJra7IgX
+IpNY9dlMd4wydPc2/Y2yc6lcZ/XlfzWQS5hYsOqMoWsylC38ZeX9yminQ+Q0TFsz
+EMK3v9aFV9kiFIKPh15wF1Iau1HMypN6e61rE8ThEixLU3gGLHhMvDuD+JIoIJzj
+b9DvF0GU8kJr/ur4oJQDSnGiW4cg+IGsySH4y9e9NMZmwpnNprXVkP6Rr94UKAfB
+KJDb683VeuuyyknwC6ZNmUYuSLIUxXi5UPbKQi20zwJkHbXui8aBMPvOIUKXSiCd
+y5apfzZw22npUUbkarg6d26BU2hVjOd+6VyrqQIDAQABo2YwZDAdBgNVHQ4EFgQU
+wVR9U/f9JDLi179Jc1qudzjYjhcwHwYDVR0jBBgwFoAUwYqnYixb6XZqbD7dpFMx
+280Z+5YwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZI
+hvcNAQELBQADggEBADiiT8vhjan43mJDv0kFS7xipePJeXbLGgAu3PocoR9qUbh+
+7Q2Zj5p1rCDaqUoUB8C5p1T3JjPxeGLQ3A9qjWP1FUhbsHTfJzcU989Q73Iomx3k
+cmmQhWt+xvCpxGFmvjBpEyyIhCkgoGBUfHQFjcyrLWbaLRXOR1eF9B0YORbJmf10
+1lxg8PQ3LclCs9m4XSI2THiURDN4dFANRYqcWvg0ncej/SOXJQ+OZ5K1AJ9z/acB
+GT/EpQ6YfSyxOsKVPAu3mrIxfOAqahKFJa4bgV+a5SmiENYEKYaWObAgMpO+Ud5F
+kG5IVBDJicJm/kazyAs2f4NmW+8p8CKEdrB/6gI=
 -----END CERTIFICATE-----
 `
-	rootCA = `
+	CASignedRSACertificateChainPrivateKey = `
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDEoCEYaEl1mrEO
+Jy6jO8+QXXmlb8mYAWQL+lSOPYRvzuPWOvnfvW/BkDYpvzosfDZgHNS106ROtWFe
++kQZTTrm+xPTWMl/JIyn5ka1ZnJMAey0Oxyn2PgSmly++6esOiKHCZm9Zhx2p7/d
+/fkYhu6G0X08SKVwZdtkerfKHqPEuEEcWm1H+IbMVweKDjiAqrEepcWKr/+i8NmO
+ERCYvPFL6/Kf8/U4MrDM/3vh70DFKWZ3x5xWG7TWl3vCS4I+y/m7xEEQgF2vofcQ
+O0CD09s4iRKCqbVM2vofWZVhYj63BgfbIXHYCFPyIpaTwc3u4fRWpnWIUp9BFUy8
+PqXjh9vfAgMBAAECggEARD43flsjs9eewATFYQ4vOjHXOJ4V39YLvUSC+GNNhejO
+ltodQ5RiJ1JAGjkunaX20WDwSrNMAa1eQDKoVAfD+8sE1IOqW6B52QRJYkhOPycj
+2mHxzie14e8FZZu+VD5RIYEphNzd4CjUpN2zCNo8CzrGNpgYI2yWuscE5ve/a1TT
+/diQVMpnDQkOFbqAmGS70hAjcSJ1yW5nUSSXmjjlEkxOmWt4wqLUYTmrqcW5DKxv
+jmxoRb1XdWzT+ryXOVX6ilvjlQVMi4k+ohvV6svFjkRiTdii16/YK9CbRaZvq8eU
++F53LF68Cv4YlX/5C4pcwyEf+I/UolDfyNE4NrY4kQKBgQDsvYpenMs80H14wd3r
+O7QpaIvZe6u++nIa9Pa0n4gwsieBEHAhrvJvqln6h2mOuWL8I6cSERBVqqUD3F5w
+HdNa8mStpIF+XlBmQW5UGZTqUk6KugJzIB6ZBXKOfW6g/+xaQmC0tFTzuvsV0pZ0
+X8EmsW9xbBe/+Y/zOgLXpsfgtQKBgQDUnyNz7Gaq2SldGEVMrI8eicfV8KcH0rK7
+ocUnESxL9zvNFkz9wz1t5/D4L/D3XuLAjXtKV1lUvbzVxHh46GQxvz0/5swYjL71
+rhEDqQF2t7PISxXFq9yMAg5iOxyLwBFGDcNsL6G5SdXpM/YWGo7wSwsWdYEzZULs
+UZ/ZOQIqwwKBgQCfFh/NxH+utkwawexnDw/aY67Wzwxyocnb45GFf079qjpxuKIh
+gHbaIxekCyscBehGl47FzUG0z59kIMo1fVVyYEDXjxyV1rsgfAev7CDt9bFh9+19
+f7AQFGEO76tP9arWXJSv2h7cSmJAH+uK+G3LmqDRD1pGX2YkhG80i5b1oQKBgQCo
+GMypqJuetSObo0WekcpwxVNFVAZqC+0cpI+/DDeuM1+HC/uAoKvfSYFcZmKm39B7
+lR+FLbvFYGB7zOHGDUyxe9VLwQdY3WVXzO9MqoAqwJ+VWa9z4STzV+jRRpSR9B5z
++Quoa5v7ZmGFBnynCwY4+cthTTMBVCxtszaiQQzyiwKBgQDnJLZONi3IcsgGOuka
+4qYVQl7sSIuBJ1gyZr44WjoUlykxLij59MEnAOolR86PWif6VgNfsJL4MqTkaX++
+PgH8k1z8wkIxUP94BXLfSHJyUriHMPX45T3Rr6uBrvtVujRNIHndGKDoa7P16Hzz
+otCrxsW0tXSVJ1KfW1Cwb7jtHA==
+-----END PRIVATE KEY-----
+`
+	CASignedRSARootCA = `
 -----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==
+MIIENDCCAxygAwIBAgIJAKtfkOE64RynMA0GCSqGSIb3DQEBCwUAMIGlMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMIQ29sb3JhZG8xDzANBgNVBAcTBkRlbnZlcjEUMBIG
+A1UEChMLVHJhZmZpYyBPcHMxFDASBgNVBAsTC1RyYWZmaWMgT3BzMRwwGgYDVQQD
+ExNUcmFmZmljIE9wcyBSb290IENBMSgwJgYJKoZIhvcNAQkBFhluby1yZXBseUBp
+bnZhbGlkMi5pbnZhbGlkMCAXDTE5MDMwNjE2NTEwN1oYDzIwNTkwMjI0MTY1MTA3
+WjCBpTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCENvbG9yYWRvMQ8wDQYDVQQHEwZE
+ZW52ZXIxFDASBgNVBAoTC1RyYWZmaWMgT3BzMRQwEgYDVQQLEwtUcmFmZmljIE9w
+czEcMBoGA1UEAxMTVHJhZmZpYyBPcHMgUm9vdCBDQTEoMCYGCSqGSIb3DQEJARYZ
+bm8tcmVwbHlAaW52YWxpZDIuaW52YWxpZDCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAMi3d1btekZha72UWkdJvsuZenp8zNiQW7OaLLyZvLbvCncm6sNG
+nZTVTkq5LZnrq2sOc04JIf7gFJc8vnJdBPEZEP5GRbWXmel4Q4qnoOcCr4/6UZ5I
+1gG1JkGMsMWq83Zv/jqtjBSpIO9fQFEiv6h9jUAkzln7lfvpM892qCKZCFLh89TZ
+5flSmwmNVOW5IFvUu9uFdKDBzOYaXpBXXhua3ewh9YqUtCfwBH/zz8bb3Shm9p55
+RhT0Rp4yQpFB4FwG0MxNNqjZ8BLuF9pleTcRlTrVwTLQ2sOq7HndvyyahxtSP3BF
+plFrnnzmeOZjtr7RRPvG/22fHxb6lGxnXEkCAwEAAaNjMGEwHQYDVR0OBBYEFMGK
+p2IsW+l2amw+3aRTMdvNGfuWMB8GA1UdIwQYMBaAFMGKp2IsW+l2amw+3aRTMdvN
+GfuWMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMA0GCSqGSIb3DQEB
+CwUAA4IBAQCRtSa8H5mwNKT1SgSjEatLMLjzYk1jpfIns6hR2X5f+D/kZkpgPX/d
+4dAke1DnMIyxE43t1RJJzoi1BhFg9YvEyNU5k5L7ECuYmgU5tbmeNx2cDu4Huy5k
+6ZmQ4Amh01X3JY3MFARJyRi/+CvmT+SbwdKYs8fwhPbGcLRhlUC0tvFe6JfvceH/
+18TRlcDPC51+f+WidVkWC8Er7Mydv+bmNYqEgDEJ0UQWtI/j/hxYj1wuqvUaoN2A
+GcDuf0HznG/JMOtoGmMELyxJlIHCBPG1h+myLON9/XuPHlhMQcIhmqNEBBGwSdwm
+1Ybc3W8sUkBAEha1Nm4SGJOz2Lfk/rAZ
 -----END CERTIFICATE-----
 `
+	CASignedNoSkiAkiRSACertificateChain = `
+-----BEGIN CERTIFICATE-----
+MIID/zCCAuegAwIBAgIFFVGJhGIwDQYJKoZIhvcNAQELBQAwga0xCzAJBgNVBAYT
+AlVTMREwDwYDVQQIEwhDb2xvcmFkbzEPMA0GA1UEBxMGRGVudmVyMRQwEgYDVQQK
+EwtUcmFmZmljIE9wczEUMBIGA1UECxMLVHJhZmZpYyBPcHMxJDAiBgNVBAMTG1Ry
+YWZmaWMgT3BzIEludGVybWVkaWF0ZSBDQTEoMCYGCSqGSIb3DQEJARYZbm8tcmVw
+bHlAaW52YWxpZDIuaW52YWxpZDAeFw0xOTAzMDYxODU0MjVaFw0zOTAzMDExODU0
+MjVaMGkxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhDb2xvcmFkbzEPMA0GA1UEBwwG
+RGVudmVyMRQwEgYDVQQKDAtUcmFmZmljIE9wczEgMB4GA1UEAwwXKi50ZXN0Lmlu
+dmFsaWQyLmludmFsaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS
+Mski1L4DVQfYdwXBxBHAWD3ZdpoS+MZa3lJXPMecpNOQfZmFzI16l3oKaePK0t2a
+2BmxPmueiQ4UD4n2x3Z4bV/sjz6W13ATZs+N3EZopkr5kjr5T4NxiHaWA2JCFBFF
+aMhJwoX4g94pUuHKHm5iMr7mr6nJLKwXW1RrZ3hl8q3vBoo0DzyZ1lIo+s1MqMzG
+G86Wdw49lNwgi4eCMBPnX+UOENij0Kl80KfoCsp9FOxbAtZIpP5cgmb8EQnmuaoV
+wbetaz2sZ+S/qasSr1nlD9wuZ74dCTxnPzt+hguyhiSLra0sd48ie9QdCqSHyYAc
+rmNtELNY3ytbEN2KG0xnAgMBAAGjaTBnMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEB
+BAQDAgZAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAiBgNV
+HREEGzAZghcqLnRlc3QuaW52YWxpZDIuaW52YWxpZDANBgkqhkiG9w0BAQsFAAOC
+AQEAHkjRjqQSsLCJUQE6QNBcx5I+hle3InFiyvr5u2DAuL95GzA4LQbk1voYFj2h
+fCgAE9ON2aViPjlqQcPYl+2Koyk0vkQwkSb8oJsEucAcAGk65BmlBVDbM9IgVC96
+ILYuk0kT+Y0CgvEWBftodYs8xKEAkNuopUTKZH1iPLIFghI3cxuU56G6A4XUFEbZ
+Af5qM2UBxFnKPPm7HyKs7WPoud9/V4d7UaaspXwFdvA7f8bGJvgjHGYE8XBZONgQ
+YJWLBgCfIKF0LqXAFwVrbbzJEshRT+WXCNvCCq5+AJK4gBaovzk7QkAREkwTe7Du
+++NBiHeG0TrPN6tX7Ke7EUYcHg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID+TCCAuGgAwIBAgIFFVGJhGAwDQYJKoZIhvcNAQELBQAwgaUxCzAJBgNVBAYT
+AlVTMREwDwYDVQQIEwhDb2xvcmFkbzEPMA0GA1UEBxMGRGVudmVyMRQwEgYDVQQK
+EwtUcmFmZmljIE9wczEUMBIGA1UECxMLVHJhZmZpYyBPcHMxHDAaBgNVBAMTE1Ry
+YWZmaWMgT3BzIFJvb3QgQ0ExKDAmBgkqhkiG9w0BCQEWGW5vLXJlcGx5QGludmFs
+aWQyLmludmFsaWQwHhcNMTkwMzA2MTg1NDIyWhcNMzkwMzAxMTg1NDIyWjCBrTEL
+MAkGA1UEBhMCVVMxETAPBgNVBAgTCENvbG9yYWRvMQ8wDQYDVQQHEwZEZW52ZXIx
+FDASBgNVBAoTC1RyYWZmaWMgT3BzMRQwEgYDVQQLEwtUcmFmZmljIE9wczEkMCIG
+A1UEAxMbVHJhZmZpYyBPcHMgSW50ZXJtZWRpYXRlIENBMSgwJgYJKoZIhvcNAQkB
+Fhluby1yZXBseUBpbnZhbGlkMi5pbnZhbGlkMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAtkDh9gusfqgvuTN/EYfiXS/JbnX34R9Kjau3JRqA+CttbY7i
+5pYbb+xdVBiUSEO2hikIF9LbuCrEQUdwPbBdX5gratDcOquqwYj47uh9ii1UEsH+
+7Sa4aV2Tr1zOFLrdkuKdJIUk1Gwp6yfoLAsXDfmScIY61EMfEcau9zH/UlCNMbfT
+UMYIkJJK8iPyFlS/EehhFuPd+0Mjd/qXPCBBD0bCcJLVka/mAjKyXZPJ6Vyh4/UD
+5Ne+bVp7VatiWaiAf7wCF0pOr81yTdEYV7Sp53fXMUEuwACClV88YlET3eGwfSXd
+j7ugKBnyDX3TlgOZix88qRhrJro+Zr9i4RMl8wIDAQABoyYwJDASBgNVHRMBAf8E
+CDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIChDANBgkqhkiG9w0BAQsFAAOCAQEAWIM+
+R69UBhumUvzLsw2xXTPmHElzuM0w5BQMfJcvZ3gsdo0wvCXkKQPSu2yPBH0BuqRt
+l29Ng3+ciuvRqk+wnDp8BH651U6U7oqSw2V7alOOy4ugPdQm7NNbJuOSYCCAngEh
+ohEloW/4CGLyyY4ffNfoPySgl0xXL8B/QVuTuw/0IPK448ziUJ346sZf1oBQcM2y
++gHfbNp+jQM9lQeQhjv2TKFZKrfy6uS5hHQAlpo17e0oPZA+Yw6+hQ1n91CGZ/Xx
+rWm+oBTAyZUuL0NgHBCwGzZMpqKk2hyevvOC3yWQsxhbh3Q92ucxx3ifQv+WsGu5
+e8Rwmr3/doh6voOnGQ==
+-----END CERTIFICATE-----
+`
+	CASignedNoSkiAkiRSAPrivateKey = `
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDSMski1L4DVQfY
+dwXBxBHAWD3ZdpoS+MZa3lJXPMecpNOQfZmFzI16l3oKaePK0t2a2BmxPmueiQ4U
+D4n2x3Z4bV/sjz6W13ATZs+N3EZopkr5kjr5T4NxiHaWA2JCFBFFaMhJwoX4g94p
+UuHKHm5iMr7mr6nJLKwXW1RrZ3hl8q3vBoo0DzyZ1lIo+s1MqMzGG86Wdw49lNwg
+i4eCMBPnX+UOENij0Kl80KfoCsp9FOxbAtZIpP5cgmb8EQnmuaoVwbetaz2sZ+S/
+qasSr1nlD9wuZ74dCTxnPzt+hguyhiSLra0sd48ie9QdCqSHyYAcrmNtELNY3ytb
+EN2KG0xnAgMBAAECggEBAKyW3IXH7nin8bgwCj8OMZEgIzCSbHHVaHCmCS/uDOw2
+fiwupMayrRwSkjdIuKwJtcF1XKsm2JCkcjXQiHRjVIgPLmr7NuX94N1dVmBhlEJL
+AFapVdjtC71F0jDceGpPNdsq7QF7QitKgzilABXIJNRmXE7nv14aWvcWm1tQ6w+w
+1RkAEqmPcmEzGeOxWWMcaUFamEPI/SDGIDSYyeVW3qH2afqgm2B3WMU0A9hM2iDV
+rTXYQpQCaTulSSCNYXCou+cOlvN+Jvf21OjxoZ0/UjGqeM42aCdyUU9K0Jc56Ps6
+RdW8rObTAYFQJj1wp9NB41QRh02HIBp7yhyyazJoXIkCgYEA8VbRqwNN7g3QmCp9
+gDxm/CQ+1tDFfbSteRnvcPwpQoLY8L+XOCws8VPP3IfKSwVU21CS+ji+0uk+x8nj
+83iyFHK8K/ToAeijllftACcBgJDQOfRq9LrXwHBCIvTq4pwNoPiSVwtUotaZ5AQX
+DMTOB9T6hnMu+YpaOtq84O2xHyMCgYEA3veuizIYnpi1QnTDB5zn08EWLWQYMjrq
+K4SUqgL3Y81dls34bPHHAPqcK62pMRnK7qbgdJ7wjJiODC3ZZ7bjZHJFNFO7RzEA
+ktFNCZ344CuX7vNR9NywathFA46mu/eCKWJLI/NrF1IclGG08ju+y8lrFm0UdxOe
+9G228h30s+0CgYBHOCOvn84Djjgcb42RpkGN7vRMWFevfP4kWq76XK+gXRTAFwn9
+Haw1m1If9kKQWQZtoh19kfleLE7GjqGiW9/RgPpezmsZBRohZ9kczmX3FsUcFTDq
+/6hjtb0Oq9AVB5BODIzC+ykC1OmdDEfxELLsRMGZo6wdH+L4s0xB5GL8mQKBgGMs
+S6iCKc0xIz5h7PWP5tWbBqA96z08Uzf0CqPsGdl8WOpgxuS+TcOztI8A+UZrsIWi
+GCgHIfuHR3dHVXH6OP5OjVWPALfTpeunyNpEN5SOD1ArTgLZvmZnt5qzcpocpvp9
+S+q7tKB0111wcClmRaEi/8zDy9yDD6qsujjK9jKpAoGAWQCY3cGmJD5tbt2FtHbb
+hcAmRHPHGNps2rfW6JzQsLcb47Tp5iqt8aZYTtehnQyb7wyBdP68MGloenI6x3dQ
+UjVsFHOBQq/cUVgoIlKcm9kmByjmGKcgWtPHi0lFT8u8kLvxf2NUiZyKDis+P2xq
+0ojmGWKT22C4HUSsMTfq2Ew=
+-----END PRIVATE KEY-----
+`
+	CASignedNoSkiAkiRSARootCA = `
+-----BEGIN CERTIFICATE-----
+MIID9DCCAtygAwIBAgIJAJSR9zIym8jSMA0GCSqGSIb3DQEBCwUAMIGlMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMIQ29sb3JhZG8xDzANBgNVBAcTBkRlbnZlcjEUMBIG
+A1UEChMLVHJhZmZpYyBPcHMxFDASBgNVBAsTC1RyYWZmaWMgT3BzMRwwGgYDVQQD
+ExNUcmFmZmljIE9wcyBSb290IENBMSgwJgYJKoZIhvcNAQkBFhluby1yZXBseUBp
+bnZhbGlkMi5pbnZhbGlkMCAXDTE5MDMwNjE4NTQyMloYDzIwNTkwMjI0MTg1NDIy
+WjCBpTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCENvbG9yYWRvMQ8wDQYDVQQHEwZE
+ZW52ZXIxFDASBgNVBAoTC1RyYWZmaWMgT3BzMRQwEgYDVQQLEwtUcmFmZmljIE9w
+czEcMBoGA1UEAxMTVHJhZmZpYyBPcHMgUm9vdCBDQTEoMCYGCSqGSIb3DQEJARYZ
+bm8tcmVwbHlAaW52YWxpZDIuaW52YWxpZDCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKSMntoOnNIqxYKDAM7T3hLleGV/DXTkUbFdg3YuJFfYCmIg5MUP
+XjmpdzXmvZAxGlKUb5Np7lZeY2xRt7DqK3vVbOmFLAryAgyglD5eTq8VESegUogt
+pdI1ROhVYV3/aS1/jkfJWZjGfRim8NZ5RhisHRd0++oDmRUh0H0+e7zRbCNEPvDY
+Vmw3JTaPwJz6ULgbOqHGofNwQFUJN4E0TBzt/qzC7r11aaQQag/j+TlPi0UTq46A
+7pbm9kFD4kdEOQ3M6jAowyEAfei0Xq8jeHcf6eMeD+tki0AenXdrx7yTZqX5fwgc
+wHUiwUZ2vZklescONvbbuW/WePA2uYKfYoECAwEAAaMjMCEwDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAAO2gylryjq2
+Ou+mm4E8On/Ecchci1FUlc8ZLAzxxTdtJDZQd4b6uEEOFnXyIDy1DU3CND3ieIa0
+EL12/dsGzzhI0mJEf+oes4aaa4l0znMA7WQ58CUdBWuGoGvUzLkE3TAFqLwKC79h
+DARQQp0VaM01pZQd/Sh/3+V3ijEg3818VtTvKHm5t26ggIRhSSGMhEeqCoG+9EKL
+igzzaBprKzbSuGpj9QKLO4P4vIvgt2RutfqYBNR6sdzKmQYyPCYshfsoQVWo9mmD
+/LLpNoSwwXGgBhI7cprp0CsN5f5/mL2dDSQqEAOl8YitVa4nL44iFrL8d4d8OM7z
+jI///X8MUJs=
+-----END CERTIFICATE-----
+`
+	CASignedECDSACertificateChain                   = ``
+	CASignedECDSACertificateChainPrivateKey         = ``
+	CASignedECDSARootCA                             = ``
+	CASignedNoSkiAkiECDSACertificateChain           = ``
+	CASignedNoSkiAkiECDSACertificateChainPrivateKey = ``
+	CASignedNoSkiAkiECDSARootCA                     = ``
 )
 
-func TestVerifyAndEncodeCertificate(t *testing.T) {
+func TestDecodePrivateKeyPKCS8RSA2048(t *testing.T) {
+
+	privateKey, cleanPemPrivateKey, err := decodeRSAPrivateKey(PrivateKeyPKCS8RSA2048)
+
+	if err != nil {
+		t.Fatalf("unexpected result: " + err.Error())
+	}
+
+	pBlock, remain := pem.Decode([]byte(cleanPemPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("remaining bytes after decode > 0. expected: 0")
+	}
+
+	if privateKey == nil {
+		t.Fatal("RSA private key is nil. expect: not nil")
+	}
+}
+
+func TestDecodePrivateKeyPKCS1RSA2048(t *testing.T) {
+
+	privateKey, cleanPemPrivateKey, err := decodeRSAPrivateKey(PrivateKeyPKCS1RSA2048)
 
+	if err != nil {
+		t.Fatalf("unexpected result: " + err.Error())
+	}
+
+	pBlock, remain := pem.Decode([]byte(cleanPemPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("remaining bytes after decode > 0. expected: 0")
+	}
+
+	if privateKey == nil {
+		t.Fatal("RSA private key is nil")
+	}
+}
+
+func TestDecodePrivateKeyECDSANISTPrime256V1(t *testing.T) {
+
+	privateKey, cleanPemPrivateKey, err := decodeECDSAPrivateKey(PrivateKeyECDSANISTPrime256V1)
+
+	if err != nil {
+		t.Fatalf("unexpected result: " + err.Error())
+	}
+
+	var pemData = []byte(cleanPemPrivateKey)
+	var parsedBlocks = make([]*pem.Block, 0)
+
+	for len(pemData) > 0 {
+		var block *pem.Block = nil
+
+		// Check for at least one END marker
+		if strings.Count(string(pemData), "\n-----END") == 0 {
+			break
+		}
+
+		block, pemData = pem.Decode(pemData)
+
+		if block == nil {
+			t.Fatal("can't decode cleaned ecdsa private-key/param pem block")
+		}
+
+		parsedBlocks = append(parsedBlocks, block)
+	}
+
+	expectedParsedBlocks := 2
+	if len(parsedBlocks) != expectedParsedBlocks {
+		t.Fatalf("incorrect number of parsed pem blocks - expected:%d actual:%d", expectedParsedBlocks, len(parsedBlocks))
+	}
+
+	if privateKey == nil {
+		t.Fatal("ECDSA private key is nil")
+	}
+}
+
+func TestDecodePrivateKeyECDSANISTPrime256V1WithoutParams(t *testing.T) {
+
+	privateKey, cleanPemPrivateKey, err := decodeECDSAPrivateKey(PrivateKeyECDSANISTPrime256V1WithoutParams)
+
+	if err != nil {
+		t.Fatalf("unexpected result: " + err.Error())
+	}
+
+	pBlock, remain := pem.Decode([]byte(cleanPemPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("remaining bytes after decode > 0. expected: 0")
+	}
+
+	if privateKey == nil {
+		t.Fatal("ECDSA private key is nil")
+	}
+}
+
+func TestDecodePrivateKeyECDSANISTSecP384R1(t *testing.T) {
+	privateKey, cleanPemPrivateKey, err := decodeECDSAPrivateKey(PrivateKeyECDSANISTSecP384R1)
+
+	if err != nil {
+		t.Fatalf("unexpected result: " + err.Error())
+	}
+
+	var pemData = []byte(cleanPemPrivateKey)
+	var parsedBlocks = make([]*pem.Block, 0)
+
+	for len(pemData) > 0 {
+		var block *pem.Block = nil
+
+		// Check for at least one END marker
+		if strings.Count(string(pemData), "\n-----END") == 0 {
+			break
+		}
+
+		block, pemData = pem.Decode(pemData)
+
+		if block == nil {
+			t.Fatal("can't decode cleaned ecdsa private-key/param pem block")
+		}
+
+		parsedBlocks = append(parsedBlocks, block)
+	}
+
+	expectedParsedBlocks := 2
+	if len(parsedBlocks) != expectedParsedBlocks {
+		t.Fatalf("incorrect number of parsed pem blocks - expected:%d actual:%d", expectedParsedBlocks, len(parsedBlocks))
+	}
+
+	if privateKey == nil {
+		t.Fatal("ECDSA private key is nil")
+	}
+}
+
+func TestDecodePrivateKeyECDSANISTSecP384R1WithoutParams(t *testing.T) {
+	privateKey, cleanPemPrivateKey, err := decodeECDSAPrivateKey(PrivateKeyECDSANISTSecP384R1WithoutParams)
+
+	if err != nil {
+		t.Fatalf("unexpected result: " + err.Error())
+	}
+
+	pBlock, remain := pem.Decode([]byte(cleanPemPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("remaining bytes after decode > 0. expected: 0")
+	}
+
+	if privateKey == nil {
+		t.Fatal("ECDSA private key is nil")
+	}
+}
+
+func TestDecodeRSAPrivateKeyBadData(t *testing.T) {
+
+	// Expected to fail.
+	privateKey, _, err := decodeRSAPrivateKey(BadKeyData)
+	if err == nil && privateKey != nil {
+		t.Fatal("unexpected result: decoding of bad private key data should have returned an error")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
+	}
+}
+
+func TestDecodeECDSAPrivateKeyBadData(t *testing.T) {
+
+	// Expected to fail.
+	privateKey, _, err := decodeECDSAPrivateKey(BadKeyData)
+	if err == nil && privateKey != nil {
+		t.Fatal("unexpected result: decoding of bad private key data should have returned an error")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
+	}
+}
+
+func TestDecodePrivateKeyRSAEncrypted(t *testing.T) {
+
+	// Expected to fail on decode of encrypted pem rsa private key
+	privateKey, _, err := decodeRSAPrivateKey(PrivateKeyEncryptedRSA2048)
+	if err == nil && privateKey != nil {
+		t.Fatal("unexpected result: decoding of encrypted private key should have returned an error")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
+	}
+}
+
+func TestDecodePrivateKeyECDSAEncrypted(t *testing.T) {
+
+	// Expected to fail on decode of encrypted pem ecdsa private key
+	privateKey, _, err := decodeECDSAPrivateKey(PrivateKeyECDSANISTSecP384R1Encrypted)
+	if err == nil && privateKey != nil {
+		t.Fatal("unexpected result: decoding of encrypted private key should have returned an error")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
+	}
+}
+
+func TestVerifyAndEncodeCertificateBadData(t *testing.T) {
 	// should fail bad base64 data
-	dat, _, err := verifyCertificate(BadData, "")
+	_, _, _, _, err := verifyCertKeyPair(BadCertData, BadKeyData, "", true)
 	if err == nil {
-		t.Errorf("Unexpected result, there should have been a base64 decoding failure")
+		t.Fatalf("unexpected result: there should have been a base64 decoding failure")
 	}
+}
+
+func TestVerifyAndEncodeCertificateSelfSignedCertKeyPairDSA(t *testing.T) {
+	// should fail due to x509 + DSA being unsupported
+	_, _, _, _, err := verifyCertKeyPair(SelfSignedDSACertificate, SelfSignedDSAPrivateKey, "", true)
 
-	// 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")
+		t.Fatalf("unexpected result: the DSA PKI algorithm is unsupported")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
+	}
+}
+
+func TestVerifyAndEncodeCertificateSelfSignedX509v1(t *testing.T) {
+	// should successfully validate as x509v1 must remain supported
+	certChain, certPrivateKey, unknownAuth, _, err := verifyCertKeyPair(SelfSignedX509v1Certificate, SelfSignedX509v1PrivateKey, "", true)
+
+	if err != nil {
+		t.Fatalf("unexpected result: the x509v1 cert/key pair is valid and should have passed validation")
+	}
+
+	if !unknownAuth {
+		t.Fatalf("unexpected result: certificate verification should have detected signature of unknown authority")
+	}
+
+	// Decode the clean Private Key
+	pBlock, remain := pem.Decode([]byte(certPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("unexpected result: can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("unexpected result: remaining bytes after decode > 0. expected: 0")
+	}
+
+	if len(certChain) == 0 {
+		t.Fatal("unexpected: certChain should not be empty")
+	}
+}
+
+func TestVerifyAndEncodeCertificateSelfSignedNoSkiAkiCertKeyPair(t *testing.T) {
+
+	certChain, certPrivateKey, unknownAuth, _, err := verifyCertKeyPair(SelfSignedNOSKIAKIRSACertificate, SelfSignedNOSKIAKIRSAPrivateKey, "", true)
+
+	if err != nil {
+		t.Fatalf("unexpected result: a certificate verification error should have occured")
+	}
+
+	if !unknownAuth {
+		t.Fatalf("unexpected result: certificate verification should have detected unknown authority")
+	}
+
+	// Decode the clean Private Key
+	pBlock, remain := pem.Decode([]byte(certPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("unexpected result: can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("unexpected result: remaining bytes after decode > 0. expected: 0")
+	}
+
+	if len(certChain) == 0 {
+		t.Fatal("unexpected: certChain should not be empty")
 	}
+}
+
+func TestVerifyAndEncodeCertificateSelfSignedCertKeyPair(t *testing.T) {
+
+	certChain, certPrivateKey, unknownAuth, _, err := verifyCertKeyPair(SelfSignedRSACertificate, SelfSignedRSAPrivateKey, "", true)
 
-	// 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)
+		t.Fatalf("unexpected result, a certificate verification error should have occured")
 	}
+
 	if !unknownAuth {
-		t.Errorf("Unexpected result, certificate verification should have detected unknown authority")
+		t.Fatalf("unexpected result, certificate verification should have detected unknown authority")
+	}
+
+	// Decode the clean Private Key
+	pBlock, remain := pem.Decode([]byte(certPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("unexpected result: can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("unexpected result: remaining bytes after decode > 0. expected: 0")
+	}
+
+	if len(certChain) == 0 {
+		t.Fatal("unexpected: certchain should not empty")
 	}
+}
+
+func TestVerifyAndEncodeCertificateSelfSignedCertKeyPairMisMatchedPrivateKey(t *testing.T) {
+
+	// Should fail on cert/private-key mismatch
+	_, _, _, _, err := verifyCertKeyPair(SelfSignedRSACertificate, PrivateKeyPKCS1RSA2048, "", true)
+
+	if err == nil {
+		t.Fatalf("unexpected result: a certificate/key modulus mismatch error should have occurred")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
+	}
+}
+
+func TestVerifyAndEncodeCertificateSelfSignedNoServerAuthExtKeyUsage(t *testing.T) {
+
+	// Should fail due to not having the serverAuth extKeyUsage (x509v3 only)
+	_, _, _, _, err := verifyCertKeyPair(SelfSignedRSACertificateNoServerAuthExtKeyUsage, SelfSignedRSAPrivateKeyNoServerAuthExtKeyUsage, "", true)
+
+	if err == nil {
+		t.Fatalf("unexpected result: x509v3 certificate should have been rejected since it doesn't have the server auth extKeyUsage")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
+	}
+}
+
+func TestVerifyAndEncodeCertificateSelfSignedRSANoKeyEnciphermentKeyUsage(t *testing.T) {
+
+	// Should fail due to not having the keyEncipherment keyUsage (x509v3 only)
+	// keyUsage extension must include keyEncipherment if the PKI algorithm is RSA.
+	_, _, _, _, err := verifyCertKeyPair(SelfSignedRSACertificateNoKeyEnciphermentKeyUsage, SelfSignedRSAPrivateKeyNoKeyEnciphermentKeyUsage, "", true)
+
+	if err == nil {
+		t.Fatalf("unexpected result: x509v3 certificate should have been rejected since it doesn't have the keyEncipherment keyUsage (required for x509v3+RSA certificates)")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
+	}
+}
+
+func TestVerifyAndEncodeCertificateCASignedCertKeyPair(t *testing.T) {
+
+	// Should succeed, but with unknown authority warning.
+	certChain, certPrivateKey, unknownAuth, _, err := verifyCertKeyPair(CASignedRSACertificateChain, CASignedRSACertificateChainPrivateKey, "", true)
 
-	// should pass
-	dat, _, err = verifyCertificate(GoodTLSKeys, rootCA)
 	if err != nil {
-		t.Errorf("Test failure: %s", err)
+		t.Fatalf("unexpected result: " + err.Error())
 	}
 
-	certs := strings.SplitAfter(dat, PemCertEndMarker)
-	length := len(certs) - 1
-	if length != 3 { // rootCA now included in certChain
-		t.Errorf("Test failure: expected 2 certs from verifyCertificate(), got: %d ", length)
+	if !unknownAuth {
+		t.Fatalf("unexpected result, certificate verification should have detected unknown authority")
+	}
+
+	// Decode the clean Private Key
+	pBlock, remain := pem.Decode([]byte(certPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("unexpected result: can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("unexpected result: remaining bytes after decode > 0. expected: 0")
+	}
+
+	if len(certChain) == 0 {
+		t.Fatal("unexpected: certchain should not empty")
+	}
+}
+
+func TestVerifyAndEncodeCertificateCASignedCertKeyPairWithRootCA(t *testing.T) {
+
+	// should succeed and be fully validated.
+	certChain, certPrivateKey, unknownAuth, _, err := verifyCertKeyPair(CASignedRSACertificateChain, CASignedRSACertificateChainPrivateKey, CASignedRSARootCA, true)
+
+	if err != nil {
+		t.Fatalf("unexpected result: " + err.Error())
+	}
+
+	if unknownAuth {
+		t.Fatalf("unexpected result: warning for unknown authority even though rootCA is in certChain")
+	}
+
+	// Decode the clean Private Key
+	pBlock, remain := pem.Decode([]byte(certPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("unexpected result: can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("unexpected result: remaining bytes after decode > 0. expected: 0")
+	}
+
+	if len(certChain) == 0 {
+		t.Fatal("unexpected: certchain should not empty")
+	}
+}
+
+func TestVerifyAndEncodeCertificateCASignedNoSkiAkiCertKeyPair(t *testing.T) {
+
+	// Should succeed, but with unknown authority warning.
+	certChain, certPrivateKey, unknownAuth, _, err := verifyCertKeyPair(CASignedNoSkiAkiRSACertificateChain, CASignedNoSkiAkiRSAPrivateKey, "", true)
+
+	if err != nil {
+		t.Fatalf("unexpected result: " + err.Error())
+	}
+
+	if !unknownAuth {
+		t.Fatalf("unexpected result, certificate verification should have detected unknown authority")
+	}
+
+	// Decode the clean Private Key
+	pBlock, remain := pem.Decode([]byte(certPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("unexpected result: can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("unexpected result: remaining bytes after decode > 0. expected: 0")
+	}
+
+	if len(certChain) == 0 {
+		t.Fatal("unexpected: certchain should not empty")
+	}
+}
+
+func TestVerifyAndEncodeCertificateCASignedNoSkiAkiCertKeyPairWithRootCA(t *testing.T) {
+
+	// should succeed and be fully validated despite not having subject/authority key identifier(s).
+	certChain, certPrivateKey, unknownAuth, _, err := verifyCertKeyPair(CASignedNoSkiAkiRSACertificateChain, CASignedNoSkiAkiRSAPrivateKey, CASignedNoSkiAkiRSARootCA, true)
+
+	if err != nil {
+		t.Fatalf("unexpected result: " + err.Error())
+	}
+
+	if unknownAuth {
+		t.Fatalf("unexpected result: warning for unknown authority even though rootCA is in certChain")
+	}
+
+	// Decode the clean Private Key
+	pBlock, remain := pem.Decode([]byte(certPrivateKey))
+
+	if pBlock == nil {
+		t.Fatal("unexpected result: can't decode cleaned private key pem block")
+	} else if len(remain) > 0 {
+		t.Fatal("unexpected result: remaining bytes after decode > 0. expected: 0")
+	}
+
+	if len(certChain) == 0 {
+		t.Fatal("unexpected: cert chain should not empty")
+	}
+}
+
+func TestVerifyAndEncodeCertificateECDSASelfSignedCertificateKeyPairWithoutDigitalSignatureKeyUsage(t *testing.T) {
+	// Should fail due to unsupported private/public key algorithm
+	// keyUsage must contain the digitalSignature usage if a DSA based PKI algorithm is indicated (unlike RSA).
+	_, _, _, _, err := verifyCertKeyPair(SelfSignedECDSACertificateNoDigitalSignatureKeyUsage, SelfSignedECDSAPrivateKeyNoDigitalSignatureKeyUsage, "", true)
+
+	if err == nil {
+		t.Fatalf("unexpected result: x509v3 certificate should have been rejected since it doesn't have the digitalSignature keyUsage (required for x509v3+ECDSA certificates)")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
+	}
+}
+
+func TestVerifyAndEncodeCertificateECDSASelfSignedCertificateKeyPair(t *testing.T) {
+	// Should be successful as the certificate and key are valid with proper keyUsage/extendedKeyUsage.
+	_, _, _, _, err := verifyCertKeyPair(SelfSignedECDSACertificate, SelfSignedECDSAPrivateKey, "", true)
+
+	if err != nil {
+		t.Fatalf("unexpected result - valid ECDSA cert/key pair should have been validated: " + err.Error())
+	}
+}
+
+func TestVerifyAndEncodeCertificateECDSASelfSignedCertificateKeyPairECDisabled(t *testing.T) {
+	// Should be rejected as allowEC flag has been set to false
+	_, _, _, _, err := verifyCertKeyPair(SelfSignedECDSACertificate, SelfSignedECDSAPrivateKey, "", false)
+
+	if err == nil {
+		t.Fatalf("unexpected result - ECDSA cert/key pair should have been rejected due to allowEC being false")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
+	}
+}
+
+func TestVerifyAndEncodeCertificateECDSASelfSignedCertificateKeyPairWithoutParams(t *testing.T) {
+	// Test result should be successful as the certificate and key are valid with proper keyUsage/extendedKeyUsage.
+	_, _, _, _, err := verifyCertKeyPair(SelfSignedECDSACertificate, SelfSignedECDSAPrivateKeyWithoutParams, "", true)
+
+	if err != nil {
+		t.Fatalf("unexpected result - valid ECDSA cert/key pair should have been validated: " + err.Error())
+	}
+}
+
+func TestVerifyAndEncodeCertificateECDSASelfSignedCertificateKeyPairMisMatchedPrivateKey(t *testing.T) {
+	// Should fail due to mismatched ECDSA cert/private key pair
+	_, _, _, _, err := verifyCertKeyPair(SelfSignedECDSACertificate, PrivateKeyECDSANISTPrime256V1, "", true)
+
+	if err == nil {
+		t.Fatalf("unexpected Result: Mismatched ECDSA cert/key pair should have failed verification")
+	} else {
+		t.Logf("expected error message: %s", err.Error())
 	}
 }