| // Copyright 2017 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build boringcrypto |
| |
| package tls |
| |
| import ( |
| "crypto/ecdsa" |
| "crypto/elliptic" |
| "crypto/internal/boring/fipstls" |
| "crypto/rand" |
| "crypto/rsa" |
| "crypto/x509" |
| "crypto/x509/pkix" |
| "encoding/pem" |
| "fmt" |
| "internal/obscuretestdata" |
| "math/big" |
| "net" |
| "runtime" |
| "strings" |
| "testing" |
| "time" |
| ) |
| |
| func allCipherSuitesIncludingTLS13() []uint16 { |
| s := allCipherSuites() |
| for _, suite := range cipherSuitesTLS13 { |
| s = append(s, suite.id) |
| } |
| return s |
| } |
| |
| func isTLS13CipherSuite(id uint16) bool { |
| for _, suite := range cipherSuitesTLS13 { |
| if id == suite.id { |
| return true |
| } |
| } |
| return false |
| } |
| |
| func generateKeyShare(group CurveID) keyShare { |
| key, err := generateECDHEKey(rand.Reader, group) |
| if err != nil { |
| panic(err) |
| } |
| return keyShare{group: group, data: key.PublicKey().Bytes()} |
| } |
| |
| func TestBoringServerProtocolVersion(t *testing.T) { |
| test := func(name string, v uint16, msg string) { |
| t.Run(name, func(t *testing.T) { |
| serverConfig := testConfig.Clone() |
| serverConfig.MinVersion = VersionSSL30 |
| clientHello := &clientHelloMsg{ |
| vers: v, |
| random: make([]byte, 32), |
| cipherSuites: allCipherSuitesIncludingTLS13(), |
| compressionMethods: []uint8{compressionNone}, |
| supportedCurves: defaultCurvePreferences, |
| keyShares: []keyShare{generateKeyShare(CurveP256)}, |
| supportedPoints: []uint8{pointFormatUncompressed}, |
| supportedVersions: []uint16{v}, |
| } |
| testClientHelloFailure(t, serverConfig, clientHello, msg) |
| }) |
| } |
| |
| test("VersionTLS10", VersionTLS10, "") |
| test("VersionTLS11", VersionTLS11, "") |
| test("VersionTLS12", VersionTLS12, "") |
| test("VersionTLS13", VersionTLS13, "") |
| |
| fipstls.Force() |
| defer fipstls.Abandon() |
| test("VersionSSL30/fipstls", VersionSSL30, "client offered only unsupported versions") |
| test("VersionTLS10/fipstls", VersionTLS10, "client offered only unsupported versions") |
| test("VersionTLS11/fipstls", VersionTLS11, "client offered only unsupported versions") |
| test("VersionTLS12/fipstls", VersionTLS12, "") |
| test("VersionTLS13/fipstls", VersionTLS13, "") |
| } |
| |
| func isBoringVersion(v uint16) bool { |
| return v == VersionTLS12 || v == VersionTLS13 |
| } |
| |
| func isBoringCipherSuite(id uint16) bool { |
| switch id { |
| case TLS_AES_128_GCM_SHA256, |
| TLS_AES_256_GCM_SHA384, |
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, |
| TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
| TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: |
| return true |
| } |
| return false |
| } |
| |
| func isBoringCurve(id CurveID) bool { |
| switch id { |
| case CurveP256, CurveP384: |
| return true |
| } |
| return false |
| } |
| |
| func isECDSA(id uint16) bool { |
| for _, suite := range cipherSuites { |
| if suite.id == id { |
| return suite.flags&suiteECSign == suiteECSign |
| } |
| } |
| return false // TLS 1.3 cipher suites are not tied to the signature algorithm. |
| } |
| |
| func isBoringSignatureScheme(alg SignatureScheme) bool { |
| switch alg { |
| default: |
| return false |
| case PKCS1WithSHA256, |
| ECDSAWithP256AndSHA256, |
| PKCS1WithSHA384, |
| ECDSAWithP384AndSHA384, |
| PKCS1WithSHA512, |
| PSSWithSHA256, |
| PSSWithSHA384, |
| PSSWithSHA512: |
| // ok |
| } |
| return true |
| } |
| |
| func TestBoringServerCipherSuites(t *testing.T) { |
| serverConfig := testConfig.Clone() |
| serverConfig.Certificates = make([]Certificate, 1) |
| |
| for _, id := range allCipherSuitesIncludingTLS13() { |
| if isECDSA(id) { |
| serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} |
| serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey |
| } else { |
| serverConfig.Certificates[0].Certificate = [][]byte{testRSACertificate} |
| serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey |
| } |
| serverConfig.BuildNameToCertificate() |
| t.Run(fmt.Sprintf("suite=%s", CipherSuiteName(id)), func(t *testing.T) { |
| clientHello := &clientHelloMsg{ |
| vers: VersionTLS12, |
| random: make([]byte, 32), |
| cipherSuites: []uint16{id}, |
| compressionMethods: []uint8{compressionNone}, |
| supportedCurves: defaultCurvePreferences, |
| keyShares: []keyShare{generateKeyShare(CurveP256)}, |
| supportedPoints: []uint8{pointFormatUncompressed}, |
| supportedVersions: []uint16{VersionTLS12}, |
| } |
| if isTLS13CipherSuite(id) { |
| clientHello.supportedVersions = []uint16{VersionTLS13} |
| } |
| |
| testClientHello(t, serverConfig, clientHello) |
| t.Run("fipstls", func(t *testing.T) { |
| fipstls.Force() |
| defer fipstls.Abandon() |
| msg := "" |
| if !isBoringCipherSuite(id) { |
| msg = "no cipher suite supported by both client and server" |
| } |
| testClientHelloFailure(t, serverConfig, clientHello, msg) |
| }) |
| }) |
| } |
| } |
| |
| func TestBoringServerCurves(t *testing.T) { |
| serverConfig := testConfig.Clone() |
| serverConfig.Certificates = make([]Certificate, 1) |
| serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} |
| serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey |
| serverConfig.BuildNameToCertificate() |
| |
| for _, curveid := range defaultCurvePreferences { |
| t.Run(fmt.Sprintf("curve=%d", curveid), func(t *testing.T) { |
| clientHello := &clientHelloMsg{ |
| vers: VersionTLS12, |
| random: make([]byte, 32), |
| cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, |
| compressionMethods: []uint8{compressionNone}, |
| supportedCurves: []CurveID{curveid}, |
| keyShares: []keyShare{generateKeyShare(curveid)}, |
| supportedPoints: []uint8{pointFormatUncompressed}, |
| supportedVersions: []uint16{VersionTLS12}, |
| } |
| |
| testClientHello(t, serverConfig, clientHello) |
| |
| // With fipstls forced, bad curves should be rejected. |
| t.Run("fipstls", func(t *testing.T) { |
| fipstls.Force() |
| defer fipstls.Abandon() |
| msg := "" |
| if !isBoringCurve(curveid) { |
| msg = "no cipher suite supported by both client and server" |
| } |
| testClientHelloFailure(t, serverConfig, clientHello, msg) |
| }) |
| }) |
| } |
| } |
| |
| func boringHandshake(t *testing.T, clientConfig, serverConfig *Config) (clientErr, serverErr error) { |
| c, s := localPipe(t) |
| client := Client(c, clientConfig) |
| server := Server(s, serverConfig) |
| done := make(chan error, 1) |
| go func() { |
| done <- client.Handshake() |
| c.Close() |
| }() |
| serverErr = server.Handshake() |
| s.Close() |
| clientErr = <-done |
| return |
| } |
| |
| func TestBoringServerSignatureAndHash(t *testing.T) { |
| defer func() { |
| testingOnlyForceClientHelloSignatureAlgorithms = nil |
| }() |
| |
| for _, sigHash := range defaultSupportedSignatureAlgorithms { |
| t.Run(fmt.Sprintf("%#x", sigHash), func(t *testing.T) { |
| serverConfig := testConfig.Clone() |
| serverConfig.Certificates = make([]Certificate, 1) |
| |
| testingOnlyForceClientHelloSignatureAlgorithms = []SignatureScheme{sigHash} |
| |
| sigType, _, _ := typeAndHashFromSignatureScheme(sigHash) |
| switch sigType { |
| case signaturePKCS1v15, signatureRSAPSS: |
| serverConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256} |
| serverConfig.Certificates[0].Certificate = [][]byte{testRSA2048Certificate} |
| serverConfig.Certificates[0].PrivateKey = testRSA2048PrivateKey |
| case signatureEd25519: |
| serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256} |
| serverConfig.Certificates[0].Certificate = [][]byte{testEd25519Certificate} |
| serverConfig.Certificates[0].PrivateKey = testEd25519PrivateKey |
| case signatureECDSA: |
| serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256} |
| serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} |
| serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey |
| } |
| serverConfig.BuildNameToCertificate() |
| // PKCS#1 v1.5 signature algorithms can't be used standalone in TLS |
| // 1.3, and the ECDSA ones bind to the curve used. |
| serverConfig.MaxVersion = VersionTLS12 |
| |
| clientErr, serverErr := boringHandshake(t, testConfig, serverConfig) |
| if clientErr != nil { |
| t.Fatalf("expected handshake with %#x to succeed; client error: %v; server error: %v", sigHash, clientErr, serverErr) |
| } |
| |
| // With fipstls forced, bad curves should be rejected. |
| t.Run("fipstls", func(t *testing.T) { |
| fipstls.Force() |
| defer fipstls.Abandon() |
| clientErr, _ := boringHandshake(t, testConfig, serverConfig) |
| if isBoringSignatureScheme(sigHash) { |
| if clientErr != nil { |
| t.Fatalf("expected handshake with %#x to succeed; err=%v", sigHash, clientErr) |
| } |
| } else { |
| if clientErr == nil { |
| t.Fatalf("expected handshake with %#x to fail, but it succeeded", sigHash) |
| } |
| } |
| }) |
| }) |
| } |
| } |
| |
| func TestBoringClientHello(t *testing.T) { |
| // Test that no matter what we put in the client config, |
| // the client does not offer non-FIPS configurations. |
| fipstls.Force() |
| defer fipstls.Abandon() |
| |
| c, s := net.Pipe() |
| defer c.Close() |
| defer s.Close() |
| |
| clientConfig := testConfig.Clone() |
| // All sorts of traps for the client to avoid. |
| clientConfig.MinVersion = VersionSSL30 |
| clientConfig.MaxVersion = VersionTLS13 |
| clientConfig.CipherSuites = allCipherSuites() |
| clientConfig.CurvePreferences = defaultCurvePreferences |
| |
| go Client(c, clientConfig).Handshake() |
| srv := Server(s, testConfig) |
| msg, err := srv.readHandshake(nil) |
| if err != nil { |
| t.Fatal(err) |
| } |
| hello, ok := msg.(*clientHelloMsg) |
| if !ok { |
| t.Fatalf("unexpected message type %T", msg) |
| } |
| |
| if !isBoringVersion(hello.vers) { |
| t.Errorf("client vers=%#x", hello.vers) |
| } |
| for _, v := range hello.supportedVersions { |
| if !isBoringVersion(v) { |
| t.Errorf("client offered disallowed version %#x", v) |
| } |
| } |
| for _, id := range hello.cipherSuites { |
| if !isBoringCipherSuite(id) { |
| t.Errorf("client offered disallowed suite %#x", id) |
| } |
| } |
| for _, id := range hello.supportedCurves { |
| if !isBoringCurve(id) { |
| t.Errorf("client offered disallowed curve %d", id) |
| } |
| } |
| for _, sigHash := range hello.supportedSignatureAlgorithms { |
| if !isBoringSignatureScheme(sigHash) { |
| t.Errorf("client offered disallowed signature-and-hash %v", sigHash) |
| } |
| } |
| } |
| |
| func TestBoringCertAlgs(t *testing.T) { |
| // NaCl, arm and wasm time out generating keys. Nothing in this test is architecture-specific, so just don't bother on those. |
| if runtime.GOOS == "nacl" || runtime.GOARCH == "arm" || runtime.GOOS == "js" { |
| t.Skipf("skipping on %s/%s because key generation takes too long", runtime.GOOS, runtime.GOARCH) |
| } |
| |
| // Set up some roots, intermediate CAs, and leaf certs with various algorithms. |
| // X_Y is X signed by Y. |
| R1 := boringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK) |
| R2 := boringCert(t, "R2", boringRSAKey(t, 512), nil, boringCertCA) |
| |
| M1_R1 := boringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK) |
| M2_R1 := boringCert(t, "M2_R1", boringECDSAKey(t, elliptic.P224()), R1, boringCertCA) |
| |
| I_R1 := boringCert(t, "I_R1", boringRSAKey(t, 3072), R1, boringCertCA|boringCertFIPSOK) |
| I_R2 := boringCert(t, "I_R2", I_R1.key, R2, boringCertCA|boringCertFIPSOK) |
| I_M1 := boringCert(t, "I_M1", I_R1.key, M1_R1, boringCertCA|boringCertFIPSOK) |
| I_M2 := boringCert(t, "I_M2", I_R1.key, M2_R1, boringCertCA|boringCertFIPSOK) |
| |
| L1_I := boringCert(t, "L1_I", boringECDSAKey(t, elliptic.P384()), I_R1, boringCertLeaf|boringCertFIPSOK) |
| L2_I := boringCert(t, "L2_I", boringRSAKey(t, 1024), I_R1, boringCertLeaf) |
| |
| // client verifying server cert |
| testServerCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) { |
| clientConfig := testConfig.Clone() |
| clientConfig.RootCAs = pool |
| clientConfig.InsecureSkipVerify = false |
| clientConfig.ServerName = "example.com" |
| |
| serverConfig := testConfig.Clone() |
| serverConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}} |
| serverConfig.BuildNameToCertificate() |
| |
| clientErr, _ := boringHandshake(t, clientConfig, serverConfig) |
| |
| if (clientErr == nil) == ok { |
| if ok { |
| t.Logf("%s: accept", desc) |
| } else { |
| t.Logf("%s: reject", desc) |
| } |
| } else { |
| if ok { |
| t.Errorf("%s: BAD reject (%v)", desc, clientErr) |
| } else { |
| t.Errorf("%s: BAD accept", desc) |
| } |
| } |
| } |
| |
| // server verifying client cert |
| testClientCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) { |
| clientConfig := testConfig.Clone() |
| clientConfig.ServerName = "example.com" |
| clientConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}} |
| |
| serverConfig := testConfig.Clone() |
| serverConfig.ClientCAs = pool |
| serverConfig.ClientAuth = RequireAndVerifyClientCert |
| |
| _, serverErr := boringHandshake(t, clientConfig, serverConfig) |
| |
| if (serverErr == nil) == ok { |
| if ok { |
| t.Logf("%s: accept", desc) |
| } else { |
| t.Logf("%s: reject", desc) |
| } |
| } else { |
| if ok { |
| t.Errorf("%s: BAD reject (%v)", desc, serverErr) |
| } else { |
| t.Errorf("%s: BAD accept", desc) |
| } |
| } |
| } |
| |
| // Run simple basic test with known answers before proceeding to |
| // exhaustive test with computed answers. |
| r1pool := x509.NewCertPool() |
| r1pool.AddCert(R1.cert) |
| testServerCert(t, "basic", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true) |
| testClientCert(t, "basic (client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true) |
| fipstls.Force() |
| testServerCert(t, "basic (fips)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false) |
| testClientCert(t, "basic (fips, client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false) |
| fipstls.Abandon() |
| |
| if t.Failed() { |
| t.Fatal("basic test failed, skipping exhaustive test") |
| } |
| |
| if testing.Short() { |
| t.Logf("basic test passed; skipping exhaustive test in -short mode") |
| return |
| } |
| |
| for l := 1; l <= 2; l++ { |
| leaf := L1_I |
| if l == 2 { |
| leaf = L2_I |
| } |
| for i := 0; i < 64; i++ { |
| reachable := map[string]bool{leaf.parentOrg: true} |
| reachableFIPS := map[string]bool{leaf.parentOrg: leaf.fipsOK} |
| list := [][]byte{leaf.der} |
| listName := leaf.name |
| addList := func(cond int, c *boringCertificate) { |
| if cond != 0 { |
| list = append(list, c.der) |
| listName += "," + c.name |
| if reachable[c.org] { |
| reachable[c.parentOrg] = true |
| } |
| if reachableFIPS[c.org] && c.fipsOK { |
| reachableFIPS[c.parentOrg] = true |
| } |
| } |
| } |
| addList(i&1, I_R1) |
| addList(i&2, I_R2) |
| addList(i&4, I_M1) |
| addList(i&8, I_M2) |
| addList(i&16, M1_R1) |
| addList(i&32, M2_R1) |
| |
| for r := 1; r <= 3; r++ { |
| pool := x509.NewCertPool() |
| rootName := "," |
| shouldVerify := false |
| shouldVerifyFIPS := false |
| addRoot := func(cond int, c *boringCertificate) { |
| if cond != 0 { |
| rootName += "," + c.name |
| pool.AddCert(c.cert) |
| if reachable[c.org] { |
| shouldVerify = true |
| } |
| if reachableFIPS[c.org] && c.fipsOK { |
| shouldVerifyFIPS = true |
| } |
| } |
| } |
| addRoot(r&1, R1) |
| addRoot(r&2, R2) |
| rootName = rootName[1:] // strip leading comma |
| testServerCert(t, listName+"->"+rootName[1:], pool, leaf.key, list, shouldVerify) |
| testClientCert(t, listName+"->"+rootName[1:]+"(client cert)", pool, leaf.key, list, shouldVerify) |
| fipstls.Force() |
| testServerCert(t, listName+"->"+rootName[1:]+" (fips)", pool, leaf.key, list, shouldVerifyFIPS) |
| testClientCert(t, listName+"->"+rootName[1:]+" (fips, client cert)", pool, leaf.key, list, shouldVerifyFIPS) |
| fipstls.Abandon() |
| } |
| } |
| } |
| } |
| |
| const ( |
| boringCertCA = iota |
| boringCertLeaf |
| boringCertFIPSOK = 0x80 |
| ) |
| |
| func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey { |
| k, err := rsa.GenerateKey(rand.Reader, size) |
| if err != nil { |
| t.Fatal(err) |
| } |
| return k |
| } |
| |
| func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey { |
| k, err := ecdsa.GenerateKey(curve, rand.Reader) |
| if err != nil { |
| t.Fatal(err) |
| } |
| return k |
| } |
| |
| type boringCertificate struct { |
| name string |
| org string |
| parentOrg string |
| der []byte |
| cert *x509.Certificate |
| key interface{} |
| fipsOK bool |
| } |
| |
| func boringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate { |
| org := name |
| parentOrg := "" |
| if i := strings.Index(org, "_"); i >= 0 { |
| org = org[:i] |
| parentOrg = name[i+1:] |
| } |
| tmpl := &x509.Certificate{ |
| SerialNumber: big.NewInt(1), |
| Subject: pkix.Name{ |
| Organization: []string{org}, |
| }, |
| NotBefore: time.Unix(0, 0), |
| NotAfter: time.Unix(0, 0), |
| |
| KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, |
| ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, |
| BasicConstraintsValid: true, |
| } |
| if mode&^boringCertFIPSOK == boringCertLeaf { |
| tmpl.DNSNames = []string{"example.com"} |
| } else { |
| tmpl.IsCA = true |
| tmpl.KeyUsage |= x509.KeyUsageCertSign |
| } |
| |
| var pcert *x509.Certificate |
| var pkey interface{} |
| if parent != nil { |
| pcert = parent.cert |
| pkey = parent.key |
| } else { |
| pcert = tmpl |
| pkey = key |
| } |
| |
| var pub interface{} |
| switch k := key.(type) { |
| case *rsa.PrivateKey: |
| pub = &k.PublicKey |
| case *ecdsa.PrivateKey: |
| pub = &k.PublicKey |
| default: |
| t.Fatalf("invalid key %T", key) |
| } |
| |
| der, err := x509.CreateCertificate(rand.Reader, tmpl, pcert, pub, pkey) |
| if err != nil { |
| t.Fatal(err) |
| } |
| cert, err := x509.ParseCertificate(der) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| fipsOK := mode&boringCertFIPSOK != 0 |
| return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK} |
| } |
| |
| // A self-signed test certificate with an RSA key of size 2048, for testing |
| // RSA-PSS with SHA512. SAN of example.golang. |
| var ( |
| testRSA2048Certificate []byte |
| testRSA2048PrivateKey *rsa.PrivateKey |
| ) |
| |
| func init() { |
| block, _ := pem.Decode(obscuretestdata.Rot13([]byte(` |
| -----ORTVA PREGVSVPNGR----- |
| ZVVP/mPPNrrtNjVONtVENYUUK/xu4+4mZH9QnemORpDjQDLWXbMVuipANDRYODNj |
| RwRDZN4TN1HRPuZUDJAgMFOQomNrSj0kZGNkZQRkAGN0ZQInSj0lZQRlZwxkAGN0 |
| ZQInZOVkRQNBOtAIONbGO0SwoJHtD28jttRvZN0TPFdTFVo3QDRONDHNN4VOQjNj |
| ttRXNbVONDPs8sx0A6vrPOK4VBIVsXvgg4xTpBDYrvzPsfwddUplfZVITRgSFZ6R |
| 4Nl141s/7VdqJ0HgVdAo4CKuEBVQ7lQkE284kY6KoPhi/g5uC3HpruLp3uzYvlIq |
| ZxMDvMJgsHHWs/1dBgZ+buAt59YEJc4q+6vK0yn1WY3RjPVpxxAwW9uDoS7Co2PF |
| +RF9Lb55XNnc8XBoycpE8ZOFA38odajwsDqPKiBRBwnz2UHkXmRSK5ZN+sN0zr4P |
| vbPpPEYJXy+TbA9S8sNOsbM+G+2rny4QYhB95eKE8FeBVIOu3KSBe/EIuwgKpAIS |
| MXpiQg6q68I6wNXNLXz5ayw9TCcq4i+eNtZONNTwHQOBZN4TN1HqQjRO/jDRNjVS |
| bQNGOtAIUFHRQQNXOtteOtRSODpQNGNZOtAIUEZONs8RNwNNZOxTN1HqRDDFZOPP |
| QzI4LJ1joTHhM29fLJ5aZN0TPFdTFVo3QDROPjHNN4VONDPBbLfIpSPOuobdr3JU |
| qP6I7KKKRPzawu01e8u80li0AE379aFQ3pj2Z+UXinKlfJdey5uwTIXj0igjQ81e |
| I4WmQh7VsVbt5z8+DAP+7YdQMfm88iQXBefblFIBzHPtzPXSKrj+YN+rB/vDRWGe |
| 7rafqqBrKWRc27Rq5iJ+xzJJ3Dztyp2Tjl8jSeZQVdaeaBmON4bPaQRtgKWg0mbt |
| aEjosRZNJv1nDEl5qG9XN3FC9zb5FrGSFmTTUvR4f4tUHr7wifNSS2dtgQ6+jU6f |
| m9o6fukaP7t5VyOXuV7FIO/Hdg2lqW+xU1LowZpVd6ANZ5rAZXtMhWe3+mjfFtju |
| TAnR |
| -----RAQ PREGVSVPNGR-----`))) |
| testRSA2048Certificate = block.Bytes |
| |
| block, _ = pem.Decode(obscuretestdata.Rot13([]byte(` |
| -----ORTVA EFN CEVINGR XRL----- |
| ZVVRcNVONNXPNDRNa/U5AQrbattI+PQyFUlbeorWOaQxP3bcta7V6du3ZeQPSEuY |
| EHwBuBNZgrAK/+lXaIgSYFXwJ+Q14HGvN+8t8HqiBZF+y2jee/7rLG91UUbJUA4M |
| v4fyKGWTHVzIeK1SPK/9nweGCdVGLBsF0IdrUshby9WJgFF9kZNvUWWQLlsLHTkr |
| m29txiuRiJXBrFtTdsPwz5nKRsQNHwq/T6c8V30UDy7muQb2cgu1ZFfkOI+GNCaj |
| AWahNbdNaNxF1vcsudQsEsUjNK6Tsx/gazcrNl7wirn10sRdmvSDLq1kGd/0ILL7 |
| I3QIEJFaYj7rariSrbjPtTPchM5L/Ew6KrY/djVQNDNONbVONDPAcZMvsq/it42u |
| UqPiYhMnLF0E7FhaSycbKRfygTqYSfac0VsbWM/htSDOFNVVsYjZhzH6bKN1m7Hi |
| 98nVLI61QrCeGPQIQSOfUoAzC8WNb8JgohfRojq5mlbO7YLT2+pyxWxyJR73XdHd |
| ezV+HWrlFpy2Tva7MGkOKm1JCOx9IjpajxrnKctNFVOJ23suRPZ9taLRRjnOrm5G |
| 6Zr8q1gUgLDi7ifXr7eb9j9/UXeEKrwdLXX1YkxusSevlI+z8YMWMa2aKBn6T3tS |
| Ao8Dx1Hx5CHORAOzlZSWuG4Z/hhFd4LgZeeB2tv8D+sCuhTmp5FfuLXEOc0J4C5e |
| zgIPgRSENbTONZRAOVSYeI2+UfTw0kLSnfXbi/DCr6UFGE1Uu2VMBAc+bX4bfmJR |
| wOG4IpaVGzcy6gP1Jl4TpekwAtXVSMNw+1k1YHHYqbeKxhT8le0gNuT9mAlsJfFl |
| CeFbiP0HIome8Wkkyn+xDIkRDDdJDkCyRIhY8xKnVQN6Ylg1Uchn2YiCNbTONADM |
| p6Yd2G7+OkYkAqv2z8xMmrw5xtmOc/KqIfoSJEyroVK2XeSUfeUmG9CHx3QR1iMX |
| Z6cmGg94aDuJFxQtPnj1FbuRyW3USVSjphfS1FWNp3cDrcq8ht6VLqycQZYgOw/C |
| /5C6OIHgtb05R4+V/G3vLngztyDkGgyM0ExFI2yyNbTONYBKxXSK7nuCis0JxfQu |
| hGshSBGCbbjtDT0RctJ0jEqPkrt/WYvp3yFQ0tfggDI2JfErpelJpknryEt10EzB |
| 38OobtzunS4kitfFihwBsvMGR8bX1G43Z+6AXfVyZY3LVYocH/9nWkCJl0f2QdQe |
| pDWuMeyx+cmwON7Oas/HEqjkNbTNXE/PAj14Q+zeY3LYoovPKvlqdkIjki5cqMqm |
| 8guv3GApfJP4vTHEqpIdosHvaICqWvKr/Xnp3JTPrEWnSItoXNBkYgv1EO5ZxVut |
| Q8rlhcOdx4J1Y1txekdfqw4GSykxjZljwy2R2F4LlD8COg6I04QbIEMfVXmdm+CS |
| HvbaCd0PtLOPLKidvbWuCrjxBd/L5jeQOrMJ1SDX5DQ9J5Z8/5mkq4eqiWgwuoWc |
| bBegiZqey6hcl9Um4OWQ3SKjISvCSR7wdrAdv0S21ivYkOCZZQ3HBQS6YY5RlYvE |
| 9I4kIZF8XKkit7ekfhdmZCfpIvnJHY6JAIOufQ2+92qUkFKmm5RWXD== |
| -----RAQ EFN CEVINGR XRL-----`))) |
| var err error |
| testRSA2048PrivateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) |
| if err != nil { |
| panic(err) |
| } |
| } |