Skip to content

Commit

Permalink
MAISTRA-2687 Fix spiffe certificate verification (envoyproxy#116)
Browse files Browse the repository at this point in the history
* MAISTRA-2687 Fix spiffe certificate verification

Previously, when copying the X509 store context, the code erroneously copied the output certificate chain instead of the input (untrusted) chain to the new context. As the output certificate chain is set only after you run X509_verify_cert(), this chain was always empty. Thus, the code only worked properly when the leaf certificate was signed by one of the certificates in the trust bundle (e.g. when the leaf certificate was signed directly by the root certificate). In cases involving intermediate certificates, the leaf certificate was only trusted if all the intermediate certificates were in the trust bundle. Intermediate certificates sent by the client were ignored.

When copying the X509 store context, the input intermediate certificates should be retrieved by calling X509_STORE_CTX_get0_untrusted(), not X509_STORE_CTX_get0_chain().

* Add test

* Fix test

* Release references to certs

Signed-off-by: Marko Lukša <[email protected]>
  • Loading branch information
luksa authored and twghu committed Feb 16, 2022
1 parent 6045b52 commit 0150925
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,7 @@ int SPIFFEValidator::doVerifyCertChain(X509_STORE_CTX* store_ctx,
// Note that there's no api to copy crls from one store_ctx to another; the assumption is that
// neither X509_V_FLAG_CRL_CHECK nor X509_V_FLAG_CRL_CHECK_ALL verify_params are not used.
// Should this change, consider opening up X509_STORE_CTX struct, which is internal atm.
X509_STORE_CTX_init(verify_ctx.get(), trust_bundle, &leaf_cert,
X509_STORE_CTX_get0_chain(store_ctx));
X509_STORE_CTX_init(verify_ctx.get(), trust_bundle, &leaf_cert, X509_STORE_CTX_get0_untrusted(store_ctx));
X509_VERIFY_PARAM* verify_params = X509_VERIFY_PARAM_new();
X509_VERIFY_PARAM_inherit(verify_params, X509_STORE_CTX_get0_param(store_ctx));
X509_STORE_CTX_set0_param(verify_ctx.get(), verify_params);
Expand Down Expand Up @@ -298,7 +297,7 @@ class SPIFFEValidatorFactory : public CertValidatorFactory {
return std::make_unique<SPIFFEValidator>(config, stats, time_source);
}

absl::string_view name() override { return "envoy.tls.cert_validator.spiffe"; }
absl::string_view name() override { return CertValidatorNames::get().SPIFFE; }
};

REGISTER_FACTORY(SPIFFEValidatorFactory, CertValidatorFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,39 @@ name: envoy.tls.cert_validator.spiffe
EXPECT_EQ(2, stats().fail_verify_error_.value());
}

TEST_F(TestSPIFFEValidator, TestDoVerifyCertChainIntermediateCerts) {
initialize(TestEnvironment::substitute(R"EOF(
name: envoy.tls.cert_validator.spiffe
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig
trust_domains:
- name: example.com
trust_bundle:
filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/ca_cert.pem"
)EOF"));

X509StorePtr ssl_ctx = X509_STORE_new();

// Chain contains workload, intermediate, and ca cert, so it should be accepted.
auto cert = readCertFromFile(TestEnvironment::substitute(
"{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/spiffe_san_signed_by_intermediate_cert.pem"));
auto intermediate_ca_cert = readCertFromFile(TestEnvironment::substitute(
"{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/intermediate_ca_cert.pem"));
auto ca_cert = readCertFromFile(TestEnvironment::substitute(
"{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/ca_cert.pem"));

STACK_OF(X509) *intermediates = sk_X509_new_null();
sk_X509_push(intermediates, ca_cert.release());
sk_X509_push(intermediates, intermediate_ca_cert.release());
sk_X509_push(intermediates, cert.get()); // not necessary, but reflects real-world use-case

X509StoreContextPtr store_ctx = X509_STORE_CTX_new();
EXPECT_TRUE(X509_STORE_CTX_init(store_ctx.get(), ssl_ctx.get(), cert.get(), intermediates));
EXPECT_TRUE(validator().doVerifyCertChain(store_ctx.get(), nullptr, *cert, nullptr));

sk_X509_pop_free(intermediates, X509_free);
}

TEST_F(TestSPIFFEValidator, TestDoVerifyCertChainMultipleTrustDomain) {
initialize(TestEnvironment::substitute(R"EOF(
name: envoy.tls.cert_validator.spiffe
Expand Down
6 changes: 6 additions & 0 deletions test/extensions/transport_sockets/tls/test_data/certs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,12 @@ generate_x509_cert spiffe_san ca
generate_rsa_key non_spiffe_san
generate_x509_cert non_spiffe_san ca

cp -f spiffe_san_cert.cfg spiffe_san_signed_by_intermediate_cert.cfg
generate_rsa_key spiffe_san_signed_by_intermediate
generate_x509_cert spiffe_san_signed_by_intermediate intermediate_ca
rm -f spiffe_san_signed_by_intermediate_cert.cfg
cat spiffe_san_signed_by_intermediate_cert.pem intermediate_ca_cert.pem ca_cert.pem > spiffe_san_signed_by_intermediate_cert_chain.pem

cp -f spiffe_san_cert.cfg expired_spiffe_san_cert.cfg
generate_rsa_key expired_spiffe_san
generate_x509_cert expired_spiffe_san ca -365
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEUjCCAzqgAwIBAgIUYXWgru9mpTn6Ag1U4rb+6yHMfaUwDQYJKoZIhvcNAQEL
BQAwgYMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
DA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVu
Z2luZWVyaW5nMR0wGwYDVQQDDBRUZXN0IEludGVybWVkaWF0ZSBDQTAeFw0yMTEw
MjkxMjEzNTdaFw0yMzEwMjkxMjEzNTdaMHoxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
DApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARM
eWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2luZWVyaW5nMRQwEgYDVQQDDAtUZXN0IFNl
cnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANb5x7HerRCkhw7+
UOgDaldCI/G9DMqEedvTTiSqxoOfKKKrzVop4dzrJbxfDM2Up5VADLz/1Zcc718R
S4F2dVGozU0RnUZGl+hwM97FgE+Hd+aoT6jJRIYKw6niHq2bqxppWyavfu3D0Zt6
J3Qab+6twlDhPVZrCHmpWHchC9emJeOhiK3kyj0i95krQ7YWg9Z4vMpN1RAwLxv6
Mkcmo1eoi45hNI+//I1ooF9k6MrSP/1i8kPmjRbxbgko+CM0qOfPpKhC8lXrO5db
1EEtguLBehmOBnnJUzWyIT8qrbiE5GL41+82NIm1Xhom9tZB+uWaZu2trjCnlY7W
jm49LUcCAwEAAaOBxTCBwjAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIF4DAdBgNV
HSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwRgYDVR0RBD8wPYIJZW52b3kuY29t
hh1zcGlmZmU6Ly9leGFtcGxlLmNvbS93b3JrbG9hZIERZW52b3lAZXhhbXBsZS5j
b20wHQYDVR0OBBYEFN5CxzxsYI1NAdO4UIurG6O1Q9XaMB8GA1UdIwQYMBaAFKbQ
dxTWui6GjBedEeOPwmCUdTCwMA0GCSqGSIb3DQEBCwUAA4IBAQCPEaiqpS6i6st8
3a6TTjDwDomNrqY4uqot6itqTMUrQCG2p4ew9uff8aIwGut/Utrh5TxVdGmfRU/T
KE4U+5z9mq5RfCZkSQGI+i2rnKdAFEjtHoN9KmnArLgO2t6xG4pkfc+RlER8nmTP
HPt6pFKSup6DpwicV5ThQgKxii+EmS3QbfMGHV1JtlPFtEXwUS7eF+eFhdoRMmWh
fRkmdkKv3ZVGGWScGtupx2nbCtbcVZ0ThOeuvDlsnqvVQvdYS651GqakMwJvFxQ2
dAdUKV8PNHt1C6G/EzM3sOIWp6K3kJ2J+aulkW58s00pZ53zUmCbKpZyvHs4DevU
G375NUqI
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
-----BEGIN CERTIFICATE-----
MIIEUjCCAzqgAwIBAgIUYXWgru9mpTn6Ag1U4rb+6yHMfaUwDQYJKoZIhvcNAQEL
BQAwgYMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
DA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVu
Z2luZWVyaW5nMR0wGwYDVQQDDBRUZXN0IEludGVybWVkaWF0ZSBDQTAeFw0yMTEw
MjkxMjEzNTdaFw0yMzEwMjkxMjEzNTdaMHoxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
DApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARM
eWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2luZWVyaW5nMRQwEgYDVQQDDAtUZXN0IFNl
cnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANb5x7HerRCkhw7+
UOgDaldCI/G9DMqEedvTTiSqxoOfKKKrzVop4dzrJbxfDM2Up5VADLz/1Zcc718R
S4F2dVGozU0RnUZGl+hwM97FgE+Hd+aoT6jJRIYKw6niHq2bqxppWyavfu3D0Zt6
J3Qab+6twlDhPVZrCHmpWHchC9emJeOhiK3kyj0i95krQ7YWg9Z4vMpN1RAwLxv6
Mkcmo1eoi45hNI+//I1ooF9k6MrSP/1i8kPmjRbxbgko+CM0qOfPpKhC8lXrO5db
1EEtguLBehmOBnnJUzWyIT8qrbiE5GL41+82NIm1Xhom9tZB+uWaZu2trjCnlY7W
jm49LUcCAwEAAaOBxTCBwjAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIF4DAdBgNV
HSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwRgYDVR0RBD8wPYIJZW52b3kuY29t
hh1zcGlmZmU6Ly9leGFtcGxlLmNvbS93b3JrbG9hZIERZW52b3lAZXhhbXBsZS5j
b20wHQYDVR0OBBYEFN5CxzxsYI1NAdO4UIurG6O1Q9XaMB8GA1UdIwQYMBaAFKbQ
dxTWui6GjBedEeOPwmCUdTCwMA0GCSqGSIb3DQEBCwUAA4IBAQCPEaiqpS6i6st8
3a6TTjDwDomNrqY4uqot6itqTMUrQCG2p4ew9uff8aIwGut/Utrh5TxVdGmfRU/T
KE4U+5z9mq5RfCZkSQGI+i2rnKdAFEjtHoN9KmnArLgO2t6xG4pkfc+RlER8nmTP
HPt6pFKSup6DpwicV5ThQgKxii+EmS3QbfMGHV1JtlPFtEXwUS7eF+eFhdoRMmWh
fRkmdkKv3ZVGGWScGtupx2nbCtbcVZ0ThOeuvDlsnqvVQvdYS651GqakMwJvFxQ2
dAdUKV8PNHt1C6G/EzM3sOIWp6K3kJ2J+aulkW58s00pZ53zUmCbKpZyvHs4DevU
G375NUqI
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID4zCCAsugAwIBAgIJAPDlREG4TLxSMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp
c2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2luZWVyaW5nMRAw
DgYDVQQDDAdUZXN0IENBMB4XDTIwMDgyNzE1MTA1MVoXDTIyMDgyNzE1MTA1MVow
gYMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T
YW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2lu
ZWVyaW5nMR0wGwYDVQQDDBRUZXN0IEludGVybWVkaWF0ZSBDQTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAKGa0pSi8MI88LdnHT8oZJVDpZ6qa9ooYP6m
3S+xIxRBOVOGEs0a1dxko5iAfWgJJRF8igT1bRQAlNsnK/lZpGOOo8txjWsTQPFD
FLUSVVn78lnXvyYlIhAMqmhIAmSK+qo02TcsncBNa/iCT9aH9SEf0a7xjiAcyfm6
3XHScpPC0o47tICqKnkMCJvOxi4yKM0SWIxNpnoXq/ixxcipsA8QFQ4GU2r9LBSB
8+7+couSKdPDR0AvDA/t47P8pNxQHCCzvspEtX5wGMEOVVhAsh1GgwMNyYh9IbUO
TkHqR45D2ky+x6emPDPdAgqzh4xDpMR4V+hsPQ/GWdXpKLfKjdECAwEAAaNmMGQw
EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFKbQ
dxTWui6GjBedEeOPwmCUdTCwMB8GA1UdIwQYMBaAFNPBCyPjw6jyMr5fVME/eDgT
VQPZMA0GCSqGSIb3DQEBCwUAA4IBAQBFEUnhtsWzHM/xoy/vlntkdau/TYrpLQkE
KXIeDbjtjLnMBKXu5z3epKWrSV12kEQWrkARNTuhW4+5XkZUA9gb2MPMXh2yse4u
Oy3rRhhzbXMas45IFbXqnI+xuS/99vJQrhjXGB49dbUV9P9dJ4hj2Uc27UmAx/zB
6MHKDXhpRw/R6MXPtpQpZjDTEA4QU2yuwHWOZ56QHJ/aj0QZJvSbdK6DDY7VSKEC
2yCX1d+S0lF5Hcgrhhi4Me2sKA7JQwKLDDlXMOKpcI0vMZAoKXPbA+tVBQUZICZU
/t9YW49y8KWCjXK113JDIxQOtTCV8SaLnV9+qL+3ckbih6gz76Vw
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID3TCCAsWgAwIBAgIUb7lp5EdaTy6KCfKjvbTXaDHYMtgwDQYJKoZIhvcNAQEL
BQAwdjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
DVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBEx5ZnQxGTAXBgNVBAsMEEx5ZnQgRW5n
aW5lZXJpbmcxEDAOBgNVBAMMB1Rlc3QgQ0EwHhcNMjAwODIwMTY1NzQ2WhcNMjIw
ODIwMTY1NzQ2WjB2MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEW
MBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UECwwQ
THlmdCBFbmdpbmVlcmluZzEQMA4GA1UEAwwHVGVzdCBDQTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAKmqkuzB22hUhvai26KtFtia0yfQgyBYtWx8MCxw
1XI+CeOC1JsYbEozm2ze+ytxlS+1Yr8U2Sb7D43AuVd27HeQllMT7DP5JV6mQkQG
4ms1yTz8oN4H1V6au3Gy6K8BZOf7rY+1yiJMzG2yqC3ipShD8up/RXmXQWInSv9G
U6lU7ZK+bK6IezsPEUPiFVzfxspQDMCSLSLi3jZmD4S0Uld4d6pFG21pWBSSRxI8
d8xJkqqOAMc400V65rnaHm96uwvcjeWZGiI50HwhfTVjiztzcCblN1qt/Es7yhBs
eQFr+2b8N04zCMDLlL7grn9imW/XLiVSRvVrkXDyqIUmwRECAwEAAaNjMGEwDwYD
VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNPBCyPjw6jy
Mr5fVME/eDgTVQPZMB8GA1UdIwQYMBaAFNPBCyPjw6jyMr5fVME/eDgTVQPZMA0G
CSqGSIb3DQEBCwUAA4IBAQAVnbqXnnVFGz83S2tkry/Xq0wviklVWOsIn+emjV13
h4SC4WgQWHViIwVz1XjUvpguIgMg+R1uE9cPrs0G2Pi6JkrzJB3Btre6QeRvMGhN
T4HsEdyfg2KvcNj0VhkHAFD53R0g9UZywxyVcTFwjFDE4ELUSRGcYsF3lH0AU/cP
hMLm0TBsUaPDxHUSpKqn63oAjKh2BN9r8Ecg9ii7I0nYakWtjz9W8e9CPTrVHxrl
V6/lXdvkXEEtblCnNonawqYSbd4Rqs7duk2jgVX9zjguA57/0wmxeb+dDUYvVFMp
xFQdzaxezPS7myjbpTP+TUyWhbTZDJLKxhMf9LAOV3A1
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// NOLINT(namespace-envoy)
constexpr char TEST_SPIFFE_SAN_SIGNED_BY_INTERMEDIATE_CERT_256_HASH[] =
"ebdaf34636d5c934f87218b41e892a28cb755f31c76e9908a7a774d12af81b6c";
constexpr char TEST_SPIFFE_SAN_SIGNED_BY_INTERMEDIATE_CERT_1_HASH[] = "ed905c1fff40bb9d50a614d1fe6232ae77ca720f";
constexpr char TEST_SPIFFE_SAN_SIGNED_BY_INTERMEDIATE_CERT_SPKI[] = "Pg5Hx7VWs6yWnvEsJo+RVag88rHkEfaNDtyWjmLxZOQ=";
constexpr char TEST_SPIFFE_SAN_SIGNED_BY_INTERMEDIATE_CERT_SERIAL[] = "6175a0aeef66a539fa020d54e2b6feeb21cc7da5";
constexpr char TEST_SPIFFE_SAN_SIGNED_BY_INTERMEDIATE_CERT_NOT_BEFORE[] = "Oct 29 12:13:57 2021 GMT";
constexpr char TEST_SPIFFE_SAN_SIGNED_BY_INTERMEDIATE_CERT_NOT_AFTER[] = "Oct 29 12:13:57 2023 GMT";
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA1vnHsd6tEKSHDv5Q6ANqV0Ij8b0MyoR529NOJKrGg58ooqvN
Winh3OslvF8MzZSnlUAMvP/VlxzvXxFLgXZ1UajNTRGdRkaX6HAz3sWAT4d35qhP
qMlEhgrDqeIerZurGmlbJq9+7cPRm3ondBpv7q3CUOE9VmsIealYdyEL16Yl46GI
reTKPSL3mStDthaD1ni8yk3VEDAvG/oyRyajV6iLjmE0j7/8jWigX2ToytI//WLy
Q+aNFvFuCSj4IzSo58+kqELyVes7l1vUQS2C4sF6GY4GeclTNbIhPyqtuITkYvjX
7zY0ibVeGib21kH65Zpm7a2uMKeVjtaObj0tRwIDAQABAoIBAQCx0hcO2ESLmaxm
CJNf90NFPl6BHYGxGve5kAX5apGeWk7AkB/izvYXSSMDuBPdEXO1jy96PpyszLBs
EOBGDHhqvZhkgYd4k/gfuoANa40BO+tADkUmNqXJwqmqonIB5NwZksBlNZFmly2Q
z/BGp3+jDHPJdybHju2JxTx5/gnPrAlcxn7FGzXWOH7iVJJpVamPiHVaOFt9mZHY
6ITgLCsjMyjdNhuE20yJyUl7TCwbdP8m5W2j1prVaFe/tc2py5xUOPYFwYvjpH7K
w7kLm9C74iBoQhziI99G1ryQW0pY5var/RKEAjpPjGulGo6fFNUQjGvofPM/lZtK
PtvPClixAoGBAOuJ1yZ30bL3ysRvlfczDJULpzj8tBejJsCvxK69RWGzoKh/Kptx
ik2uI9vTo36+nSBzcXSWHlGrx5za2shjE/ivVV5uNLYCZpHOZ2vm5EtWMCBOPmZ+
wydcOnfHUAC2uVsDx/JgNvO4uozqurP+chrS3WcTZZFRxzQWFQWkHmbDAoGBAOmm
pKdsm9FwZs5ANLkIUqJefxiEWTIk9XyT/4AUG73Xm3EnamPCkqaQqSjT2VTHpJGC
WNU3XNn+9W5ZyooBpjyPm9vUCRIwBeTKMvE11asUJw7i03V1h0Y8GVI4ytL+LlSq
ZpjhiACS/YqAwpjNKTGQwKlty5NVZ3IuH3Pjhp8tAoGBALmAywkJ7wbTr0d8VpDl
DLDKB76TD8daAGhbRj0U5fLnxM1Psh/QkUtSrf0wtqBYwWlQYneez2wlLUX0+8A8
f/spI8QGac87HssQ01Ug+IX48FhRJ0YT6eEy+v1g5Tparqrm1G+opT7YK1xWdgrS
h81ma2cF2MVVsdzs00upESR/AoGAIhVE/4dAU5Tp6jxDdJpaM4VFVPY5bK8ngDy2
kKBeS5sf+ameQ18mtVV015fPpCZbQz6YZsHksYgXlTlT6j3DWiI4wiB0EksfEPjN
5ZHM0V/nMqyz2/aA/SXXK79NFuotJ/yTasm7ZRoMEiAmQtPqpmhPMmfpwlw68tT3
kZgnEyECgYEAu1E2pv47b63MA7EotEwQr5FpkOa4tc1p77/Es7/9tsoxlNKJHu5I
csezg38mrb86NFREoC/29W0Pn57dM9201Rd7LukADx4eKMROXP5n/oe4o9T19GDZ
w4BPPQ0g7IdmIoLY5v8sI0yaKT7BeOv3mJYGwEh+3FSVg6XrktxXRpE=
-----END RSA PRIVATE KEY-----

0 comments on commit 0150925

Please sign in to comment.