2015-06-05 18:03:57 +00:00
package pki
import (
"crypto/x509"
"encoding/pem"
"fmt"
"math"
"math/rand"
"os"
"testing"
"time"
"github.com/fatih/structs"
2015-06-17 16:43:36 +00:00
"github.com/hashicorp/vault/helper/certutil"
2015-06-05 18:03:57 +00:00
"github.com/hashicorp/vault/logical"
logicaltest "github.com/hashicorp/vault/logical/testing"
"github.com/mitchellh/mapstructure"
)
var (
stepCount = 0
)
2015-06-19 16:48:18 +00:00
// Performs basic tests on CA functionality
2015-06-05 18:03:57 +00:00
func TestBackend_basic ( t * testing . T ) {
2015-09-01 12:56:31 +00:00
defaultLeaseTTLVal := time . Hour * 24
maxLeaseTTLVal := time . Hour * 24 * 30
2015-08-27 19:24:37 +00:00
b , err := Factory ( & logical . BackendConfig {
Logger : nil ,
System : & logical . StaticSystemView {
2015-09-01 22:29:30 +00:00
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
2015-08-27 19:24:37 +00:00
} ,
} )
if err != nil {
t . Fatalf ( "Unable to create backend: %s" , err )
}
2015-06-05 18:03:57 +00:00
testCase := logicaltest . TestCase {
Backend : b ,
Steps : [ ] logicaltest . TestStep { } ,
}
stepCount += len ( testCase . Steps )
testCase . Steps = append ( testCase . Steps , generateCASteps ( t ) ... )
logicaltest . Test ( t , testCase )
}
2015-06-19 16:48:18 +00:00
// Generates and tests steps that walk through the various possibilities
// of role flags to ensure that they are properly restricted
2015-06-05 18:03:57 +00:00
func TestBackend_roles ( t * testing . T ) {
2015-09-01 12:56:31 +00:00
defaultLeaseTTLVal := time . Hour * 24
maxLeaseTTLVal := time . Hour * 24 * 30
2015-08-27 19:24:37 +00:00
b , err := Factory ( & logical . BackendConfig {
Logger : nil ,
System : & logical . StaticSystemView {
2015-09-01 22:29:30 +00:00
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
2015-08-27 19:24:37 +00:00
} ,
} )
if err != nil {
t . Fatalf ( "Unable to create backend: %s" , err )
}
2015-06-05 18:03:57 +00:00
testCase := logicaltest . TestCase {
Backend : b ,
Steps : [ ] logicaltest . TestStep { } ,
}
testCase . Steps = append ( testCase . Steps , generateCASteps ( t ) ... )
testCase . Steps = append ( testCase . Steps , generateRoleSteps ( t ) ... )
if len ( os . Getenv ( "VAULT_VERBOSE_PKITESTS" ) ) > 0 {
for i , v := range testCase . Steps {
fmt . Printf ( "Step %d:\n%+v\n\n" , i + stepCount , v )
}
}
stepCount += len ( testCase . Steps )
logicaltest . Test ( t , testCase )
}
2015-06-19 16:48:18 +00:00
// Performs some validity checking on the returned bundles
func checkCertsAndPrivateKey ( keyType string , usage certUsage , validity time . Duration , certBundle * certutil . CertBundle ) ( * certutil . ParsedCertBundle , error ) {
parsedCertBundle , err := certBundle . ToParsedCertBundle ( )
if err != nil {
return nil , fmt . Errorf ( "Error parsing cert bundle: %s" , err )
}
switch {
case parsedCertBundle . Certificate == nil :
return nil , fmt . Errorf ( "Did not find a certificate in the cert bundle" )
case parsedCertBundle . IssuingCA == nil :
return nil , fmt . Errorf ( "Did not find a CA in the cert bundle" )
case parsedCertBundle . PrivateKey == nil :
return nil , fmt . Errorf ( "Did not find a private key in the cert bundle" )
case parsedCertBundle . PrivateKeyType == certutil . UnknownPrivateKey :
return nil , fmt . Errorf ( "Could not figure out type of private key" )
}
switch {
case parsedCertBundle . PrivateKeyType == certutil . RSAPrivateKey && keyType != "rsa" :
fallthrough
case parsedCertBundle . PrivateKeyType == certutil . ECPrivateKey && keyType != "ec" :
return nil , fmt . Errorf ( "Given key type does not match type found in bundle" )
}
cert := parsedCertBundle . Certificate
// There should only be one usage type, because only one is requested
// in the tests
if len ( cert . ExtKeyUsage ) != 1 {
2015-10-02 15:55:30 +00:00
return nil , fmt . Errorf ( "Got wrong size key usage in generated cert; values are %#v" , cert . ExtKeyUsage )
2015-06-19 16:48:18 +00:00
}
switch usage {
2015-10-02 15:55:30 +00:00
case emailProtectionUsage :
if cert . ExtKeyUsage [ 0 ] != x509 . ExtKeyUsageEmailProtection {
return nil , fmt . Errorf ( "Bad key usage" )
}
2015-06-19 16:48:18 +00:00
case serverUsage :
if cert . ExtKeyUsage [ 0 ] != x509 . ExtKeyUsageServerAuth {
return nil , fmt . Errorf ( "Bad key usage" )
}
case clientUsage :
if cert . ExtKeyUsage [ 0 ] != x509 . ExtKeyUsageClientAuth {
return nil , fmt . Errorf ( "Bad key usage" )
}
case codeSigningUsage :
if cert . ExtKeyUsage [ 0 ] != x509 . ExtKeyUsageCodeSigning {
return nil , fmt . Errorf ( "Bad key usage" )
}
}
if math . Abs ( float64 ( time . Now ( ) . Unix ( ) - cert . NotBefore . Unix ( ) ) ) > 10 {
return nil , fmt . Errorf ( "Validity period starts out of range" )
}
if math . Abs ( float64 ( time . Now ( ) . Add ( validity ) . Unix ( ) - cert . NotAfter . Unix ( ) ) ) > 10 {
2015-08-27 19:24:37 +00:00
return nil , fmt . Errorf ( "Validity period of %d too large vs max of 10" , cert . NotAfter . Unix ( ) )
2015-06-19 16:48:18 +00:00
}
return parsedCertBundle , nil
}
// Generates steps to test out CA configuration -- certificates + CRL expiry,
// and ensure that the certificates are readable after storing them
2015-06-05 18:03:57 +00:00
func generateCASteps ( t * testing . T ) [ ] logicaltest . TestStep {
ret := [ ] logicaltest . TestStep {
logicaltest . TestStep {
Operation : logical . WriteOperation ,
2015-08-29 13:03:02 +00:00
Path : "config/ca/set" ,
2015-06-05 18:03:57 +00:00
Data : map [ string ] interface { } {
"pem_bundle" : caKey + caCert ,
} ,
} ,
2015-06-19 16:48:18 +00:00
logicaltest . TestStep {
Operation : logical . WriteOperation ,
Path : "config/crl" ,
Data : map [ string ] interface { } {
"expiry" : "16h" ,
} ,
} ,
2015-06-05 18:03:57 +00:00
// Ensure we can fetch it back via unauthenticated means, in various formats
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "cert/ca" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "certificate" ] . ( string ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , resp . Data [ "certificate" ] . ( string ) , caCert )
}
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "ca/pem" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
rawBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
if string ( rawBytes ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , string ( rawBytes ) , caCert )
}
if resp . Data [ "http_content_type" ] . ( string ) != "application/pkix-cert" {
return fmt . Errorf ( "Expected application/pkix-cert as content-type, but got %s" , resp . Data [ "http_content_type" ] . ( string ) )
}
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "ca" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
rawBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
pemBytes := pem . EncodeToMemory ( & pem . Block {
Type : "CERTIFICATE" ,
Bytes : rawBytes ,
} )
if string ( pemBytes ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , string ( pemBytes ) , caCert )
}
if resp . Data [ "http_content_type" ] . ( string ) != "application/pkix-cert" {
return fmt . Errorf ( "Expected application/pkix-cert as content-type, but got %s" , resp . Data [ "http_content_type" ] . ( string ) )
}
return nil
} ,
} ,
2015-06-19 16:48:18 +00:00
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "config/crl" ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "expiry" ] . ( string ) != "16h" {
return fmt . Errorf ( "CRL lifetimes do not match (got %s)" , resp . Data [ "expiry" ] . ( string ) )
}
return nil
} ,
} ,
2015-08-29 13:03:02 +00:00
// Now test uploading when the private key is already stored, such
// as when uploading a CA signed as the result of a generated CSR
logicaltest . TestStep {
Operation : logical . WriteOperation ,
Path : "config/ca/set" ,
Data : map [ string ] interface { } {
"pem_bundle" : caCert ,
} ,
} ,
// Ensure we can fetch it back via unauthenticated means, in various formats
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "cert/ca" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "certificate" ] . ( string ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , resp . Data [ "certificate" ] . ( string ) , caCert )
}
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "ca/pem" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
rawBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
if string ( rawBytes ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , string ( rawBytes ) , caCert )
}
if resp . Data [ "http_content_type" ] . ( string ) != "application/pkix-cert" {
return fmt . Errorf ( "Expected application/pkix-cert as content-type, but got %s" , resp . Data [ "http_content_type" ] . ( string ) )
}
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "ca" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
rawBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
pemBytes := pem . EncodeToMemory ( & pem . Block {
Type : "CERTIFICATE" ,
Bytes : rawBytes ,
} )
if string ( pemBytes ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , string ( pemBytes ) , caCert )
}
if resp . Data [ "http_content_type" ] . ( string ) != "application/pkix-cert" {
return fmt . Errorf ( "Expected application/pkix-cert as content-type, but got %s" , resp . Data [ "http_content_type" ] . ( string ) )
}
return nil
} ,
} ,
2015-06-05 18:03:57 +00:00
}
return ret
}
2015-06-19 16:48:18 +00:00
// Generates steps to test out various role permutations
2015-06-05 18:03:57 +00:00
func generateRoleSteps ( t * testing . T ) [ ] logicaltest . TestStep {
roleVals := roleEntry {
2015-08-27 19:24:37 +00:00
MaxTTL : "12h" ,
2015-06-05 18:03:57 +00:00
}
2015-06-15 17:33:23 +00:00
issueVals := certutil . IssueData { }
2015-06-05 18:03:57 +00:00
ret := [ ] logicaltest . TestStep { }
roleTestStep := logicaltest . TestStep {
Operation : logical . WriteOperation ,
Path : "roles/test" ,
}
issueTestStep := logicaltest . TestStep {
Operation : logical . WriteOperation ,
Path : "issue/test" ,
}
genericErrorOkCheck := func ( resp * logical . Response ) error {
if resp . IsError ( ) {
return nil
}
return fmt . Errorf ( "Expected an error, but did not seem to get one" )
}
2015-06-19 16:48:18 +00:00
// Adds tests with the currently configured issue/role information
2015-06-05 18:03:57 +00:00
addTests := func ( testCheck logicaltest . TestCheckFunc ) {
//fmt.Printf("role vals: %#v\n", roleVals)
//fmt.Printf("issue vals: %#v\n", issueTestStep)
roleTestStep . Data = structs . New ( roleVals ) . Map ( )
ret = append ( ret , roleTestStep )
issueTestStep . Data = structs . New ( issueVals ) . Map ( )
switch {
case issueTestStep . ErrorOk :
issueTestStep . Check = genericErrorOkCheck
case testCheck != nil :
issueTestStep . Check = testCheck
default :
issueTestStep . Check = nil
}
ret = append ( ret , issueTestStep )
}
2015-06-19 16:48:18 +00:00
// Returns a TestCheckFunc that performs various validity checks on the
// returned certificate information, mostly within checkCertsAndPrivateKey
2015-06-05 18:03:57 +00:00
getCnCheck := func ( name , keyType string , usage certUsage , validity time . Duration ) logicaltest . TestCheckFunc {
2015-06-15 17:33:23 +00:00
var certBundle certutil . CertBundle
2015-06-05 18:03:57 +00:00
return func ( resp * logical . Response ) error {
2015-06-15 17:33:23 +00:00
err := mapstructure . Decode ( resp . Data , & certBundle )
2015-06-05 18:03:57 +00:00
if err != nil {
return err
}
2015-06-19 16:48:18 +00:00
parsedCertBundle , err := checkCertsAndPrivateKey ( keyType , usage , validity , & certBundle )
2015-06-05 18:03:57 +00:00
if err != nil {
return fmt . Errorf ( "Error checking generated certificate: %s" , err )
}
2015-06-19 16:48:18 +00:00
cert := parsedCertBundle . Certificate
2015-06-05 18:03:57 +00:00
if cert . Subject . CommonName != name {
return fmt . Errorf ( "Error: returned certificate has CN of %s but %s was requested" , cert . Subject . CommonName , name )
}
2015-10-02 18:27:30 +00:00
if len ( cert . DNSNames ) + len ( cert . EmailAddresses ) != 1 {
return fmt . Errorf ( "Error: found more than one DNS/Email SAN but only one was requested, cert.DNSNames = %#v, cert.EmailAddresses = %#v" , cert . DNSNames , cert . EmailAddresses )
2015-06-05 18:03:57 +00:00
}
2015-10-02 18:27:30 +00:00
var retName string
if len ( cert . DNSNames ) > 0 {
retName = cert . DNSNames [ 0 ]
}
if len ( cert . EmailAddresses ) > 0 {
retName = cert . EmailAddresses [ 0 ]
}
if retName != name {
return fmt . Errorf ( "Error: returned certificate has a DNS SAN of %s but %s was requested" , retName , name )
2015-06-05 18:03:57 +00:00
}
return nil
}
}
2015-06-19 16:48:18 +00:00
// Common names to test with the various role flags toggled
2015-06-05 18:03:57 +00:00
var commonNames struct {
2015-10-02 16:22:02 +00:00
Localhost bool ` structs:"localhost" `
BaseDomain bool ` structs:"example.com" `
SubDomain bool ` structs:"foo.example.com" `
Wildcard bool ` structs:"*.example.com" `
SubSubdomain bool ` structs:"foo.bar.example.com" `
SubSubdomainWildcard bool ` structs:"*.bar.example.com" `
NonHostname bool ` structs:"daɪ ˈ ɛrɨsɨs" `
AnyHost bool ` structs:"porkslap.beer" `
2015-06-05 18:03:57 +00:00
}
2015-06-19 16:48:18 +00:00
// Adds a series of tests based on the current selection of
// allowed common names; contains some (seeded) randomness
//
// This allows for a variety of common names to be tested in various
// combinations with allowed toggles of the role
2015-06-05 18:03:57 +00:00
addCnTests := func ( ) {
cnMap := structs . New ( commonNames ) . Map ( )
// For the number of tests being run, this is known to hit all
// of the various values below
mathRand := rand . New ( rand . NewSource ( 1 ) )
for name , allowedInt := range cnMap {
roleVals . KeyType = "rsa"
roleVals . KeyBits = 2048
if mathRand . Int ( ) % 2 == 1 {
roleVals . KeyType = "ec"
roleVals . KeyBits = 224
}
roleVals . ServerFlag = false
roleVals . ClientFlag = false
roleVals . CodeSigningFlag = false
2015-10-02 15:55:30 +00:00
roleVals . EmailProtectionFlag = false
2015-06-05 18:03:57 +00:00
var usage certUsage
i := mathRand . Int ( )
switch {
2015-10-02 15:55:30 +00:00
case i % 5 == 0 :
usage = emailProtectionUsage
roleVals . EmailProtectionFlag = true
2015-06-05 18:03:57 +00:00
case i % 3 == 0 :
usage = serverUsage
roleVals . ServerFlag = true
case i % 2 == 0 :
usage = clientUsage
roleVals . ClientFlag = true
default :
usage = codeSigningUsage
roleVals . CodeSigningFlag = true
}
allowed := allowedInt . ( bool )
issueVals . CommonName = name
2015-10-02 18:27:30 +00:00
if roleVals . EmailProtectionFlag {
issueVals . CommonName = "user@" + issueVals . CommonName
}
2015-06-05 18:03:57 +00:00
if allowed {
issueTestStep . ErrorOk = false
} else {
issueTestStep . ErrorOk = true
}
2015-08-27 19:24:37 +00:00
validity , _ := time . ParseDuration ( roleVals . MaxTTL )
2015-10-02 18:27:30 +00:00
addTests ( getCnCheck ( issueVals . CommonName , roleVals . KeyType , usage , validity ) )
2015-06-05 18:03:57 +00:00
}
}
// Common Name tests
{
// common_name not provided
issueVals . CommonName = ""
issueTestStep . ErrorOk = true
addTests ( nil )
// Nothing is allowed
addCnTests ( )
roleVals . AllowLocalhost = true
commonNames . Localhost = true
addCnTests ( )
roleVals . AllowedBaseDomain = "foobar.com"
addCnTests ( )
roleVals . AllowedBaseDomain = "example.com"
2015-10-02 18:27:30 +00:00
roleVals . AllowSubdomains = true
2015-10-02 16:22:02 +00:00
commonNames . SubDomain = true
2015-06-05 18:03:57 +00:00
commonNames . Wildcard = true
2015-10-02 18:27:30 +00:00
commonNames . SubSubdomain = true
commonNames . SubSubdomainWildcard = true
2015-06-05 18:03:57 +00:00
addCnTests ( )
2015-10-02 16:22:02 +00:00
roleVals . AllowBaseDomain = true
commonNames . BaseDomain = true
addCnTests ( )
2015-06-05 18:03:57 +00:00
roleVals . AllowAnyName = true
2015-08-20 21:33:37 +00:00
roleVals . EnforceHostnames = true
2015-06-05 18:03:57 +00:00
commonNames . AnyHost = true
addCnTests ( )
2015-08-20 21:33:37 +00:00
roleVals . EnforceHostnames = false
commonNames . NonHostname = true
addCnTests ( )
2015-06-05 18:03:57 +00:00
}
// IP SAN tests
{
issueVals . IPSANs = "127.0.0.1,::1"
issueTestStep . ErrorOk = true
addTests ( nil )
roleVals . AllowIPSANs = true
issueTestStep . ErrorOk = false
addTests ( nil )
issueVals . IPSANs = "foobar"
issueTestStep . ErrorOk = true
addTests ( nil )
issueTestStep . ErrorOk = false
issueVals . IPSANs = ""
}
// Lease tests
{
roleTestStep . ErrorOk = true
roleVals . Lease = ""
2015-08-27 19:24:37 +00:00
roleVals . MaxTTL = ""
2015-06-05 18:03:57 +00:00
addTests ( nil )
roleVals . Lease = "12h"
2015-08-27 19:24:37 +00:00
roleVals . MaxTTL = "6h"
2015-06-05 18:03:57 +00:00
addTests ( nil )
roleTestStep . ErrorOk = false
}
return ret
}
const (
caKey string = ` -- -- - BEGIN RSA PRIVATE KEY -- -- -
MIIEpAIBAAKCAQEA1eKB2nFbRqTFs7KyZjbzB5VRCBbnLZfEXVP1c3bHe + YGjlfl
34 cy52dmancUzOf1 / Jfo + VglocjTLVy5wHSGJwQYs8b6pEuuvAVo / 6 wUL5Z7ZlQD
R4kDe5Q + xgoRT6Bi / Bs57E + fNYgyUq / YAUY5WLuC + ZliCbJkLnb15ItuP1yVUTDX
TYORRE3qJS5RRol8D3QvteG9LyPEc7C + jsm5iBCagyxluzU0dnEOib5q7xwZncoM
bQz + rZH3QnwOij41FOGRPazrD5Mv6xLBkFnE5VAJ + GIgvd4bpOwvYMuofvF4PS7S
FzxkGssMLlICap6PFpKz86DpAoDxPuoZeOhU4QIDAQABAoIBAQCp6VIdFdZcDYPd
WIVuvBJfINiJo6AtURa2yX8BJggdPkRRCjTcWUwwFq1 + wHDuwwtgidGTW9oxZxeU
Psh1wlvcXN2 + 28 C7ikAar / WUvsAeed44EV + 1 kXwJzV / 89 XyBFDnuazadqzcgUL0h
gP4JLR9bhULsRFRkvanmW6zFzZpcjBzi / UoFuWkFRRqZ0euM2Lpz8L75PFfW9s9M
kNglZpcV6ZmvR9c1JkEMUs / mrB8ZgCd1uvmcVosQ + u7sE8Yk / xAurHXuNJQlGXx4
azrLW0XY1CLO2Tm4l4MwPjmhH0WytXNjOSKycBCXVnBIfZsI128DsP5YyA / fW9qA
BAqFSzABAoGBAPcBNk9sf3cnZ5w6qwlE2ysDwGIGR + I1fb09YjRI6vjwwdWZgGR0
EE4UB1Pp + KIehXaTJHcEgvBBErM2NLS4qKzh25O30C2EwK6o //3jEAribuYutBhJ
ihu1qKzqcPbKClG + 34 kjX6nmtux2wlYM05f5v3ALki5Is7W / RrfceBuBAoGBAN2s
hdt4TcgIcZymPG2931qCBGF3E8AaA8bUl9TKaZHuFikOMFKA / KM5O5mznPGnQP2d
kXYKXuqdYhVLwp32FTbIbozGZZ8XliO5oS7J3vIID + sLWQhrvyFO7d0lpSjv41HH
yJ2DrykHRg8hxsbh2D4By7olBx6Q2m + B8lPzHmlhAoGACHUeKvIIG0haH9tSZ + rX
pk1mlPSqGXDDcWtcpXWptgRoXqv23Xmr5UCCT7k / Li3lW / 4 FzZ117kwMG97LRzTb
ca / 6 GMC + fBCDmHdo7ISN1BGUwoTu3bYG6JP7xo / wdkLMv6fNd6CicerYcJhQZynh
RN7kUy3SP4t1u89k2H7QDgECgYBpU0bKr8 + tQq3Qs3 + 02 OmeFHbGZJDCztmKiIqX
tZERoGFxIme9W8IuP8xczGW + wCx2FH7 / 6 g + NRDhNTBDtgvYzcGpugvnX7JoO4W1 /
ULWYpFID6QFlqeRHjDwivndKCykkO1vL07zPLsCQAglzh + 16 ENpe2KcYU9Ul9EVS
tAp4IQKBgQDrb / NpiVx7NI6PyTCm6ctuUAYm3ihAiQNV4Bmr0liPDp9PozbqkhcF
udNtivO4LlRb / PJ + DK6afDyH8aJQdDqe3NpDvyrmKiMSYOY3iVFvan4tbIiofxdQ
flwiZUzox814fzXbxheO9Cs6pXz7PUBVU4fN0Y / hXJCfRO4Ns9152A ==
-- -- - END RSA PRIVATE KEY -- -- -
`
caCert string = ` -- -- - BEGIN CERTIFICATE -- -- -
MIIDUTCCAjmgAwIBAgIJAKM + z4MSfw2mMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV
BAMMEFZhdWx0IFRlc3RpbmcgQ0EwHhcNMTUwNjAxMjA1MTUzWhcNMjUwNTI5MjA1
MTUzWjAbMRkwFwYDVQQDDBBWYXVsdCBUZXN0aW5nIENBMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEA1eKB2nFbRqTFs7KyZjbzB5VRCBbnLZfEXVP1c3bH
e + YGjlfl34cy52dmancUzOf1 / Jfo + VglocjTLVy5wHSGJwQYs8b6pEuuvAVo / 6 wU
L5Z7ZlQDR4kDe5Q + xgoRT6Bi / Bs57E + fNYgyUq / YAUY5WLuC + ZliCbJkLnb15Itu
P1yVUTDXTYORRE3qJS5RRol8D3QvteG9LyPEc7C + jsm5iBCagyxluzU0dnEOib5q
7 xwZncoMbQz + rZH3QnwOij41FOGRPazrD5Mv6xLBkFnE5VAJ + GIgvd4bpOwvYMuo
fvF4PS7SFzxkGssMLlICap6PFpKz86DpAoDxPuoZeOhU4QIDAQABo4GXMIGUMB0G
A1UdDgQWBBTknN5eFxxo5aTlfq + G4ZXs3AsxWTAfBgNVHSMEGDAWgBTknN5eFxxo
5 aTlfq + G4ZXs3AsxWTAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vbG9jYWxob3N0
OjgyMDAvdjEvcGtpL2NybDAPBgNVHRMBAf8EBTADAQH / MA4GA1UdDwEB / wQEAwIB
BjANBgkqhkiG9w0BAQsFAAOCAQEAsINcA4PZm + OyldgNrwRVgxoSrhV1I9zszhc9
VV340ZWlpTTxFKVb / K5Hg + jMF9tv70X1HwlYdlutE6KdrsA3gks5zanh4 / 3 zlrYk
ABNBmSD6SSU2HKX1bFCBAAS3YHONE5o1K5tzwLsMl5uilNf + Wid3NjFnQ4KfuYI5
loN / opnM6 + a / O3Zua8RAuMMAv9wyqwn88aVuLvVzDNSMe5qC5kkuLGmRkNgY06rI
S / fXIHIOldeQxgYCqhdVmcDWJ1PtVaDfBsKVpRg1GRU8LUGw2E4AY + twd + J2FBfa
G / 7 g4koczXLoUM3OQXd5Aq2cs4SS1vODrYmgbioFsQ3eDHd1fg ==
-- -- - END CERTIFICATE -- -- -
`
)