The following diff extracts the EKM value for a given TLS connection and then surfaces that to LUA (which emits the EKM as a header to the backend)
the LUA config will log the EKM in trace logs
# envoy -c envoy_server.yaml -l trace
[2025-04-04 08:36:29.396][3334775][info][lua] [source/extensions/filters/common/lua/lua.cc:26] script log: >>>>>>>>>>>> EKM: XGurfnlqXyjXphhJrrCmHRoKXAwC7CjrD7vixHdqOIo=
which has the same derived EKM value as a sample client app (eg, golang)
$ go run main.go
EKM EXPORTER-my_ekm: XGurfnlqXyjXphhJrrCmHRoKXAwC7CjrD7vixHdqOIo=
200 OK
{
"args": {},
"headers": {
"Accept-Encoding": "gzip",
"Ekm": "XGurfnlqXyjXphhJrrCmHRoKXAwC7CjrD7vixHdqOIo=",
"Host": "httpbin.org",
"User-Agent": "Go-http-client/1.1",
"X-Amzn-Trace-Id": "Root=1-67efd24d-09847a992febb3400b88e963",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000"
},
"url": "https://httpbin.org/get"
}
Also see
ekm.diff
(from envoy commit9faa0a3c19018bd23985d1e0aaa94cd5546c9c35
)
diff --git a/envoy/ssl/connection.h b/envoy/ssl/connection.h
index b9e968a524..1398c9f69c 100644
--- a/envoy/ssl/connection.h
+++ b/envoy/ssl/connection.h
@@ -225,6 +225,8 @@ public:
* @return std::string the SNI used to establish the connection.
**/
virtual const std::string& sni() const PURE;
+
+ virtual const std::string& ekm() const PURE;
};
using ConnectionInfoConstSharedPtr = std::shared_ptr<const ConnectionInfo>;
diff --git a/source/common/tls/connection_info_impl_base.cc b/source/common/tls/connection_info_impl_base.cc
index 24019df89b..251dcabb87 100644
--- a/source/common/tls/connection_info_impl_base.cc
+++ b/source/common/tls/connection_info_impl_base.cc
@@ -7,6 +7,8 @@
#include "absl/strings/str_replace.h"
#include "openssl/err.h"
+
+#include "openssl/ssl.h"
#include "openssl/safestack.h"
#include "openssl/x509v3.h"
#include "utility.h"
@@ -110,6 +112,31 @@ const std::string& ConnectionInfoImplBase::sha256PeerCertificateDigest() const {
});
}
+size_t string_length(const uint8_t* str) {
+ size_t length = 0;
+ while (str[length] != '\0') {
+ length++;
+ }
+ return length;
+}
+
+const std::string& ConnectionInfoImplBase::ekm() const {
+ return getCachedValueOrCreate<std::string>(CachedValueTag::EKM, [](SSL* ssl) {
+ const char *klabel = "EXPORTER-my_ekm";
+ const uint8_t* kcontext = reinterpret_cast<const uint8_t*>("my_context");
+
+ size_t size = 32;
+ uint8_t* buf = new uint8_t[size];
+
+ //int rs = SSL_export_keying_material(ssl,buf,size , klabel, strlen(klabel),NULL, 0, 0);
+ int rs = SSL_export_keying_material(ssl,buf,size , klabel, strlen(klabel),kcontext, string_length(kcontext), 1);
+ if (rs == 1) {
+ return std::string(reinterpret_cast<const char*>(buf),size);
+ }
+ return std::string{};
+ });
+}
+
absl::Span<const std::string> ConnectionInfoImplBase::sha256PeerCertificateChainDigests() const {
return getCachedValueOrCreate<std::vector<std::string>>(
CachedValueTag::Sha256PeerCertificateChainDigests, [](SSL* ssl) {
diff --git a/source/common/tls/connection_info_impl_base.h b/source/common/tls/connection_info_impl_base.h
index b386e99b1d..6f08a38b4c 100644
--- a/source/common/tls/connection_info_impl_base.h
+++ b/source/common/tls/connection_info_impl_base.h
@@ -52,6 +52,7 @@ public:
const std::string& tlsVersion() const override;
const std::string& alpn() const override;
const std::string& sni() const override;
+ const std::string& ekm() const override;
virtual SSL* ssl() const PURE;
@@ -86,6 +87,7 @@ private:
IpSansPeerCertificate,
OidsPeerCertificate,
OidsLocalCertificate,
+ EKM,
};
// Retrieve the given tag from the set of cached values, or create the value via the supplied
diff --git a/source/extensions/filters/common/expr/context.cc b/source/extensions/filters/common/expr/context.cc
index 00d6139a4d..3253934b9d 100644
--- a/source/extensions/filters/common/expr/context.cc
+++ b/source/extensions/filters/common/expr/context.cc
@@ -83,6 +83,13 @@ const SslExtractorsValues& SslExtractorsValues::get() {
}
return CelValue::CreateString(&info.dnsSansPeerCertificate()[0]);
}},
+ {EKM,
+ [](const Ssl::ConnectionInfo& info) -> absl::optional<CelValue> {
+ if (info.ekm().empty()) {
+ return {};
+ }
+ return CelValue::CreateString(&info.ekm());
+ }},
{SHA256PeerCertificateDigest,
[](const Ssl::ConnectionInfo& info) -> absl::optional<CelValue> {
if (info.sha256PeerCertificateDigest().empty()) {
diff --git a/source/extensions/filters/common/expr/context.h b/source/extensions/filters/common/expr/context.h
index 48ddf83dd1..af4bb0c03c 100644
--- a/source/extensions/filters/common/expr/context.h
+++ b/source/extensions/filters/common/expr/context.h
@@ -71,6 +71,7 @@ constexpr absl::string_view DNSSanLocalCertificate = "dns_san_local_certificate"
constexpr absl::string_view DNSSanPeerCertificate = "dns_san_peer_certificate";
constexpr absl::string_view SHA256PeerCertificateDigest = "sha256_peer_certificate_digest";
constexpr absl::string_view DownstreamTransportFailureReason = "transport_failure_reason";
+constexpr absl::string_view EKM = "ekm";
// Source properties
constexpr absl::string_view Source = "source";
diff --git a/source/extensions/filters/common/lua/wrappers.cc b/source/extensions/filters/common/lua/wrappers.cc
index f440b88a71..7b6d5e1b1b 100644
--- a/source/extensions/filters/common/lua/wrappers.cc
+++ b/source/extensions/filters/common/lua/wrappers.cc
@@ -382,6 +382,12 @@ int SslConnectionWrapper::luaCiphersuiteString(lua_State* state) {
return 1;
}
+int SslConnectionWrapper::luaEKM(lua_State* state) {
+ const std::string& e = connection_info_.ekm();
+ lua_pushlstring(state, e.data(), e.size());
+ return 1;
+}
+
int SslConnectionWrapper::luaUrlEncodedPemEncodedPeerCertificate(lua_State* state) {
const std::string& peer_cert_pem = connection_info_.urlEncodedPemEncodedPeerCertificate();
lua_pushlstring(state, peer_cert_pem.data(), peer_cert_pem.size());
diff --git a/source/extensions/filters/common/lua/wrappers.h b/source/extensions/filters/common/lua/wrappers.h
index d474555272..3e28322bc9 100644
--- a/source/extensions/filters/common/lua/wrappers.h
+++ b/source/extensions/filters/common/lua/wrappers.h
@@ -170,6 +170,7 @@ public:
{"sessionId", static_luaSessionId},
{"ciphersuiteId", static_luaCiphersuiteId},
{"ciphersuiteString", static_luaCiphersuiteString},
+ {"ekm", static_luaEKM},
{"urlEncodedPemEncodedPeerCertificate", static_luaUrlEncodedPemEncodedPeerCertificate},
{"urlEncodedPemEncodedPeerCertificateChain",
static_luaUrlEncodedPemEncodedPeerCertificateChain},
@@ -300,6 +301,9 @@ private:
*/
DECLARE_LUA_FUNCTION(SslConnectionWrapper, luaCiphersuiteString);
+
+ DECLARE_LUA_FUNCTION(SslConnectionWrapper, luaEKM);
+
/**
* Returns the TLS version (e.g. TLSv1.2, TLSv1.3) used in the established TLS connection. Returns
* string if secured and nil if not.
envoy_server.yaml
node:
cluster: service_greeter
id: test-id
admin:
access_log_path: /dev/null
address:
socket_address:
address: 0.0.0.0
port_value: 9000
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8081 }
listener_filters:
- name: envoy.filters.listener.tls_inspector
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
- name: envoy.filters.listener.http_inspector
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.http_inspector.v3.HttpInspector
filter_chains:
- filter_chain_match:
server_names: ["httpbin.org"]
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain:
filename: certs/httpbin.crt
private_key:
filename: certs/httpbin.key
filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
virtual_hosts:
- name: httpbin_service
domains: ["httpbin.org"]
routes:
- match:
path: "/get"
route:
cluster: dynamic_forward_proxy_cluster
typed_per_filter_config:
envoy.filters.http.dynamic_forward_proxy:
'@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_forward_proxy.v3.PerRouteConfig
http_filters:
- name: envoy.filters.http.lua
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inlineCode: |
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
function enc(data)
return ((data:gsub('.', function(x)
local r,b='',x:byte()
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
return r;
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
if (#x < 6) then return '' end
local c=0
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
return b:sub(c+1,c+1)
end)..({ '', '==', '=' })[#data%3+1])
end
function envoy_on_request(request_handle)
local stream = request_handle:streamInfo()
ekm_header = request_handle:headers():get("X-Custom-EKM")
if ekm_header == nil then
request_handle:respond({[":status"] = "403"},"ekm not found")
else
if stream:downstreamSslConnection():ekm() ~= nil then
local peerDigest = stream:downstreamSslConnection():ekm()
local peerSig =enc(peerDigest)
request_handle:logInfo(">>>>>>>>>>>> EKM: "..peerSig)
if ekm_header == peerSig then
request_handle:headers():add("EKM", peerSig)
else
request_handle:respond({[":status"] = "403"},"ekm header mismatch")
end
else
request_handle:respond({[":status"] = "403"},"error extracting EKM")
end
end
end
- name: envoy.filters.http.dynamic_forward_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_forward_proxy.v3.FilterConfig
dns_cache_config:
name: dynamic_forward_proxy_cache_config
dns_lookup_family: V4_ONLY
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: dynamic_forward_proxy_cluster
lb_policy: CLUSTER_PROVIDED
connect_timeout: 5s
http2_protocol_options: {}
cluster_type:
name: envoy.clusters.dynamic_forward_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
dns_cache_config:
name: dynamic_forward_proxy_cache_config
dns_lookup_family: V4_ONLY
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
common_tls_context:
validation_context:
trusted_ca:
filename: /etc/ssl/certs/ca-certificates.crt
main.go
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"fmt"
"io"
"net"
"net/http"
"os"
)
var (
ekm []byte
)
func main() {
caCert, err := os.ReadFile("certs/root-ca.crt")
if err != nil {
fmt.Printf("Error reading cacert %v\n", err)
return
}
serverCertPool := x509.NewCertPool()
serverCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
ServerName: "httpbin.org",
RootCAs: serverCertPool,
}
conn, err := tls.Dial("tcp", "localhost:8081", tlsConfig)
if err != nil {
fmt.Printf("Error dialing %v\n", err)
return
}
cs := conn.ConnectionState()
ekm, err = cs.ExportKeyingMaterial("EXPORTER-my_ekm", []byte("my_context"), 32)
//ekm, err = cs.ExportKeyingMaterial("EXPORTER-my_ekm", []byte(nil), 32)
if err != nil {
fmt.Printf("Error getting ekm %v\n", err)
return
}
fmt.Printf("EKM EXPORTER-my_ekm: %s\n", base64.StdEncoding.EncodeToString(ekm))
tr := &http.Transport{
DialTLSContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
return conn, nil
},
}
client := http.Client{
Transport: tr,
}
req, err := http.NewRequest(http.MethodGet, "https://httpbin.org/get", nil)
if err != nil {
fmt.Printf("Error creating request %v\n", err)
return
}
req.Header.Add("X-Custom-EKM", base64.StdEncoding.EncodeToString(ekm))
resp, err := client.Do(req)
if err != nil {
fmt.Printf("Error making request %v\n", err)
return
}
htmlData, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Error response %v\n", err)
return
}
defer resp.Body.Close()
fmt.Printf("%v\n", resp.Status)
fmt.Printf("%s\n", string(htmlData))
}
httpbin.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 46 (0x2e)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, O=Google, OU=Enterprise, CN=Single Root CA
Validity
Not Before: Nov 17 12:17:20 2024 GMT
Not After : Nov 17 12:17:20 2034 GMT
Subject: C=US, O=Google, OU=Enterprise, CN=httpbin.org
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:a6:95:81:de:6e:97:17:6e:fb:27:6b:7c:d2:06:
a6:1e:83:eb:e5:18:75:d7:b0:01:07:36:1d:b0:11:
d3:90:d7:f1:77:68:d8:f7:b5:34:d5:40:e4:70:21:
a5:9a:67:85:ac:b6:8c:05:7d:3c:3f:e9:1c:10:e4:
bd:94:29:1d:7d:27:c4:a0:92:5d:f7:bb:b4:e2:6d:
c0:7f:e0:46:b5:61:33:b3:f3:5d:3a:80:ae:8e:3a:
88:1e:09:bc:cc:b4:43:87:14:52:2e:2b:60:08:04:
12:23:06:1f:f0:c2:75:ff:d3:56:6c:e3:3d:c3:e7:
ee:8b:df:47:2d:e8:6c:a3:21:d8:04:05:a7:2a:ed:
a2:3a:36:b6:ce:24:d3:15:cf:ff:e1:25:40:6e:67:
c8:cc:2f:22:00:87:ce:7a:0b:18:c2:ac:f4:12:9f:
c8:10:ea:6c:86:23:dc:65:95:f6:18:7a:1a:b8:33:
b2:ee:71:4e:eb:8a:28:23:7b:e4:8f:4a:18:58:15:
46:b4:7a:b4:cc:dc:71:1b:2f:3d:d1:1d:7c:3b:b0:
7b:b4:b0:51:cb:a8:5c:c0:6b:80:65:2f:3f:01:93:
6d:5f:b0:0f:82:c8:ef:63:9f:ff:60:e8:d8:6d:51:
81:2d:bb:18:73:f8:7e:61:75:67:07:a7:43:f8:87:
12:31
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature
X509v3 Basic Constraints:
CA:FALSE
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Subject Key Identifier:
DF:F9:3C:DC:25:48:11:1A:63:6B:39:D2:4D:E2:10:59:3A:BC:73:0B
X509v3 Authority Key Identifier:
EC:F0:EA:53:53:3F:9F:23:DC:C1:0E:31:10:37:07:DE:DE:E7:6E:F3
Authority Information Access:
CA Issuers - URI:http://pki.esodemoapp2.com/ca/root-ca.cer
X509v3 CRL Distribution Points:
Full Name:
URI:http://pki.esodemoapp2.com/ca/root-ca.crl
X509v3 Subject Alternative Name:
DNS:httpbin.org
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
1a:ba:c8:ad:44:8c:77:20:a4:ce:eb:14:07:52:86:31:df:1a:
bf:e4:48:c2:c2:10:dc:4d:0d:d9:6b:85:2e:ad:b9:f3:bd:f3:
f8:17:93:b9:47:2f:bf:43:72:6b:30:c5:63:2a:5c:d8:7a:7f:
14:05:27:aa:26:ed:9b:7a:0e:63:00:e4:4f:9e:58:82:df:4e:
a5:72:20:3c:df:a7:50:3f:cd:f9:54:7b:ed:b2:e4:0f:82:cd:
c1:ff:25:9b:5b:b5:7f:6b:a4:77:8e:ac:6d:b7:86:63:07:c0:
0e:e4:21:4a:f6:c1:30:3c:eb:0f:c5:95:08:2e:4e:2b:34:13:
d2:d7:fc:b5:a2:b7:96:7f:6c:51:e7:24:04:63:c3:b9:e0:58:
6a:ad:dc:e0:2f:a4:1a:45:ba:87:7e:be:67:b1:72:17:0d:ae:
be:08:1c:b9:23:e3:4d:44:05:f3:48:fe:0c:8d:2b:5c:92:23:
8d:2e:31:8f:af:eb:7c:70:53:36:f6:aa:e3:33:c3:cc:61:90:
8b:f4:47:ff:fe:fb:c6:1b:ce:25:ca:61:e8:c9:a8:e3:94:ef:
84:11:4f:b7:0e:bf:d3:87:7f:3f:bc:80:9d:ad:75:af:e9:95:
06:22:c3:c3:81:4a:1f:46:b6:69:50:79:a6:3d:d7:85:d7:cd:
03:94:69:4e
-----BEGIN CERTIFICATE-----
MIIEITCCAwmgAwIBAgIBLjANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJVUzEP
MA0GA1UECgwGR29vZ2xlMRMwEQYDVQQLDApFbnRlcnByaXNlMRcwFQYDVQQDDA5T
aW5nbGUgUm9vdCBDQTAeFw0yNDExMTcxMjE3MjBaFw0zNDExMTcxMjE3MjBaMEkx
CzAJBgNVBAYTAlVTMQ8wDQYDVQQKDAZHb29nbGUxEzARBgNVBAsMCkVudGVycHJp
c2UxFDASBgNVBAMMC2h0dHBiaW4ub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAppWB3m6XF277J2t80gamHoPr5Rh117ABBzYdsBHTkNfxd2jY97U0
1UDkcCGlmmeFrLaMBX08P+kcEOS9lCkdfSfEoJJd97u04m3Af+BGtWEzs/NdOoCu
jjqIHgm8zLRDhxRSLitgCAQSIwYf8MJ1/9NWbOM9w+fui99HLehsoyHYBAWnKu2i
Oja2ziTTFc//4SVAbmfIzC8iAIfOegsYwqz0Ep/IEOpshiPcZZX2GHoauDOy7nFO
64ooI3vkj0oYWBVGtHq0zNxxGy890R18O7B7tLBRy6hcwGuAZS8/AZNtX7APgsjv
Y5//YOjYbVGBLbsYc/h+YXVnB6dD+IcSMQIDAQABo4IBDzCCAQswDgYDVR0PAQH/
BAQDAgeAMAkGA1UdEwQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYE
FN/5PNwlSBEaY2s50k3iEFk6vHMLMB8GA1UdIwQYMBaAFOzw6lNTP58j3MEOMRA3
B97e527zMEUGCCsGAQUFBwEBBDkwNzA1BggrBgEFBQcwAoYpaHR0cDovL3BraS5l
c29kZW1vYXBwMi5jb20vY2Evcm9vdC1jYS5jZXIwOgYDVR0fBDMwMTAvoC2gK4Yp
aHR0cDovL3BraS5lc29kZW1vYXBwMi5jb20vY2Evcm9vdC1jYS5jcmwwFgYDVR0R
BA8wDYILaHR0cGJpbi5vcmcwDQYJKoZIhvcNAQELBQADggEBABq6yK1EjHcgpM7r
FAdShjHfGr/kSMLCENxNDdlrhS6tufO98/gXk7lHL79DcmswxWMqXNh6fxQFJ6om
7Zt6DmMA5E+eWILfTqVyIDzfp1A/zflUe+2y5A+CzcH/JZtbtX9rpHeOrG23hmMH
wA7kIUr2wTA86w/FlQguTis0E9LX/LWit5Z/bFHnJARjw7ngWGqt3OAvpBpFuod+
vmexchcNrr4IHLkj401EBfNI/gyNK1ySI40uMY+v63xwUzb2quMzw8xhkIv0R//+
+8YbziXKYejJqOOU74QRT7cOv9OHfz+8gJ2tda/plQYiw8OBSh9GtmlQeaY914XX
zQOUaU4=
-----END CERTIFICATE-----
httpbin.key
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmlYHebpcXbvsn
a3zSBqYeg+vlGHXXsAEHNh2wEdOQ1/F3aNj3tTTVQORwIaWaZ4WstowFfTw/6RwQ
5L2UKR19J8Sgkl33u7TibcB/4Ea1YTOz8106gK6OOogeCbzMtEOHFFIuK2AIBBIj
Bh/wwnX/01Zs4z3D5+6L30ct6GyjIdgEBacq7aI6NrbOJNMVz//hJUBuZ8jMLyIA
h856CxjCrPQSn8gQ6myGI9xllfYYehq4M7LucU7riigje+SPShhYFUa0erTM3HEb
Lz3RHXw7sHu0sFHLqFzAa4BlLz8Bk21fsA+CyO9jn/9g6NhtUYEtuxhz+H5hdWcH
p0P4hxIxAgMBAAECggEADHMCZl7h7EanPuItzR1hl0i5HaEnF2QoI4OUEuc2Ji45
NbkQc+ynIuPLXqTpFSG07/wheTyLfuQ7LHkHwPWUpliNPYnKu3ub8EsO9o+KgT4f
KMzgdAGPagIuT35fTXYQUN1AKgKkVd0GBPeNdgb2XhTLce5GnKgt3+ajEWd8DPHY
wCsT7CSSTDGvGq0EZ1E2KK+hDM3Wj5kn65jX+AXVyDppuJZUqH8ycx9g+oBeE8Y0
n4Edno4ghM9xQDW/Vrj0nxI2pNas9GviyswwhRHCqV5uZ0HJBYeSsACiaBBd+094
slWC1YSpMFsjXj0A1LIyMKmLrVZNim95ongAHRRq5QKBgQDmOtR1kcX51EbdWFrk
aqF18GnuawHxtCblUXqdWuWV4JKfj7D2nu/AsMxUxyMlbcDDAFsQiW4oIcY16AhF
Dw72+49VrU+QA6wQyPCBCdIb2TsXUwmo1qAP8ldfZYgUaki4CHPabBk7aY2yvSbO
eMZtWI6wCl5vS91vXoQBB85OJQKBgQC5OuzY8EzxE8jDStfzBAG7iSwGocdGyGOg
1LKN3eLQMtx1n7DumBqVjNPpUNZUutw8zUA859QXsuMA+ieidKauhnbt2ZYfb7Mr
Aq4AVeiW2uhKgvZru9u+FLCt06rgBSaDBBc0jSQYVQ32YFZ6nEXTvtDyGExu1BmQ
gs30T4XYHQKBgEI9mvNYxcVjth/pU/10UJBGY7QdRantU2OXVdgAVx4QRx9xkFDk
2cZvF9sskIgsU9HHQGw5nmAdl5Ha+MYl1wBo0IyuGL4u0ErkBY6a7MDmd4H2ekkB
t3vfFhR0efqludZ5WBv4Dipx7DsJASlWxoCfgi5UTWdoRIXOg9xoCouhAoGAOHEu
LsS6jVNb/7ZUq2ZzKLQZyEOPt4/kW+O0LOqJ7Ksy5lysy2dp4lwxTo0lYlg2OAjL
JEP4KuiFp4ySezxUdiXfI4cD6bxduiNs5glHgIBf/CR/9kAeK4Oeerle/jhTjeS3
NXo0n317bbHZaC8qT+V7QeoJkFPtHk3deC6rODkCgYEA33AxdMfl0pgZpYxI/Dv4
7DMG1XUuomgzqymxmNyoyZPsx5QUm5NUAxzkv8ijwDUO9ymXvZWSh4GECQjwbtdI
YQgcsCVBsvsHtoq8ZI4tGK0uuNSAruWQ8ATABFbM2KQvBiwZ+J0IF1yNy2KLNX7m
4c9dGvwi/BTxQyMEWUxzZtg=
-----END PRIVATE KEY-----
root-ca.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, O=Google, OU=Enterprise, CN=Single Root CA
Validity
Not Before: Dec 27 17:38:02 2023 GMT
Not After : Dec 26 17:38:02 2033 GMT
Subject: C=US, O=Google, OU=Enterprise, CN=Single Root CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:bd:4e:4b:a5:b0:44:c4:8a:e0:82:cf:f2:e2:30:
02:08:9b:c3:31:82:29:7c:49:91:24:a9:eb:f3:6e:
2e:f8:97:51:6d:b2:54:be:8e:e9:18:18:e4:24:6f:
4e:9e:7c:82:c3:d1:1b:0a:7c:f1:6f:90:37:3a:5c:
26:ff:4a:2b:72:53:dc:7a:22:8f:e5:ab:14:13:e9:
44:be:03:60:3a:d0:dd:e5:95:61:40:84:5b:e7:19:
01:5f:c6:87:5d:47:fa:e2:0a:6e:bd:9d:7b:b1:88:
ac:8f:a3:8f:97:b7:6d:57:03:a3:6c:bf:7b:25:1e:
f0:ba:09:c2:47:7e:0a:eb:b8:c3:9f:e7:87:c9:a1:
4b:0f:70:ca:75:0b:ee:b3:8e:a3:9a:92:f6:18:65:
5a:e0:37:8c:ef:48:bb:cd:45:35:85:11:19:dc:d8:
f1:6f:8d:a5:d7:ef:48:15:9f:1a:47:fa:16:dd:77:
29:69:06:6d:1e:d9:1d:4f:86:61:df:6b:b8:91:f1:
43:b6:80:e4:65:20:66:90:aa:d1:4d:a6:3d:39:7c:
a2:19:8e:16:a7:61:a2:f2:18:4b:13:25:ee:1b:72:
38:b9:8f:3c:50:ad:cd:88:fa:dc:08:a5:67:8e:0f:
8a:c8:66:8d:13:50:24:c3:1f:a8:c7:a9:56:7f:c3:
15:3f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
EC:F0:EA:53:53:3F:9F:23:DC:C1:0E:31:10:37:07:DE:DE:E7:6E:F3
X509v3 Authority Key Identifier:
EC:F0:EA:53:53:3F:9F:23:DC:C1:0E:31:10:37:07:DE:DE:E7:6E:F3
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
77:aa:56:03:04:39:86:fc:c8:69:8b:c3:02:ae:87:43:e9:af:
66:60:fd:f0:df:98:3e:f3:f1:ea:bb:8e:1a:40:ce:18:d2:b4:
28:93:e4:4d:1c:15:14:89:23:85:10:7f:cf:f6:37:b4:64:c8:
8e:57:67:41:2e:08:0f:19:87:e6:7a:8a:4a:e6:93:92:96:53:
27:19:21:24:38:c7:2f:43:67:be:a4:85:3c:e4:b0:10:d7:14:
76:48:e8:81:e0:ba:7a:26:c4:f3:1d:ba:61:bd:cd:96:4e:9d:
f6:b6:e5:ad:6a:79:c0:89:01:a9:1e:9b:54:95:97:6e:fb:99:
17:84:7f:b6:a0:05:a1:0b:41:a6:c8:d3:a4:08:f6:d6:ff:6f:
1e:94:87:d0:c3:4b:da:8a:4a:aa:42:a8:60:2c:55:25:b1:62:
bc:a3:54:0e:de:4a:36:07:78:ed:2a:ed:d0:e2:d8:45:45:f3:
4e:4f:1c:3f:a5:5d:59:bf:5e:66:f4:f6:77:1b:87:90:c0:78:
94:aa:a8:1b:83:6d:0f:f9:83:32:5b:18:78:1b:99:46:61:64:
46:61:80:bd:d8:3d:6a:e5:6f:cf:37:c6:bf:32:c9:a0:6e:f4:
95:4e:de:07:35:af:2e:d5:1f:9d:6c:fb:b4:59:db:90:bb:b9:
44:43:40:92
-----BEGIN CERTIFICATE-----
MIIDdjCCAl6gAwIBAgIBATANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJVUzEP
MA0GA1UECgwGR29vZ2xlMRMwEQYDVQQLDApFbnRlcnByaXNlMRcwFQYDVQQDDA5T
aW5nbGUgUm9vdCBDQTAeFw0yMzEyMjcxNzM4MDJaFw0zMzEyMjYxNzM4MDJaMEwx
CzAJBgNVBAYTAlVTMQ8wDQYDVQQKDAZHb29nbGUxEzARBgNVBAsMCkVudGVycHJp
c2UxFzAVBgNVBAMMDlNpbmdsZSBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAvU5LpbBExIrggs/y4jACCJvDMYIpfEmRJKnr824u+JdRbbJU
vo7pGBjkJG9OnnyCw9EbCnzxb5A3Olwm/0orclPceiKP5asUE+lEvgNgOtDd5ZVh
QIRb5xkBX8aHXUf64gpuvZ17sYisj6OPl7dtVwOjbL97JR7wugnCR34K67jDn+eH
yaFLD3DKdQvus46jmpL2GGVa4DeM70i7zUU1hREZ3Njxb42l1+9IFZ8aR/oW3Xcp
aQZtHtkdT4Zh32u4kfFDtoDkZSBmkKrRTaY9OXyiGY4Wp2Gi8hhLEyXuG3I4uY88
UK3NiPrcCKVnjg+KyGaNE1Akwx+ox6lWf8MVPwIDAQABo2MwYTAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7PDqU1M/nyPcwQ4xEDcH
3t7nbvMwHwYDVR0jBBgwFoAU7PDqU1M/nyPcwQ4xEDcH3t7nbvMwDQYJKoZIhvcN
AQELBQADggEBAHeqVgMEOYb8yGmLwwKuh0Ppr2Zg/fDfmD7z8eq7jhpAzhjStCiT
5E0cFRSJI4UQf8/2N7RkyI5XZ0EuCA8Zh+Z6ikrmk5KWUycZISQ4xy9DZ76khTzk
sBDXFHZI6IHgunomxPMdumG9zZZOnfa25a1qecCJAakem1SVl277mReEf7agBaEL
QabI06QI9tb/bx6Uh9DDS9qKSqpCqGAsVSWxYryjVA7eSjYHeO0q7dDi2EVF805P
HD+lXVm/Xmb09ncbh5DAeJSqqBuDbQ/5gzJbGHgbmUZhZEZhgL3YPWrlb883xr8y
yaBu9JVO3gc1ry7VH51s+7RZ25C7uURDQJI=
-----END CERTIFICATE-----