also see https://github.com/salrashid123/go_ekm_tls
$ gcc server.c -lcrypto -lssl -o server
$ ./server
OpenSSL 3.4.1 11 Feb 2025 (Library: OpenSSL 3.3.3 11 Feb 2025)
built on: Sat Mar 29 11:36:38 2025 UTC
platform: linux-x86_64
options: bn(64,64)
EKM
B8 18 3B 0A 5B 16 FF 8C 9A 6E D8 D8 63 84 74 36 59 40 35 C2
$ gcc client.c -lcrypto -lssl -o client
$ ./client
OpenSSL 3.4.1 11 Feb 2025 (Library: OpenSSL 3.3.3 11 Feb 2025)
built on: Sat Mar 29 11:36:38 2025 UTC
platform: linux-x86_64
options: bn(64,64)
EKM
B8 18 3B 0A 5B 16 FF 8C 9A 6E D8 D8 63 84 74 36 59 40 35 C2
test
server.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#include <stdlib.h>
void handleErrors(void)
{
unsigned long errCode;
printf("An error occurred\n");
while(errCode = ERR_get_error())
{
char *err = ERR_error_string(errCode, NULL);
printf("%s\n", err);
}
abort();
}
void configure_context(SSL_CTX *ctx)
{
/* Set the key and cert */
if (SSL_CTX_use_certificate_file(ctx, "cert.pem", SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
if (SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) <= 0 ) {
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
}
int main(int argc, char **argv)
{
int sock;
SSL_CTX *ctx;
printf("%s (Library: %s)\n",
OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION));
printf("%s\n", OpenSSL_version(OPENSSL_BUILT_ON));
printf("%s\n", OpenSSL_version(OPENSSL_PLATFORM));
printf("options: ");
printf(" %s", BN_options());
printf("\n");
ctx = SSL_CTX_new(TLS_server_method());
if (!ctx) {
perror("Unable to create SSL context");
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
// SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
// SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
configure_context(ctx);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8081);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Unable to create socket");
exit(EXIT_FAILURE);
}
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("Unable to bind");
exit(EXIT_FAILURE);
}
if (listen(sock, 1) < 0) {
perror("Unable to listen");
exit(EXIT_FAILURE);
}
while(1) {
struct sockaddr_in addr;
unsigned int len = sizeof(addr);
SSL *ssl;
const char reply[] = "test\n";
int client = accept(sock, (struct sockaddr*)&addr, &len);
if (client < 0) {
perror("Unable to accept");
exit(EXIT_FAILURE);
}
ssl = SSL_new(ctx);
SSL_set_fd(ssl, client);
if (SSL_accept(ssl) <= 0) {
ERR_print_errors_fp(stderr);
} else {
const char *klabel = "EXPORTER-my_ekm";
unsigned char *out = (unsigned char*)malloc(32 * sizeof(unsigned char));
const char *context = "mycontext";
printf("EKM\n");
int rs = SSL_export_keying_material(ssl,out, 32 , klabel, strlen(klabel),context, strlen(context), 1);
if (rs == 1) {
for (size_t i = 0; i < 20; ++i) {
printf("%02X ", out[i]);
}
printf("\n");
} else {
printf("error getting ekm\n");
}
SSL_write(ssl, reply, strlen(reply));
}
SSL_shutdown(ssl);
SSL_free(ssl);
close(client);
}
close(sock);
SSL_CTX_free(ctx);
}
client.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#include <stdlib.h>
void handleErrors(void)
{
unsigned long errCode;
printf("An error occurred\n");
while(errCode = ERR_get_error())
{
char *err = ERR_error_string(errCode, NULL);
printf("%s\n", err);
}
abort();
}
int main(int argc, char **argv)
{
SSL_CTX *ctx;
BIO *web = NULL, *out = NULL;
SSL *ssl = NULL;
long res = 1;
printf("%s (Library: %s)\n",
OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION));
printf("%s\n", OpenSSL_version(OPENSSL_BUILT_ON));
printf("%s\n", OpenSSL_version(OPENSSL_PLATFORM));
printf("options: ");
printf(" %s", BN_options());
printf("\n");
ctx = SSL_CTX_new(TLS_client_method());
if (!ctx) {
perror("Unable to create SSL context");
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
// SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
// SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
web = BIO_new_ssl_connect(ctx);
if(!(web != NULL)) handleErrors();
res = BIO_set_conn_hostname(web, "127.0.0.1:8081");
if(!(1 == res)) handleErrors();
BIO_get_ssl(web, &ssl);
if(!(ssl != NULL)) handleErrors();
out = BIO_new_fp(stdout, BIO_NOCLOSE);
if(!(NULL != out)) handleErrors();
res = BIO_do_connect(web);
if(!(1 == res)) handleErrors();
res = BIO_do_handshake(web);
if(!(1 == res)) handleErrors();
const char *klabel = "EXPORTER-my_ekm";
const char *context = "mycontext";
unsigned char *outc = (unsigned char*)malloc(32 * sizeof(unsigned char));
printf("EKM\n");
int rs = SSL_export_keying_material(ssl,outc, 32 , klabel, strlen(klabel),context, strlen(context), 1);
if (rs == 1) {
for (size_t i = 0; i < 20; ++i) {
printf("%02X ", outc[i]);
}
printf("\n");
} else {
printf("error getting ekm\n");
}
int len = 0;
do
{
char buff[1536] = {};
len = BIO_read(web, buff, sizeof(buff));
if(len > 0)
BIO_write(out, buff, len);
} while (len > 0 || BIO_should_retry(web));
if(out)
BIO_free(out);
if(web != NULL)
BIO_free_all(web);
SSL_CTX_free(ctx);
}
cert.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 7 (0x7)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, O=Google, OU=Enterprise, CN=Single Root CA
Validity
Not Before: Mar 29 19:06:50 2024 GMT
Not After : Mar 29 19:06:50 2034 GMT
Subject: C=US, O=Google, OU=Enterprise, CN=http.domain.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:b8:35:f3:67:2c:c8:f3:b2:ed:4d:3a:5e:7b:8b:
2e:59:2d:d5:d7:9f:a9:d8:46:c0:ad:bf:c4:1d:09:
11:03:d9:31:8a:58:cc:80:0d:4f:0d:6f:ff:27:c8:
10:73:74:e5:d9:f6:d9:c6:e5:a5:c5:f7:aa:82:aa:
06:84:e3:79:eb:fd:ab:63:a3:e0:70:bf:7c:5e:d6:
5b:e4:36:97:f2:72:e0:d9:1d:a5:f9:25:08:80:46:
f7:d7:a5:c3:fd:cd:05:80:57:58:aa:e1:4a:49:87:
41:47:39:f7:f2:4b:a8:80:eb:33:c0:ef:12:51:dd:
06:a8:93:fc:9b:f3:10:13:ed:c3:31:5a:0b:42:a0:
30:0b:59:4b:fe:4e:b9:0d:34:2b:2c:77:9f:ed:42:
45:4d:4a:41:dd:53:51:62:17:d1:ec:25:42:36:aa:
dd:51:00:31:9b:0f:32:01:0e:fa:40:85:c8:f5:df:
33:e3:6f:2a:81:9d:16:15:67:e7:49:46:97:9f:93:
63:7d:25:59:cd:d3:49:f3:e3:bd:7b:10:43:29:a0:
11:34:0a:c5:58:10:55:ed:71:05:97:e4:59:b7:da:
db:af:45:e3:15:22:e5:a8:d8:ea:9e:51:8a:d3:b1:
6e:a4:27:21:c9:b5:f5:8f:6f:2c:39:50:c8:c2:da:
36:73
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:
1D:6A:C1:70:D6:6B:44:B5:DC:79:AD:76:A6:23:BB:FA:2D:12:3F:C1
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:http.domain.com
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
7f:3d:69:17:9c:37:b7:a9:6c:a2:f8:49:1d:8a:95:d2:f3:37:
95:bf:22:32:b4:f9:d3:00:69:a7:6f:d0:31:12:5f:64:5e:20:
73:e7:74:3b:b2:d8:97:89:d4:02:5a:4f:13:4d:79:e6:af:ab:
29:1d:d0:c3:91:ea:dc:f0:18:7d:c6:ef:9b:61:e5:fd:44:4a:
1d:f5:f1:a9:6d:02:8f:32:cf:04:47:1d:32:44:c6:55:e0:c6:
b6:09:5c:3c:c2:79:5f:47:ea:51:9c:85:61:da:7a:67:09:81:
a6:57:ed:d3:58:f3:30:dc:d2:9c:ca:06:74:72:eb:ed:b9:a1:
b2:d6:86:1d:07:08:81:f9:c8:d2:5e:e7:25:d9:d8:ba:24:f2:
e4:0a:8b:41:e4:50:d2:33:d1:cf:82:73:18:00:96:74:b7:d2:
5c:84:e9:1e:8c:95:c0:92:70:bf:77:48:e2:8c:76:3e:54:41:
cf:41:4f:5f:34:c1:ce:bd:b2:8c:2d:8a:33:3b:60:95:5a:bd:
20:2e:16:92:fe:ec:22:25:84:70:f9:84:c7:c8:ad:a1:e1:2e:
b8:ad:0d:df:4d:3f:1f:1e:95:3b:ce:97:86:75:fe:64:9c:01:
d5:49:39:94:73:39:62:77:b6:cd:50:17:29:5b:4c:33:4c:0b:
54:e0:e9:a3
-----BEGIN CERTIFICATE-----
MIIEKTCCAxGgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJVUzEP
MA0GA1UECgwGR29vZ2xlMRMwEQYDVQQLDApFbnRlcnByaXNlMRcwFQYDVQQDDA5T
aW5nbGUgUm9vdCBDQTAeFw0yNDAzMjkxOTA2NTBaFw0zNDAzMjkxOTA2NTBaME0x
CzAJBgNVBAYTAlVTMQ8wDQYDVQQKDAZHb29nbGUxEzARBgNVBAsMCkVudGVycHJp
c2UxGDAWBgNVBAMMD2h0dHAuZG9tYWluLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBALg182csyPOy7U06XnuLLlkt1defqdhGwK2/xB0JEQPZMYpY
zIANTw1v/yfIEHN05dn22cblpcX3qoKqBoTjeev9q2Oj4HC/fF7WW+Q2l/Jy4Nkd
pfklCIBG99elw/3NBYBXWKrhSkmHQUc59/JLqIDrM8DvElHdBqiT/JvzEBPtwzFa
C0KgMAtZS/5OuQ00Kyx3n+1CRU1KQd1TUWIX0ewlQjaq3VEAMZsPMgEO+kCFyPXf
M+NvKoGdFhVn50lGl5+TY30lWc3TSfPjvXsQQymgETQKxVgQVe1xBZfkWbfa269F
4xUi5ajY6p5RitOxbqQnIcm19Y9vLDlQyMLaNnMCAwEAAaOCARMwggEPMA4GA1Ud
DwEB/wQEAwIHgDAJBgNVHRMEAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1Ud
DgQWBBQdasFw1mtEtdx5rXamI7v6LRI/wTAfBgNVHSMEGDAWgBTs8OpTUz+fI9zB
DjEQNwfe3udu8zBFBggrBgEFBQcBAQQ5MDcwNQYIKwYBBQUHMAKGKWh0dHA6Ly9w
a2kuZXNvZGVtb2FwcDIuY29tL2NhL3Jvb3QtY2EuY2VyMDoGA1UdHwQzMDEwL6At
oCuGKWh0dHA6Ly9wa2kuZXNvZGVtb2FwcDIuY29tL2NhL3Jvb3QtY2EuY3JsMBoG
A1UdEQQTMBGCD2h0dHAuZG9tYWluLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAfz1p
F5w3t6lsovhJHYqV0vM3lb8iMrT50wBpp2/QMRJfZF4gc+d0O7LYl4nUAlpPE015
5q+rKR3Qw5Hq3PAYfcbvm2Hl/URKHfXxqW0CjzLPBEcdMkTGVeDGtglcPMJ5X0fq
UZyFYdp6ZwmBplft01jzMNzSnMoGdHLr7bmhstaGHQcIgfnI0l7nJdnYuiTy5AqL
QeRQ0jPRz4JzGACWdLfSXITpHoyVwJJwv3dI4ox2PlRBz0FPXzTBzr2yjC2KMztg
lVq9IC4Wkv7sIiWEcPmEx8itoeEuuK0N300/Hx6VO86XhnX+ZJwB1Uk5lHM5Yne2
zVAXKVtMM0wLVODpow==
-----END CERTIFICATE-----
key.pem
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4NfNnLMjzsu1N
Ol57iy5ZLdXXn6nYRsCtv8QdCRED2TGKWMyADU8Nb/8nyBBzdOXZ9tnG5aXF96qC
qgaE43nr/atjo+Bwv3xe1lvkNpfycuDZHaX5JQiARvfXpcP9zQWAV1iq4UpJh0FH
OffyS6iA6zPA7xJR3Qaok/yb8xAT7cMxWgtCoDALWUv+TrkNNCssd5/tQkVNSkHd
U1FiF9HsJUI2qt1RADGbDzIBDvpAhcj13zPjbyqBnRYVZ+dJRpefk2N9JVnN00nz
4717EEMpoBE0CsVYEFXtcQWX5Fm32tuvReMVIuWo2OqeUYrTsW6kJyHJtfWPbyw5
UMjC2jZzAgMBAAECggEAU4XKxgYtWynOpMyJWHTj3/WDVxACv5hc9qrTbeLVfyw0
ZSkcGBdwt4QHae8xXlgre6eMWL15a4h/HF2hNRG7D0BmPHhqZFS+PHXvFkuWm4xw
3KCvx4Z+E0OaToHPmr0h+G4iOuCJgUs9UuE6xfZ+AW4jeiAr60hPI5Jt3/vWV2IY
Y57cBZ9IIW6namd++xsQxm10wjltTF7u+xCiKzfj0Um463WVdh8e4NixvdlZQeJ7
tHxmt+bOxbOLZ4e9TRbj5/0nhKPCdpSsBkUflzVSg9ZhuTVEuj5KTTE/uLFyJ5pT
PkDZEf0r4dnwFLbTPSRzKyXNJbx9oQAccSy0AVNs6QKBgQD9xNaM4uJMMK/e5/Tf
kfOjP0yNvyHxqLGxFws596lSWuyqUQjY734oIXKBn67cBibhW6u53xCgMlvLCoYU
mtB2A9Fw82wyTmIKZjeWJ54qa7jq3FnnXoca1NRRoGSBtScfG9i+cxpCXpRUvvcz
ygFtP7IqYzznYG5QsPxOAfKQpwKBgQC51I6X0+OTMVUVuGUFJYfZMqFj6BDo4HX4
+aGit0Cut3NY2X1goEpUznML+OX/PLmTCTlVS+wkYz1SFJlLEkrf4CuS4HeTHZ2p
s5YrPAEppLaJwbEtg6eIytIpMarpkV+5BX2Rx7BIHZC35ZUc9pTs3aw2hxWdqke4
4TzE3G05VQKBgQC4w2wCv95L4tbp0LC1ZqqhHSE7wwGP1WcqrMB7wBoD4DeX+dAb
QqPzzAZ24jCJ+eCtC/WIKyULvh6fQlZFAkLs6fK/7jvElNVFBQ9LwCSkdjH4rd63
Wle77WF43PLQjXiiab/xShTAZeRRn4iUqGtJg6rQudhKDifDkFji4wAc2QKBgBmi
wh0d5Qo8RwGdE4qXN9t1yZ/vts15kazMO0koQKsZsbbzIgG/eyGh7WscZhZE+VDY
d+lVdPk8G4yEPPWHS38A/OHhR32rG0H6/V9vgrWM/IWai+e8ftM3L7DxIiPgozTy
FfWTd7UrJvjHmj+JoNfgaM6I6il7ATP3FpwN0J+VAoGAbyrQrQd1+W46wXbZm3qH
TLPLZGoaHPfVdH3MMa3Xm1qvMACKa/0h6M5UA0ZA6rm5mCwEqt5AL1zHQX35I6ez
7Cf/X6SRXZ+P1iP7V6KKEg5sO6EKQ0HWkab3ndZEJKpBZavj+xLRV2sY31atSYCi
x4o2aG85gKjuhOgWWezSh0Y=
-----END PRIVATE KEY-----