Last active
April 15, 2016 18:10
-
-
Save liggitt/535f6529e7efaeb6faef38434f98c3aa to your computer and use it in GitHub Desktop.
Test case for client-cert CORS requests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/tls" | |
"crypto/x509" | |
"fmt" | |
"net" | |
"net/http" | |
"os" | |
"time" | |
) | |
// Download and install go from https://golang.org/dl/ | |
// Launch with: | |
// go run client-cert-test.go | |
func main() { | |
go serve("9080") | |
go serveTLS("9443", true) | |
go serveTLS("9444", false) | |
fmt.Println(`Launch http://127.0.0.1:9080/`) | |
fmt.Println(`ctrl+c to exit`) | |
select {} | |
} | |
// launch a non-tls server on the given port | |
// mostly for setup instructions, serving the CA to trust, and the launch page for the tests | |
func serve(port string) { | |
server := &http.Server{ | |
Addr: "0.0.0.0:" + port, | |
Handler: http.HandlerFunc(handle(port)), | |
} | |
fmt.Println(server.ListenAndServe()) | |
os.Exit(1) | |
} | |
// launch a tls server on the given port | |
// optionally request client certificates during the handshake | |
func serveTLS(port string, requestClientCert bool) { | |
servingCert, _ := tls.X509KeyPair(serverCertData, serverKeyData) | |
server := &http.Server{ | |
Addr: "0.0.0.0:" + port, | |
Handler: http.HandlerFunc(handle(port)), | |
TLSConfig: &tls.Config{ | |
NextProtos: []string{"http/1.1"}, | |
Certificates: []tls.Certificate{servingCert}, | |
}, | |
} | |
// Make sure every request has to do a TLS handshake | |
// Otherwise, incidental visits to the api host can make the bug intermittently reproduceable | |
server.SetKeepAlivesEnabled(false) | |
if requestClientCert { | |
clientCAPool := x509.NewCertPool() | |
clientCAPool.AppendCertsFromPEM(serverCAData) | |
server.TLSConfig.ClientCAs = clientCAPool | |
server.TLSConfig.ClientAuth = tls.RequestClientCert | |
} | |
ln, err := net.Listen("tcp", server.Addr) | |
if err != nil { | |
panic(err) | |
} | |
l := &debuggingListener{tls.NewListener(ln, server.TLSConfig)} | |
fmt.Println(server.Serve(l)) | |
os.Exit(1) | |
} | |
// Wrap a net.Listener to log when Accept calls are made | |
type debuggingListener struct { | |
net.Listener | |
} | |
func (d *debuggingListener) Accept() (net.Conn, error) { | |
conn, err := d.Listener.Accept() | |
fmt.Printf("Accept connection: %v\n", err) | |
return conn, err | |
} | |
// handle all requests | |
func handle(port string) func(w http.ResponseWriter, req *http.Request) { | |
return func(w http.ResponseWriter, req *http.Request) { | |
fmt.Printf("%s %s\n%#v\n\n", req.Method, req.URL, req.Header) | |
switch req.URL.Path { | |
case "/": | |
// Serve setup HTML | |
w.Header().Set("Content-Type", "text/html") | |
w.Write([]byte(setupHTML)) | |
case "/ca.crt": | |
// Serve CA cert so browsers can accept it | |
w.Header().Set("Content-Type", "application/x-x509-ca-cert") | |
w.Write(serverCAData) | |
case "/test": | |
// Serve test case HTML | |
w.Header().Set("Content-Type", "text/html") | |
w.Write([]byte(fmt.Sprintf(testHTML, port))) | |
default: | |
// Serve plaintext test data from all other paths | |
// Add CORS headers to allow cross-domain requests | |
origin := req.Header.Get("Origin") | |
if origin != "" { | |
w.Header().Set("Access-Control-Allow-Origin", origin) | |
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") | |
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Requested-With, If-Modified-Since") | |
w.Header().Set("Access-Control-Allow-Credentials", "true") | |
} | |
if req.Method == "OPTIONS" { | |
w.WriteHeader(http.StatusNoContent) | |
} else { | |
w.Header().Set("Content-Type", "text/plain") | |
w.WriteHeader(http.StatusOK) | |
w.Write([]byte(fmt.Sprintf(`%d.%d`, time.Now().Second(), time.Now().Nanosecond()))) | |
} | |
} | |
} | |
} | |
var ( | |
setupHTML = `<!doctype html> | |
<html lang="en"> | |
<head> | |
<style> | |
* { font-family: sans-serif } | |
table { width: 100% } | |
iframe { width: 100%; height: 200px; } | |
</style> | |
</head> | |
<body> | |
<ol> | |
<li>Alias api.example.com and web.example.com to 127.0.0.1 (using <code>/etc/hosts</code> or <code>%WINDOWS%\system32\drivers\etc\hosts</code>) | |
<li>Install <a href="/ca.crt" target="_blank">ca.crt</a> to the Trusted Root Certification Authorities certificate store (in a throwaway VM or test machine, not on a real machine!). The frames below should load without security warnings. | |
<li>Try both cross-origin test cases. The only difference between them is the client cert request. | |
<li>Try both same-origin test cases. The only difference between them is the client cert request, and both succeed. | |
</ol> | |
<p>If the "same-origin with client cert request" test case is loaded before running the "cross-origin with client cert request" test, the cross-origin test will pass, despite each request starting from scratch with a TLS handshake (keep-alive is disabled in the test server)</p> | |
<table> | |
<tr> | |
<th><a href="https://web.example.com:9443/test" target="cross_cert">Cross-origin XHR with client cert request</a> | |
<th><a href="https://web.example.com:9444/test" target="cross_nocert">Cross-origin XHR without client cert request</a> | |
<tr> | |
<td><iframe name="cross_cert"></iframe> | |
<td><iframe name="cross_nocert"></iframe> | |
<tr> | |
<th><a href="https://api.example.com:9443/test" target="same_cert">Same-origin XHR with client cert request</a> | |
<th><a href="https://api.example.com:9444/test" target="same_nocert">Same-origin XHR without client cert request</a> | |
<tr> | |
<td><iframe name="same_cert"></iframe> | |
<td><iframe name="same_nocert"></iframe> | |
</table> | |
</body> | |
</html>` | |
testHTML = `<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script> | |
<script> | |
function request(method, outputTarget) { | |
var target = $(outputTarget); | |
target.empty().append("<div>Requesting "+method+"...</div>"); | |
$.ajax({ | |
method: method, | |
url: "https://api.example.com:%[1]s/api/" + (new Date().getTime()), | |
headers: {"Authorization":"Bearer 123"} | |
}) | |
.done(function(){ | |
console.log(arguments); | |
$("<div></div>").text("Success: " + JSON.stringify(arguments)).appendTo(target); | |
}) | |
.fail(function(){ | |
console.log(arguments); | |
$("<div></div>").text("Fail: " + JSON.stringify(arguments)).appendTo(target); | |
}); | |
} | |
$(function(){ | |
$("#origin").text(document.location.toString()); | |
}) | |
</script> | |
</head> | |
<body> | |
Serving from <span id="origin"></span><br> | |
<button onclick="request('GET','#result')">Make GET XHR request to https://api.example.com:%[1]s/</button><br> | |
<button onclick="request('POST','#result')">Make POST XHR request to https://api.example.com:%[1]s/</button><br> | |
<div id="result"></div> | |
</body> | |
</html> | |
` | |
serverCAData = []byte(` | |
Certificate: | |
Data: | |
Version: 3 (0x2) | |
Serial Number: 1 (0x1) | |
Signature Algorithm: sha256WithRSAEncryption | |
Issuer: CN=test-ca | |
Validity | |
Not Before: Apr 13 14:45:54 2016 GMT | |
Not After : Mar 20 14:45:55 2116 GMT | |
Subject: CN=test-ca | |
Subject Public Key Info: | |
Public Key Algorithm: rsaEncryption | |
RSA Public Key: (2048 bit) | |
Modulus (2048 bit): | |
00:cb:52:6a:a0:cf:86:ff:dd:bd:a4:38:32:71:6e: | |
cc:85:bd:7a:be:03:8d:b1:3b:f8:c0:dd:eb:21:96: | |
ef:9b:5d:b7:d1:f5:e5:d8:6c:8e:68:f6:80:f6:9b: | |
19:3c:84:05:a8:3c:ae:da:c8:df:17:23:32:52:bf: | |
92:13:0c:9e:b2:f3:ce:18:83:fd:2d:6c:ef:b8:35: | |
32:45:90:15:6c:06:64:9f:81:c4:df:74:cc:96:a4: | |
75:e4:c4:fa:ad:b4:f3:fd:ba:36:22:01:c9:9e:76: | |
58:42:a3:80:c0:64:7e:c0:b0:90:84:88:b4:a0:59: | |
fe:43:ef:91:1e:1a:7a:92:e6:09:cd:dd:4c:8e:d1: | |
ea:4b:0f:0f:b5:48:b1:77:9f:06:38:29:08:ba:6c: | |
34:56:58:a7:52:dd:64:3a:28:17:78:72:69:8f:f6: | |
16:f8:e4:64:03:7f:35:92:7b:4f:23:83:07:48:29: | |
27:de:f3:ae:a9:84:48:98:35:9b:29:f4:01:bf:37: | |
12:f5:dc:40:0c:99:5f:81:44:8f:17:94:25:d1:65: | |
19:35:a8:82:57:2b:2c:4a:ae:b1:3d:47:76:3d:aa: | |
3e:f0:3b:68:3c:68:82:81:6f:62:68:2f:85:b6:47: | |
5c:fc:68:d9:be:b5:7c:da:6d:62:36:47:cf:3b:fd: | |
56:57 | |
Exponent: 65537 (0x10001) | |
X509v3 extensions: | |
X509v3 Key Usage: critical | |
Digital Signature, Key Encipherment, Certificate Sign | |
X509v3 Basic Constraints: critical | |
CA:TRUE | |
Signature Algorithm: sha256WithRSAEncryption | |
97:d1:6d:3f:3f:6b:a6:cb:40:30:a5:ab:cd:2d:c6:8e:70:07: | |
6f:f1:69:b4:0c:d6:0c:a8:cc:98:3d:47:d0:9e:f1:6a:7c:c3: | |
07:4e:5b:c6:47:64:d9:70:5f:6c:6f:a8:c0:0c:ad:14:c8:33: | |
be:f0:26:67:ac:43:b9:c2:5f:b1:29:ff:c3:69:2d:a1:72:62: | |
b4:1a:e4:20:0d:0d:88:41:4a:90:2d:f7:5c:ab:ed:23:55:28: | |
f6:dd:aa:37:a5:ad:15:ab:dc:18:9d:c6:e7:a0:30:48:ed:ee: | |
91:0f:49:b8:dd:ef:78:29:01:0e:c0:37:06:59:99:7e:39:e8: | |
9c:80:38:1f:4d:aa:b6:aa:5e:ec:35:ee:01:d9:45:01:5f:69: | |
da:f5:aa:bc:5d:b6:a0:ce:cb:fc:4e:e4:5f:c6:42:a0:bd:91: | |
a1:99:b1:95:f5:86:a2:0e:29:98:0b:6e:d3:8b:e4:f6:1c:bc: | |
24:39:4f:67:12:3c:dc:69:77:38:57:d4:19:da:9e:98:59:c2: | |
c3:84:39:26:ab:6d:5a:6e:1a:51:27:27:43:35:97:8c:8e:27: | |
1f:e6:c6:24:ec:ef:4f:b4:63:e0:c5:f2:cf:43:0a:b6:7a:df: | |
1c:90:87:15:6d:a2:7e:02:d4:9d:90:e7:ba:6e:6f:d3:11:89: | |
24:92:31:b5 | |
-----BEGIN CERTIFICATE----- | |
MIICxDCCAaygAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwd0ZXN0 | |
LWNhMCAXDTE2MDQxMzE0NDU1NFoYDzIxMTYwMzIwMTQ0NTU1WjASMRAwDgYDVQQD | |
Ewd0ZXN0LWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy1JqoM+G | |
/929pDgycW7Mhb16vgONsTv4wN3rIZbvm1230fXl2GyOaPaA9psZPIQFqDyu2sjf | |
FyMyUr+SEwyesvPOGIP9LWzvuDUyRZAVbAZkn4HE33TMlqR15MT6rbTz/bo2IgHJ | |
nnZYQqOAwGR+wLCQhIi0oFn+Q++RHhp6kuYJzd1MjtHqSw8PtUixd58GOCkIumw0 | |
VlinUt1kOigXeHJpj/YW+ORkA381kntPI4MHSCkn3vOuqYRImDWbKfQBvzcS9dxA | |
DJlfgUSPF5Ql0WUZNaiCVyssSq6xPUd2Pao+8DtoPGiCgW9iaC+Ftkdc/GjZvrV8 | |
2m1iNkfPO/1WVwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAqQwDwYDVR0TAQH/BAUw | |
AwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAl9FtPz9rpstAMKWrzS3GjnAHb/FptAzW | |
DKjMmD1H0J7xanzDB05bxkdk2XBfbG+owAytFMgzvvAmZ6xDucJfsSn/w2ktoXJi | |
tBrkIA0NiEFKkC33XKvtI1Uo9t2qN6WtFavcGJ3G56AwSO3ukQ9JuN3veCkBDsA3 | |
BlmZfjnonIA4H02qtqpe7DXuAdlFAV9p2vWqvF22oM7L/E7kX8ZCoL2RoZmxlfWG | |
og4pmAtu04vk9hy8JDlPZxI83Gl3OFfUGdqemFnCw4Q5JqttWm4aUScnQzWXjI4n | |
H+bGJOzvT7Rj4MXyz0MKtnrfHJCHFW2ifgLUnZDnum5v0xGJJJIxtQ== | |
-----END CERTIFICATE-----`) | |
serverCertData = []byte(` | |
Certificate: | |
Data: | |
Version: 3 (0x2) | |
Serial Number: 2 (0x2) | |
Signature Algorithm: sha256WithRSAEncryption | |
Issuer: CN=test-ca | |
Validity | |
Not Before: Apr 13 14:46:21 2016 GMT | |
Not After : Mar 20 14:46:22 2116 GMT | |
Subject: CN=api.example.com | |
Subject Public Key Info: | |
Public Key Algorithm: rsaEncryption | |
RSA Public Key: (2048 bit) | |
Modulus (2048 bit): | |
00:bf:4c:26:e6:f5:7c:a8:55:56:6d:b6:b4:02:88: | |
4e:69:41:e9:f6:6e:1d:02:f1:25:a4:46:85:49:90: | |
10:bc:a7:d9:ec:98:b9:7a:c5:b9:9c:97:61:00:c1: | |
7e:83:cd:3f:a5:eb:55:ba:20:86:c4:08:aa:34:06: | |
8e:1b:2f:13:e8:f3:13:35:d4:a2:1e:76:7b:cb:3b: | |
17:06:b6:64:bc:75:d7:f5:9b:da:2d:b5:c9:7a:a4: | |
51:e1:46:5b:dc:2c:e6:32:c8:04:94:52:f6:71:c0: | |
ae:04:d9:8e:bc:95:54:5b:c6:d9:d9:f9:19:b1:08: | |
30:03:54:20:34:9d:c5:e8:ca:44:8d:f8:c7:a1:f6: | |
41:35:a1:8d:85:b0:06:1c:46:53:ce:a3:93:47:e6: | |
0f:ec:bd:f5:bd:d8:ec:dc:67:a8:a0:37:f9:44:90: | |
26:11:75:c2:18:8a:4c:64:13:f0:2e:24:e0:8a:87: | |
be:fd:f3:17:32:56:73:37:71:54:c9:75:0c:7d:8a: | |
15:fb:74:bb:04:c0:b8:14:06:18:6f:bb:a4:c9:6c: | |
a6:5d:37:5b:91:f2:3e:6d:26:cd:33:fa:72:19:89: | |
f1:b3:86:b8:47:79:ae:08:ec:89:57:5c:d5:e4:bd: | |
2a:bb:73:a3:08:a6:94:c4:98:3e:6e:8f:a5:63:9f: | |
c1:57 | |
Exponent: 65537 (0x10001) | |
X509v3 extensions: | |
X509v3 Key Usage: critical | |
Digital Signature, Key Encipherment | |
X509v3 Extended Key Usage: | |
TLS Web Server Authentication | |
X509v3 Basic Constraints: critical | |
CA:FALSE | |
X509v3 Subject Alternative Name: | |
DNS:api.example.com, DNS:web.example.com | |
Signature Algorithm: sha256WithRSAEncryption | |
05:0c:d2:60:5c:23:fd:b2:af:c6:bd:2a:bb:f9:a3:9c:77:eb: | |
dc:39:d5:47:6a:46:40:cb:fc:c9:aa:b4:01:0f:3a:89:44:4f: | |
24:1e:a8:0f:29:36:3b:0b:16:ae:b9:a6:92:ef:78:18:b8:5b: | |
cc:ae:75:f0:d1:44:5d:df:6f:71:c4:c1:50:ff:c7:8f:65:5c: | |
da:2b:71:2e:ad:79:81:86:40:6d:32:d6:c0:80:9a:55:cd:0d: | |
d4:0e:09:80:42:11:38:06:37:f2:a4:f4:19:a9:7f:07:1a:fa: | |
ee:66:8a:3a:61:08:20:6f:41:87:d4:78:1c:3e:50:47:15:74: | |
78:6a:88:35:f6:97:d2:09:1e:c4:80:6a:8c:97:b2:a7:5b:16: | |
9f:ca:8d:82:4d:b3:60:e4:90:28:55:fa:f1:47:1e:8c:e2:03: | |
44:7f:2f:f4:55:80:b7:b2:22:4f:df:43:f1:de:8f:16:ba:af: | |
6a:7c:08:21:2e:47:39:82:01:a5:05:21:62:f9:0c:8c:2a:27: | |
fe:72:f7:32:6d:c9:44:73:4c:b2:e5:aa:72:82:26:9d:fe:61: | |
c5:40:09:c0:4b:04:3f:7e:71:d0:0c:8e:7b:b4:db:c8:59:85: | |
8a:d1:1c:92:cb:b4:f1:f3:6f:fe:e8:ce:d8:d7:79:a1:1e:98: | |
d6:89:be:af | |
-----BEGIN CERTIFICATE----- | |
MIIDCzCCAfOgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwd0ZXN0 | |
LWNhMCAXDTE2MDQxMzE0NDYyMVoYDzIxMTYwMzIwMTQ0NjIyWjAaMRgwFgYDVQQD | |
Ew9hcGkuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB | |
AQC/TCbm9XyoVVZttrQCiE5pQen2bh0C8SWkRoVJkBC8p9nsmLl6xbmcl2EAwX6D | |
zT+l61W6IIbECKo0Bo4bLxPo8xM11KIednvLOxcGtmS8ddf1m9ottcl6pFHhRlvc | |
LOYyyASUUvZxwK4E2Y68lVRbxtnZ+RmxCDADVCA0ncXoykSN+Meh9kE1oY2FsAYc | |
RlPOo5NH5g/svfW92OzcZ6igN/lEkCYRdcIYikxkE/AuJOCKh7798xcyVnM3cVTJ | |
dQx9ihX7dLsEwLgUBhhvu6TJbKZdN1uR8j5tJs0z+nIZifGzhrhHea4I7IlXXNXk | |
vSq7c6MIppTEmD5uj6Vjn8FXAgMBAAGjYjBgMA4GA1UdDwEB/wQEAwIFoDATBgNV | |
HSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMCsGA1UdEQQkMCKCD2FwaS5l | |
eGFtcGxlLmNvbYIPd2ViLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAF | |
DNJgXCP9sq/GvSq7+aOcd+vcOdVHakZAy/zJqrQBDzqJRE8kHqgPKTY7CxauuaaS | |
73gYuFvMrnXw0URd329xxMFQ/8ePZVzaK3EurXmBhkBtMtbAgJpVzQ3UDgmAQhE4 | |
BjfypPQZqX8HGvruZoo6YQggb0GH1HgcPlBHFXR4aog19pfSCR7EgGqMl7KnWxaf | |
yo2CTbNg5JAoVfrxRx6M4gNEfy/0VYC3siJP30Px3o8Wuq9qfAghLkc5ggGlBSFi | |
+QyMKif+cvcybclEc0yy5apygiad/mHFQAnASwQ/fnHQDI57tNvIWYWK0RySy7Tx | |
82/+6M7Y13mhHpjWib6v | |
-----END CERTIFICATE-----`) | |
serverKeyData = []byte(` | |
-----BEGIN RSA PRIVATE KEY----- | |
MIIEowIBAAKCAQEAv0wm5vV8qFVWbba0AohOaUHp9m4dAvElpEaFSZAQvKfZ7Ji5 | |
esW5nJdhAMF+g80/petVuiCGxAiqNAaOGy8T6PMTNdSiHnZ7yzsXBrZkvHXX9Zva | |
LbXJeqRR4UZb3CzmMsgElFL2ccCuBNmOvJVUW8bZ2fkZsQgwA1QgNJ3F6MpEjfjH | |
ofZBNaGNhbAGHEZTzqOTR+YP7L31vdjs3GeooDf5RJAmEXXCGIpMZBPwLiTgioe+ | |
/fMXMlZzN3FUyXUMfYoV+3S7BMC4FAYYb7ukyWymXTdbkfI+bSbNM/pyGYnxs4a4 | |
R3muCOyJV1zV5L0qu3OjCKaUxJg+bo+lY5/BVwIDAQABAoIBADUZ3nKeEkxn4+Xw | |
oWdSjvGI6nkNd+ApMFm5eaZB52N29HdIrbP2zt845iRfkc7kWpakDNftz3r7LMPk | |
Te4d01kGoH6A17+9BAAWFv42AyCNVbVH3fhyTctNca0m6rjjfcL64sqJfP92jNer | |
zINssE4JlM985jTOIQXLhGUWpqlHgX+EtLTRhQ+3NsCWjpKlfMVTm6AoISI8rjaZ | |
JjyZwgVx5zjGnfZZIVlz5Ej6tGBq2S/VSZihV/RdrCQXhPX1cODewN0S3CQNzuK0 | |
Ht8m6+wGb+uk+hxHuxi7hySaXHYWo4pjyydCElnGeb7iXlJ/7/eA0qmC5533JSff | |
jOrnFQECgYEA4TlVfTKC7+hDwvK04kbyJTrjEhRH4LN387yNA3iHhU60vlwif4/7 | |
jaryE/iU8AMN6dlsoUJB+pVH4fThJT6vjM/QEdUNdANJMJvtk0KjIjfJnUGVJ74B | |
DLXlM//rS1JIM+qrjCjb4aN8woQNsTT8NaZiYgHCLmg/0wdJqmzdLu8CgYEA2XAE | |
8rdpfzdajFJmUzYWf3r6zmBe5ecfgAuMzPCYyJe0lfHqSnXlC2nrG96QX+1ojzIj | |
/Vceh0GQswIeIWSS99JukLRsU4Rd0fzk8BQFqprVwJQ/R2YKiGTBtni1wBoR34sP | |
jiGVG3vT66zcze8L5h4P/DWlV0Ne57PCbEtclBkCgYEApMR2B16RrgNkt1UqAbRX | |
Z+c5wbs2jmudYKHbI+PkeSEIV4896cajCJQ7/2JHS4NghWj78MlxTWoyqVql78J5 | |
WXGazcDo06unurkISEhi4iCgDbyx6t41FGBp6u3Z7EOo8NpIYARwQBWDqyZCgha6 | |
QGGV7g9NSPgZYUAeo2B7O98CgYASGTfgOBII68OWsHkh7fubatIbgXwEqOM/VjbH | |
DDO7Zp06aeN1hTCmbY+LR1A/G9S7LpI+URUSbwurSr7VSrjM9fAMDWiC3x6sDt/D | |
d/csxyyJlg1aVQ0FY1WYaZ2/OqxILhwCWZs+qWTvVfkfDwmvgssT1CdKByqMILNL | |
Lk6raQKBgHjdXmKCA4Eu7dyCbb6BN8IQHckFuqdoDSjMeGQq/3o2G6onY+UwgQ/H | |
95O18lIVcQE7Ng1gNYL17m55h9JKyR1dkYodKtB1CQLzYb4lrByPPJFuLVpu1xZP | |
Y3AmKViLO1tZVdR4455in9Grc1qEmZPocAP3uwr4ZzIaq4jE2Zml | |
-----END RSA PRIVATE KEY-----`) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment