Requires openssl-tpm2 provider
# export OPENSSL_MODULES=/usr/lib/x86_64-linux-gnu/ossl-modules/
#
# cat /etc/ssl/openssl.cnf
# [openssl_init]
# providers = provider_sect
# ssl_conf = ssl_sect
# [provider_sect]
# default = default_sect
# tpm2 = tpm2_sect
# [tpm2_sect]
# activate = 1
#
# [default_sect]
# activate = 1
$ openssl list --providers
Providers:
default
name: OpenSSL Default Provider
version: 3.0.2
status: active
tpm2
name: TPM 2.0 Provider
version: 1.3.0
status: active
$ openssl req --provider tpm2 --provider default -x509 -newkey rsa \
-pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 \
-keyout key.pem -out cert.pem -sha256 -days 365
$ openssl rsa -provider tpm2 -provider default -in key.pem --text
Private-Key: (RSA 2048 bit, TPM 2.0)
Parent: 0x40000001
Modulus:
00:c9:1b:e4:fb:db:a1:49:27:4d:b7:f5:f1:44:c6:
4c:ba:d0:d9:20:4e:8f:bd:ad:78:d4:b0:5b:58:26:
f6:b0:c1:d0:71:18:73:64:cc:72:7d:d3:77:8a:11:
ec:70:69:ab:8c:a4:0c:2f:94:d3:54:47:d3:79:c8:
6a:16:d9:4e:c0:9d:5b:67:a3:28:89:44:4b:c5:c4:
c4:49:45:7a:23:e0:48:69:a4:01:63:47:5b:82:35:
3e:37:f3:6e:db:81:3f:16:b1:39:a1:ae:82:2e:a9:
81:f5:46:be:e3:e4:8e:84:4f:d9:5c:7c:f8:42:aa:
d1:2a:bb:e4:cc:4c:c8:59:32:c1:80:e9:c1:5d:86:
62:c7:e7:46:2b:a8:3d:4f:82:30:f1:c6:c7:ff:a5:
13:88:6e:0a:ee:d4:5d:d6:b9:8f:61:8b:20:71:10:
50:f9:7b:87:ff:c7:78:51:3f:4b:52:65:64:3a:9f:
2a:4f:c6:93:e8:eb:c0:52:49:25:05:3a:25:65:ae:
ed:b3:23:1a:97:24:42:3f:fd:21:db:68:21:6e:15:
24:06:25:07:c4:7c:0a:01:0f:a5:dc:e2:13:ad:68:
3c:42:b6:2a:8b:ba:68:32:bc:af:ad:17:07:26:4c:
1f:2c:bd:99:87:da:e1:86:04:e4:f7:62:dc:0c:e5:
45:7b
Exponent: 65537 (0x10001)
Object Attributes:
fixedTPM
fixedParent
sensitiveDataOrigin
userWithAuth
decrypt
sign / encrypt
Signature Scheme: <NULL>
Hash: <NULL>
writing RSA key
-----BEGIN TSS2 PRIVATE KEY-----
MIICEgYGZ4EFCgEDoAMBAQECBEAAAAEEggEYARYAAQALAAYAcgAAABAAEAgAAAAA
AAEAyRvk+9uhSSdNt/XxRMZMutDZIE6Pva141LBbWCb2sMHQcRhzZMxyfdN3ihHs
cGmrjKQML5TTVEfTechqFtlOwJ1bZ6MoiURLxcTESUV6I+BIaaQBY0dbgjU+N/Nu
24E/FrE5oa6CLqmB9Ua+4+SOhE/ZXHz4QqrRKrvkzEzIWTLBgOnBXYZix+dGK6g9
T4Iw8cbH/6UTiG4K7tRd1rmPYYsgcRBQ+XuH/8d4UT9LUmVkOp8qT8aT6OvAUkkl
BTolZa7tsyMalyRCP/0h22ghbhUkBiUHxHwKAQ+l3OITrWg8QrYqi7poMryvrRcH
JkwfLL2Zh9rhhgTk92LcDOVFewSB4ADeACDekeQS2q1DW+fhExstNAaz/NI6mQSY
BaUcsUAkM5CrrQAQj/lMCy8sH81RqFpzXrBlrC/N2yWIiCwNw/uPM/XOLq/Ma/Tc
g3k4Vy4FsXKYi0ckXiT7Id1oATCt+cE9lIpIF8SMVOyB0hdU0Duo8xwtFtVi4GTV
ReITtrmog3Xxf+iu94qlcExGkRCiy+0ZPMMIZ/hez2J+tT8F4isXUOAbP9vBLmf2
U2Ic4K1nR30mhUiSyQkwKiPDmGyq45muAHHDmPFF7bnP6xwsV+pCuLBr4hVR24Mw
+N25jOAG
-----END TSS2 PRIVATE KEY-----
$ openssl x509 -provider tpm2 -provider default -in cert.pem -text -noout
openssl c
gcc server.c -lcrypto -lssl -o server
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/provider.h>
int create_socket(int port)
{
int s;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror("Unable to create socket");
exit(EXIT_FAILURE);
}
if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("Unable to bind");
exit(EXIT_FAILURE);
}
if (listen(s, 1) < 0) {
perror("Unable to listen");
exit(EXIT_FAILURE);
}
return s;
}
SSL_CTX *create_context()
{
const SSL_METHOD *method;
SSL_CTX *ctx;
method = TLS_server_method();
ctx = SSL_CTX_new(method);
if (!ctx) {
perror("Unable to create SSL context");
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
return ctx;
}
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)
{
OSSL_PROVIDER* provider;
provider = OSSL_PROVIDER_load(NULL, "default");
if (provider == NULL) {
printf("Failed to load Default provider\n");
exit(EXIT_FAILURE);
}
printf("Default Provider name: %s\n", OSSL_PROVIDER_get0_name(provider));
OSSL_PROVIDER* custom_provider = OSSL_PROVIDER_load(NULL, "tpm2");
if (custom_provider == NULL) {
perror("Could not create custom provider");
exit(EXIT_FAILURE);
}
printf("Custom Provider name: %s\n", OSSL_PROVIDER_get0_name(custom_provider));
int sock;
SSL_CTX *ctx;
/* Ignore broken pipe signals */
signal(SIGPIPE, SIG_IGN);
ctx = create_context();
configure_context(ctx);
sock = create_socket(4433);
/* Handle connections */
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 {
SSL_write(ssl, reply, strlen(reply));
}
SSL_shutdown(ssl);
SSL_free(ssl);
close(client);
}
close(sock);
SSL_CTX_free(ctx);
}
python
import http.server
import ssl
import os
class HTTPServerRequestHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
return http.server.SimpleHTTPRequestHandler.do_GET(self)
if __name__ == '__main__':
httpd = http.server.HTTPServer(('localhost', 4433), HTTPServerRequestHandler)
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context.load_cert_chain(certfile='cert.pem', keyfile='key.pem')
httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True)
print("Serving at https://localhost:4433")
httpd.serve_forever()
$ openssl s_client --connect localhost:4433
CONNECTED(00000003)
Can't use SSL_get_servername
depth=0 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
verify error:num=18:self-signed certificate
verify return:1
depth=0 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
verify return:1
---
Certificate chain
0 s:C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
i:C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: Mar 17 11:20:18 2025 GMT; NotAfter: Mar 17 11:20:18 2026 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIUEdXrJSw3yQWqAMrpFwQykfaDXUQwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTAzMTcxMTIwMThaFw0yNjAz
MTcxMTIwMThaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDJG+T726FJJ0239fFExky60NkgTo+9rXjUsFtYJvaw
wdBxGHNkzHJ903eKEexwaauMpAwvlNNUR9N5yGoW2U7AnVtnoyiJREvFxMRJRXoj
4EhppAFjR1uCNT43827bgT8WsTmhroIuqYH1Rr7j5I6ET9lcfPhCqtEqu+TMTMhZ
MsGA6cFdhmLH50YrqD1PgjDxxsf/pROIbgru1F3WuY9hiyBxEFD5e4f/x3hRP0tS
ZWQ6nypPxpPo68BSSSUFOiVlru2zIxqXJEI//SHbaCFuFSQGJQfEfAoBD6Xc4hOt
aDxCtiqLumgyvK+tFwcmTB8svZmH2uGGBOT3YtwM5UV7AgMBAAGjUzBRMB0GA1Ud
DgQWBBQVQCodV9VwfmIQ+1CaokkltQcP2DAfBgNVHSMEGDAWgBQVQCodV9VwfmIQ
+1CaokkltQcP2DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCE
mflQr7zoq3pgicnSO0V3XUQzNcMJz+WacCcLftmc78p/ggX5lpxjptUaMtsnHQIn
AyqkQ4SzNrugoP3ItEI9/v/u/sG0jNHQ7mh5hW3uvIk7p5tc/epAIgDjPY+gZlzb
Fk2eahsTPhZwktaTjfAkyD1zpKonmltXbSpj5tmkRy0Nv6d3p+OluU9RjyC5PyvP
g/Q0MwUs9hq64a+YlYobc4/IszubduS771qlmrxxjgzUVPUR6pHl+1ULjSlnOT44
udAC9aqsuWMVvJxhSJmsXAclqsc5gOqmFwx4CHVDnlMSGMJjVt7LnJo/Haw3OtT+
5pm8GR/ea7Pjloulu3zy
-----END CERTIFICATE-----
subject=C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
issuer=C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1435 bytes and written 373 bytes
Verification error: self-signed certificate
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 18 (self-signed certificate)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Session-ID: EB4C62ACA2DBCC01FD09ADA8AA620BF7DC7410C1DE581F9BEA19BBE14F369BFE
Session-ID-ctx:
Resumption PSK: B93B01BE74E775A87E37C5178103E04A1C09DB67D95016C29C05F5EB051F19A0D2318784ABF8AC585DD3F6FD40D07BE1
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 7200 (seconds)
TLS session ticket:
0000 - b6 14 64 60 ea 5c ec 12-43 59 cd 66 6b 0a c4 e4 ..d`.\..CY.fk...
0010 - c1 59 ab 6d 21 bc c7 fd-1e eb c3 a3 e2 f8 ac 8f .Y.m!...........
0020 - 0a 9e d9 4d f5 3d dd 6b-3b f8 13 59 cb 5e a8 b7 ...M.=.k;..Y.^..
0030 - 38 bd bf 01 f3 0c 5d 59-40 c2 90 63 1d fa 26 cc 8.....][email protected]..&.
0040 - ad e9 78 e6 d5 3c 39 f3-36 b8 4d 63 30 5a df 62 ..x..<9.6.Mc0Z.b
0050 - f7 b1 97 2a f8 9a e4 1f-7c 6c 06 d9 e0 ff 9f de ...*....|l......
0060 - 2c 0c f5 10 aa 92 8a ca-4e 88 cb 03 c6 c8 b8 9b ,.......N.......
0070 - 65 5d d3 2f 4d ac e8 51-e9 5d 61 c7 ab f9 fe 80 e]./M..Q.]a.....
0080 - 4b a9 87 be 39 47 88 68-96 37 a4 0f 9c 98 ea c9 K...9G.h.7......
0090 - 94 3a 58 b5 f2 cb 3e 69-f8 96 95 d4 41 6d f6 6c .:X...>i....Am.l
00a0 - bd bf 4a 4c b4 ae 24 c5-77 a9 64 29 9a 76 00 f6 ..JL..$.w.d).v..
00b0 - 39 8e 8e b2 44 ac eb e7-3c 4b 18 fc e3 ed 6c 36 9...D...<K....l6
00c0 - 5d 6c 52 07 41 ec 57 1d-da e0 a2 2b 8a fa bf 62 ]lR.A.W....+...b
Start Time: 1742210478
Timeout : 7200 (sec)
Verify return code: 18 (self-signed certificate)
Extended master secret: no
Max Early Data: 0
---
read R BLOCK
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Session-ID: 509FD58BBB4B2492AB8CBDBBD8BF7BA5D816B3C05C15F104C8C283442E5AE378
Session-ID-ctx:
Resumption PSK: 9BEA90B8715391F9D4466A067D0E8AFEEA77E2F5245D4032C56D1DA0DCA6677BD05BB423F1B731509883B3C3F7595339
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 7200 (seconds)
TLS session ticket:
0000 - b6 14 64 60 ea 5c ec 12-43 59 cd 66 6b 0a c4 e4 ..d`.\..CY.fk...
0010 - bd a6 60 ce 3e 47 21 d6-cd 41 61 06 60 e6 98 70 ..`.>G!..Aa.`..p
0020 - 3b c8 65 07 98 4c ba 34-5d 53 c6 38 10 71 c3 50 ;.e..L.4]S.8.q.P
0030 - 87 d0 6b 1e 4e f3 ac 0b-cb 7d 67 2c 7a ac 4a e7 ..k.N....}g,z.J.
0040 - d3 bd bd 13 29 20 1e 2f-29 92 c5 42 ad 8b 53 41 ....) ./)..B..SA
0050 - 2a 2f a0 f6 e2 91 bf e3-5f 76 86 76 89 d4 bf aa */......_v.v....
0060 - 89 b6 28 29 92 bb eb 75-03 e7 88 13 95 85 96 71 ..()...u.......q
0070 - b7 b2 eb a4 5d 53 1a c6-61 23 68 32 4d 43 8b 63 ....]S..a#h2MC.c
0080 - 10 55 0a 26 4d cb 9f 6a-10 90 0d 8b e3 a8 02 96 .U.&M..j........
0090 - 92 d6 11 89 4b 68 0d 1e-9f 88 64 87 37 d2 a6 03 ....Kh....d.7...
00a0 - 6b 31 c2 06 aa 07 4b 28-4e 95 c5 e3 76 7c aa 6b k1....K(N...v|.k
00b0 - d1 8c c8 78 e6 51 c0 6d-f3 ad 55 27 b7 01 e7 dc ...x.Q.m..U'....
00c0 - 95 55 dd 5c 7c d0 4e 22-9a 75 b3 ec b1 f6 8c 6c .U.\|.N".u.....l
Start Time: 1742210478
Timeout : 7200 (sec)
Verify return code: 18 (self-signed certificate)
Extended master secret: no
Max Early Data: 0
---
read R BLOCK
test
closed