From 0363e481c22db862ecdeb715ba7be04d88f35828 Mon Sep 17 00:00:00 2001 From: Joseph Birr-Pixton Date: Tue, 19 Mar 2024 16:48:16 +0000 Subject: [PATCH] Test server behaviour --- rustls-libssl/Makefile | 5 +- rustls-libssl/test-ca/rsa/server.cert | 82 ++++++++++++ rustls-libssl/test-ca/rsa/server.key | 28 ++++ rustls-libssl/tests/runner.rs | 97 +++++++++++++- rustls-libssl/tests/server.c | 185 ++++++++++++++++++++++++++ 5 files changed, 389 insertions(+), 8 deletions(-) create mode 100644 rustls-libssl/test-ca/rsa/server.cert create mode 100644 rustls-libssl/test-ca/rsa/server.key create mode 100644 rustls-libssl/tests/server.c diff --git a/rustls-libssl/Makefile b/rustls-libssl/Makefile index 8c6a5ab..1092470 100644 --- a/rustls-libssl/Makefile +++ b/rustls-libssl/Makefile @@ -19,7 +19,7 @@ ifneq (,$(TARGET)) CARGOFLAGS += --target $(TARGET) endif -all: target/ciphers target/client target/constants target/$(PROFILE)/libssl.so.3 +all: target/ciphers target/client target/constants target/server target/$(PROFILE)/libssl.so.3 test: all ${CARGO} test $(CARGOFLAGS) @@ -48,6 +48,9 @@ target/client: target/client.o target/constants: target/constants.o $(CC) -o $@ $^ $(LDFLAGS) $(shell pkg-config --libs openssl) +target/server: target/server.o + $(CC) -o $@ $^ $(LDFLAGS) $(shell pkg-config --libs openssl) + clean: rm -rf target diff --git a/rustls-libssl/test-ca/rsa/server.cert b/rustls-libssl/test-ca/rsa/server.cert new file mode 100644 index 0000000..960366a --- /dev/null +++ b/rustls-libssl/test-ca/rsa/server.cert @@ -0,0 +1,82 @@ +-----BEGIN CERTIFICATE----- +MIIEGDCCAoCgAwIBAgICAcgwDQYJKoZIhvcNAQELBQAwLDEqMCgGA1UEAwwhcG9u +eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTIzMTIyMTE3MjMxNVoX +DTI5MDYxMjE3MjMxNVowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDI1plwQmA+rr6Evlvn2hzIB/zYKlx +Tm14SPzomxpaf3OpzXzHuOn34yVvU1vTDijUl/YJbcnx052m0075SYeuW08VQB/p +zjhLrFp1ULSD272IddbB88T8Jq/VZ5dAxBB1q6Tm0vGBYQ8eIcmJv+fJQTbTXHKQ +KPHQRmVyqXVkwvwcgEJi9gpOcEEpJ6SDGdyGh1ck3wGnhrSpmsu+hwUVi7las+Ka +QUlvkmD+UGQKo8Ta91Xu8ja25QLTpjVcYxbi719rtA6I9DpX4+3aeIy/0s1xk0Xi +yMXIjSl3dn47gp3IZFRCECuoTdOwOZ9+y9ENnpHvZ84jCBXddU09qheJAgMBAAGj +gdYwgdMwDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFAUefby7 +fPnK64BnGdIizLlWDkbPMEIGA1UdIwQ7MDmAFJCh13RFfpFyZ5LRR+A6ndRRvvGa +oR6kHDAaMRgwFgYDVQQDDA9wb255dG93biBSU0EgQ0GCAXswUwYDVR0RBEwwSoIO +dGVzdHNlcnZlci5jb22HBMYzZAGCFXNlY29uZC50ZXN0c2VydmVyLmNvbYcQIAEN +uAAAAAAAAAAAAAAAAYIJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBgQC2gxGT +c3aayDPR5/ICnuK8aVSsM67xRsGsWvzBxdyyXaB+qSGxa+sCkw8guuAp2W7MrrO/ +zu7yhXDI2nyav6ZP6NvLABFYZ6pXokV/Hj4rQpCDVxvvDVh/E/rW/wx6z580zfdo +auHqUCD9QfR97nENwtGv7ESLN6qFeU0CsJd2GE3y3pnadlpCW3AYHeLX4crm7poj +SfG1F4ipqM1i0knQN86KBzG5PO49azGJGmcsu5lPFQgTRvvR7W+Niq/kIQPu00AW +so8aSB1gp2lypUGHqwsrd51yrQ374jKvXSDt1ptc0xDI9004TuYre9XQsyjxq4Qn +VjmpnKLCbumkrlELf93oomWxT5g6Nb/vu1TUgsrdWgDAW0AZ+rfcWorrZAjbvYw9 +4MJ1PdAmeg+sk51xoh2KF7syHPaMcNCaoSBtXrB5LqrAxixdmB6ORM/KlQU7h9A7 +X+WysEwMowV2MsGr8VsHxYTOpoiE8nUPfnRmbrGPpUU24bzvqTxtxxqQU14= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEwDCCAqigAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 +dG93biBSU0EgQ0EwHhcNMjMxMjIxMTcyMzE1WhcNMzMxMjE4MTcyMzE1WjAsMSow +KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G +CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDC9IRIszo5zkkxlz+pkU8otrZ2Jwlf +BQ4j5heoPkpmvFss2fDElZZCVhZt54ehk2+oRuZhfgldfmuT0KCQEMnx8iN7K+pk +2LgaAVGzT4X/NBv+qamgkzRu9UvrS5NrlWutHsPPRt2TldVVJ1UEiLuWrrFMQwi+ +JATjgBHz6PhhD+UnPszZM/SJaBmtMXT99rO/sS6aaQhkZJCSDVVOnnecXafshkEF +tlMkKDRTTxxTOiTGu2NSH5MMzB3F952AiG8ZDONRSyBtxh/kpRV6+idO/4ufIQ3w +ZUPjLlRZIF9cDIGJXRU+cjYvMSV6yPzM2rP+67dPS9N7gQS1AFiMOlLQRbp3Sz9e +R6eetX/ggaHPcIzNv+pLp0L4+8PINZWhcJnZUlgkNR9Gg25mdPC6BLpWH20NH37V +VfSs40ytxHyw5QRokwwjcGUmlzXSJf0R+eUhXkJAmR+bgKbQKRbCW6M+byNdphfu +c3R2irNvRbYkwTOP3FvFkcC+cYyMIHyKihMCAwEAAaN/MH0wHQYDVR0OBBYEFJCh +13RFfpFyZ5LRR+A6ndRRvvGaMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF +BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAWgBRCEI9X +B595ntLEaruio2xG9pG/KzANBgkqhkiG9w0BAQsFAAOCAgEAxyqRDyGCkF07q/2P +44Mkwg+olQdT7moiO7V7MauwLZmCNqkr4hQcAk1NKi1QdYw/xCgd/x7PQ/INVMYN +oAG/xxr4nh0whygSsPGk9LkzoeG4dfeVv7tbsYw+4o7wU9kgCM1v0c2vMskyHh3F +vdMJV+5hWZqHZLUOZY1l9ziJysz/aSD4WpMtXdwT5fFgbJ8zggcMADkIESSBPrK5 +ykjFqFnoryK938IUw8fHEdU5ZdjM+1li4Q6P3YT6ovY9aA9gXbD/xb4mUb5kG+ug +tmGV+MDvi6Qgyt1O9ZgaW0tLdbjdxzTjEgU0KwUDpK6AZ9ebcyL5PGj3JA15ZPvS +36AHH/3N+u3w1Poyxb8NxyOgNY7AX3hRQax9G1/43F3VZ1C991xVrwWL++mRD+Ai +5FhMKjZ258+8DKgYaT2JIExwNWA5taafmR2CKpxgVWSFLha/WogJH3kyyTJHXLjU +Bm5qvwqWAvS3Px+WkSbtqFKRDCs+oaj2wGGuwxqEEEriMJ26AC3Si2n9k0a17TOj +lezKgblBHlpokEgcqOkRDB8k1g/Hkx7eRX4RlBRJ4PVRFT6qSTyy3dESsWhb7Sz2 ++uB8SQIYH+5QXwD3MpNrg2BILQYtcciPiGmLNyQB3ZvJUKcj0n63CjxAfcSnbkUF +AnF6iUVbZu9AMRaBDiRdNLGnBms= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFFTCCAv2gAwIBAgIUZBEaAuV4ORnPH4GxeJGyEiqXUN8wDQYJKoZIhvcNAQEL +BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTIzMTIyMTE3MjMxNFoX +DTMzMTIxODE3MjMxNFowGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzvK/b5WhfthXBMVIHboJJuR9XuG9 ++ioSrlzwT9DW7QV31UpgBUZyf1nvT7CmDplNiWZtpqSdJ9pjskBIj5dv4m5cX8A9 +fK1IATdkd6j5/c2ZFkqi5k9iPeJa5rZY6SoGKgvBEr/Y5oiO8HZJZOFetafSr6zV +WRAsKlagrmiNS0oiWC0P0yPVWZyhlHHbtYrHtF/CuWEJ9HqzUk9KeTPwgjfphlYJ +YM0bCZzqN8TEbWPksU1WnmU15YbTgjwI0bNjUXA7W9LmMvbW7EXFJ2+LI+oiF3mk +TQEXqhfdTL9NtqAikD+cfAM1y5e5QSpi8dQuexBteFtXphRZzFk8M9DVKHyngKTH +/QZo6B4Gj9VPrNRPlbPkpbnu8JWD7hO/22VLU4YhghsdwQ/833pfokdV89NMoLo4 +JOUzbTTGtjH0bq6LWTMtLifuQ4H0D1WLtdy/EGgKptnTaeYaXNYT7+v+NNcBHaW8 +W3Orbx0s9IXgQnZTk1u03RbRdIxNxqm+HYEM8gT6S9IUymNZkzDCfZC0bC/saevd +zVE2xpZmuLOfhDl+EcalDYNPrM72+NzkAwRPFGec+bcUEhBxhvxpav+SxDiRC1gD +43qFU7hVfuqVH/EFp0lR3I3Xo8TZ5OIgEyJ5vQH5Ne1+C+sqdCqdGoqf1TZuIE80 +ZwKYcMnRwDXpiGsCAwEAAaNTMFEwHQYDVR0OBBYEFEIQj1cHn3me0sRqu6KjbEb2 +kb8rMB8GA1UdIwQYMBaAFEIQj1cHn3me0sRqu6KjbEb2kb8rMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQELBQADggIBAEKDnm8x+NOaWNrPNH5kIlGD0tGdDJvw +/KvBZmkMcgFkb4zhbbeUmlu0j5CX4+6Lck0uw62zRgP4Nw3x36W3DL7pmoV4MYHC +djNG1ruNoojvgZyyGgMaSabto0nSHSE9opAorrSXB9RoOv2WcBuQSBNl72eaCQ1F +4kAYjKN6ZwPxEdTsdEmqWyUyEPy6E5kNoM0jW1uI2ZBxzbIOYeePvQ3muUSIMtmC +jShiEOOpmYpzENsAMouY3ZN+CWVS5kB5umnYSviQlAVEKSjC764FD9vMLL+rNhfP +fz+y6EhKcnnYy7mdXIRY73uh5eMyCLUO0yr2Y2ophhD8D79f2w7KtYjaSKfAch0L +lETe9Ch+fGDxUCph3J1IuR/3n01ZjB47WXu/yDZ6s7SHGXIgPaptzP+nZkDnmlZX +bvjB5s6r4U2spuqeLxrwd/1Jin7It+LOYLVmkihpbta9+/KKiXOuSYN1rSiQ2XKp +n1ZN0XxhcZzsALklBIU+Lm11b8gPVS7rXqll/sDmaAH9Iw+AXwUYjCb62Gy58yzu +uk3Q+msRr3oVI9bBhmEXmZxyENYJrw305qOlI3+tHBoJLUSP6zQ214aEu4trJr5K +kmbF7DZRG9MSBXeRk7e5ojK13xI1/XCjgIOTkGxF4rEFbVwhc0B8zS/2x3zw0fkE +M4J0J+gz0QYr +-----END CERTIFICATE----- diff --git a/rustls-libssl/test-ca/rsa/server.key b/rustls-libssl/test-ca/rsa/server.key new file mode 100644 index 0000000..cb236b6 --- /dev/null +++ b/rustls-libssl/test-ca/rsa/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDI1plwQmA+rr6 +Evlvn2hzIB/zYKlxTm14SPzomxpaf3OpzXzHuOn34yVvU1vTDijUl/YJbcnx052m +0075SYeuW08VQB/pzjhLrFp1ULSD272IddbB88T8Jq/VZ5dAxBB1q6Tm0vGBYQ8e +IcmJv+fJQTbTXHKQKPHQRmVyqXVkwvwcgEJi9gpOcEEpJ6SDGdyGh1ck3wGnhrSp +msu+hwUVi7las+KaQUlvkmD+UGQKo8Ta91Xu8ja25QLTpjVcYxbi719rtA6I9DpX +4+3aeIy/0s1xk0XiyMXIjSl3dn47gp3IZFRCECuoTdOwOZ9+y9ENnpHvZ84jCBXd +dU09qheJAgMBAAECggEABbzZYJqPc/prWwUJzo1qXdA5AEf8U3eR4nKK9S/yU2zh +8sE3BQxb3M0SAbb6wTbuXmnlcxuGT5UAUrJt5QiTc739kktjZNWKdDcqJb7sv9/L +L+L/II7RYPSmQOkd2mqpbTxRyfOz5DD9Z85ohaNd5l4Dha13NOPvUEdxnjB7Yi4I +YbUYZ/Zq6MUosFRObS0XPBvk6d+zDI3WUZatVTNfuS7fqI1BvkXs5EkV34DQXgQs +LKb1LFAoEZoh64UnfkONIT9oG4OTbbaQ9gCbfQPpKw07GuaMdtjp0QD0yldOKvL4 +V4crSZyj2f3LnPCqCjUwcz6quKSUqUgosVApH+JCcQKBgQDpaGXy3laYTK3zbauh ++eHY5Ia+7fM2ETZx4LfwAYA1K5E84T98swpO571lZVrbOKjBukpUrbHdOcEVcBRH +BTvCh1vL1AXXWR0cCvWtp/WAbu90rDqgu6mxaD+V8wGq29URTWOCRG1WA7zeNHPB +0XAZPLQVeqeSvHGLSqyPf4aoHQKBgQDWBqvl5To7P4ZT6VFl18v0EB3zgzpRuyC3 +xKKz5mGw4tuvspdMU2XaOGQsRl5emMijGeII7JUweHbBdkq44S2FZ9wyn4+I+8Oi +Atu4Nce06ARnw+5RRcJlSs/LrExfOtxF3xp8EQqpL/jEO03n7G5cwcFwuWTKoVTI +0RwcuU4JXQKBgDBMCvRzb2W6UDBT3DT7GPGhcARoBnCEpUhxIH6IQPg/mKEJVvK9 +tX9YUod9row4MCtOGf1lp61IOxztgTSk75W0HpmRuNezt+NKnUWewJ0f12rEDKmf +y2BLWwTzMMAjFvaqldGpyRoIUfeE0QMlDFYcioL7S1uApNoWzJgw4jM9AoGBANIk +osuLku1xphbl08JHbD4rRP1AMBbnwWwuagJxhiID3OhaVivfBvaIv/Ko9Se0o+th +EorooGODJDc4So3Uqrl+DLq36Fr7uE5uuAXa6Ec8OHcZ7flmoUSLfBPjDOnEBVul +f3+py+nq7Drgb9H0VzhEFgb0QX6jgXfbudqKJ5ERAoGAR5Q6wQEoT9VT53nuKprl +3K/6agd+4wlpVQW0W1LImdrJHRHUXO7KJe7Bo5rtjL3lw8dCl3olHlLPJKg9frMn +ZWvJ2t0zca18S76rNcsPew2BecJxNRFlGwdcE1BBA2p/yzBhsZbIO7eqfh+dK5va +rnlrPNbWDhylxMaU4/CoU7k= +-----END PRIVATE KEY----- diff --git a/rustls-libssl/tests/runner.rs b/rustls-libssl/tests/runner.rs index dac055e..ad95eef 100644 --- a/rustls-libssl/tests/runner.rs +++ b/rustls-libssl/tests/runner.rs @@ -1,3 +1,4 @@ +use std::io::Read; use std::process::{Child, Command, Output, Stdio}; use std::{net, thread, time}; @@ -30,7 +31,7 @@ use std::{net, thread, time}; #[test] #[ignore] fn client_unauthenticated() { - let _server = KillOnDrop( + let _server = KillOnDrop(Some( Command::new("openssl") .args([ "s_server", @@ -49,7 +50,7 @@ fn client_unauthenticated() { .env("LD_LIBRARY_PATH", "") .spawn() .expect("failed to start openssl s_server"), - ); + )); wait_for_port(4443); @@ -125,7 +126,7 @@ fn client_unauthenticated() { #[test] #[ignore] fn client_auth() { - let _server = KillOnDrop( + let _server = KillOnDrop(Some( Command::new("openssl") .args([ "s_server", @@ -148,7 +149,7 @@ fn client_auth() { .env("LD_LIBRARY_PATH", "") .spawn() .expect("failed to start openssl s_server"), - ); + )); wait_for_port(4444); @@ -269,12 +270,77 @@ fn ciphers() { assert_eq!(openssl_output, rustls_output); } -struct KillOnDrop(Child); +#[test] +#[ignore] +fn server() { + fn curl() { + Command::new("curl") + .env("LD_LIBRARY_PATH", "") + .args([ + "-v", + "--cacert", + "test-ca/rsa/ca.cert", + "https://localhost:5555/", + ]) + .stdout(Stdio::piped()) + .output() + .map(print_output) + .unwrap(); + } + + let mut openssl_server = KillOnDrop(Some( + Command::new("tests/maybe-valgrind.sh") + .env("LD_LIBRARY_PATH", "") + .args([ + "target/server", + "5555", + "test-ca/rsa/server.key", + "test-ca/rsa/server.cert", + "unauth", + ]) + .stdout(Stdio::piped()) + .spawn() + .unwrap(), + )); + wait_for_stdout(openssl_server.0.as_mut().unwrap(), b"listening\n"); + curl(); + + let openssl_output = print_output(openssl_server.take_inner().wait_with_output().unwrap()); + + let mut rustls_server = KillOnDrop(Some( + Command::new("tests/maybe-valgrind.sh") + .args([ + "target/server", + "5555", + "test-ca/rsa/server.key", + "test-ca/rsa/server.cert", + "unauth", + ]) + .stdout(Stdio::piped()) + .spawn() + .unwrap(), + )); + wait_for_stdout(rustls_server.0.as_mut().unwrap(), b"listening\n"); + curl(); + + let rustls_output = print_output(rustls_server.take_inner().wait_with_output().unwrap()); + assert_eq!(openssl_output, rustls_output); +} + +struct KillOnDrop(Option); + +impl KillOnDrop { + fn take_inner(&mut self) -> Child { + self.0.take().unwrap() + } +} impl Drop for KillOnDrop { fn drop(&mut self) { - self.0.kill().expect("failed to kill subprocess"); - self.0.wait().expect("failed to wait for killed subprocess"); + if let Some(mut child) = self.0.take() { + child.kill().expect("failed to kill subprocess"); + child.wait().expect("failed to wait for killed subprocess"); + } } } @@ -306,3 +372,20 @@ fn wait_for_port(port: u16) -> Option<()> { } } } + +fn wait_for_stdout(stream: &mut Child, expected: &[u8]) { + let stdout = stream.stdout.as_mut().unwrap(); + + let mut buffer = Vec::with_capacity(1024); + + loop { + let mut input = [0u8]; + let new = stdout.read(&mut input).unwrap(); + assert_eq!(new, 1); + buffer.push(input[0]); + + if buffer.ends_with(expected) { + return; + } + } +} diff --git a/rustls-libssl/tests/server.c b/rustls-libssl/tests/server.c new file mode 100644 index 0000000..cc86dc2 --- /dev/null +++ b/rustls-libssl/tests/server.c @@ -0,0 +1,185 @@ +/** + * Simple server test program. + * + * Listens on the given port, and accepts one connection on it. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int trace(int rc, const char *str) { + printf("%s: %d\n", str, rc); + return rc; +} + +#define TRACE(fn) trace((fn), #fn) + +static void hexdump(const char *label, const void *buf, int n) { + const uint8_t *ubuf = (const uint8_t *)buf; + printf("%s (%d bytes): ", label, n); + for (int i = 0; i < n; i++) { + printf("%02x", ubuf[i]); + } + printf("\n"); +} + +static void dump_openssl_error_stack(void) { + if (ERR_peek_error() != 0) { + printf("openssl error: %08lx\n", ERR_peek_error()); + ERR_print_errors_fp(stderr); + } +} + +static void state(const SSL *s) { + OSSL_HANDSHAKE_STATE st = SSL_get_state(s); + printf("state: %d (before:%d, init:%d, fin:%d)\n", st, SSL_in_before(s), + SSL_in_init(s), SSL_is_init_finished(s)); +} + +int main(int argc, char **argv) { + if (argc != 5) { + printf("%s |unauth\n\n", + argv[0]); + return 1; + } + + const char *port = argv[1], *keyfile = argv[2], *certfile = argv[3], + *cacert = argv[4]; + + int listener = TRACE(socket(AF_INET, SOCK_STREAM, 0)); + struct sockaddr_in us, them; + memset(&us, 0, sizeof(us)); + us.sin_family = AF_INET; + us.sin_addr.s_addr = htonl(INADDR_ANY); + us.sin_port = htons(atoi(port)); + TRACE(bind(listener, (struct sockaddr *)&us, sizeof(us))); + TRACE(listen(listener, 5)); + printf("listening\n"); + fflush(stdout); + socklen_t them_len = sizeof(them); + int sock = TRACE(accept(listener, (struct sockaddr *)&them, &them_len)); + + TRACE(OPENSSL_init_ssl(0, NULL)); + dump_openssl_error_stack(); + SSL_CTX *ctx = SSL_CTX_new(TLS_method()); + dump_openssl_error_stack(); + if (strcmp(cacert, "unauth") != 0) { + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + dump_openssl_error_stack(); + TRACE(SSL_CTX_load_verify_file(ctx, cacert)); + dump_openssl_error_stack(); + } else { + printf("client auth disabled\n"); + } + + X509 *server_cert = NULL; + EVP_PKEY *server_key = NULL; + TRACE(SSL_CTX_use_certificate_chain_file(ctx, certfile)); + TRACE(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM)); + server_key = SSL_CTX_get0_privatekey(ctx); + server_cert = SSL_CTX_get0_certificate(ctx); + + TRACE(SSL_CTX_set_alpn_protos(ctx, (const uint8_t *)"\x08http/1.1", 9)); + dump_openssl_error_stack(); + + SSL *ssl = SSL_new(ctx); + dump_openssl_error_stack(); + printf("SSL_new: SSL_get_privatekey %s SSL_CTX_get0_privatekey\n", + SSL_get_privatekey(ssl) == server_key ? "same as" : "differs to"); + printf("SSL_new: SSL_get_certificate %s SSL_CTX_get0_certificate\n", + SSL_get_certificate(ssl) == server_cert ? "same as" : "differs to"); + state(ssl); + TRACE(SSL_set_fd(ssl, sock)); + dump_openssl_error_stack(); + state(ssl); + TRACE(SSL_accept(ssl)); + dump_openssl_error_stack(); + state(ssl); + printf("SSL_accept: SSL_get_privatekey %s SSL_CTX_get0_privatekey\n", + SSL_get_privatekey(ssl) == server_key ? "same as" : "differs to"); + printf("SSL_accept: SSL_get_certificate %s SSL_CTX_get0_certificate\n", + SSL_get_certificate(ssl) == server_cert ? "same as" : "differs to"); + + // check the alpn (also sees that SSL_accept completed handshake) + const uint8_t *alpn_ptr = NULL; + unsigned int alpn_len = 0; + SSL_get0_alpn_selected(ssl, &alpn_ptr, &alpn_len); + hexdump("alpn", alpn_ptr, alpn_len); + + printf("version: %s\n", SSL_get_version(ssl)); + printf("verify-result: %ld\n", SSL_get_verify_result(ssl)); + printf("cipher: %s\n", SSL_CIPHER_standard_name(SSL_get_current_cipher(ssl))); + + // check the peer certificate and chain + X509 *cert = SSL_get1_peer_certificate(ssl); + if (cert) { + char *name = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); + printf("client subject: %s\n", name); + free(name); + } else { + printf("client cert absent\n"); + } + X509_free(cert); + + STACK_OF(X509) *chain = SSL_get_peer_cert_chain(ssl); + if (chain) { + printf("%d certs in client chain\n", sk_X509_num(chain)); + for (int i = 0; i < sk_X509_num(chain); i++) { + X509 *cert = sk_X509_value(chain, i); + char *name = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); + printf(" %d: %s\n", i, name); + free(name); + } + } else { + printf("client cert chain absent\n"); + } + + // read "request" + while (1) { + char buf[128] = {0}; + int rd = TRACE(SSL_read(ssl, buf, sizeof(buf))); + dump_openssl_error_stack(); + TRACE(SSL_pending(ssl)); + dump_openssl_error_stack(); + TRACE(SSL_has_pending(ssl)); + dump_openssl_error_stack(); + if (rd == 0) { + printf("nothing read\n"); + break; + } else { + hexdump("result", buf, rd); + } + state(ssl); + + if (!TRACE(SSL_has_pending(ssl))) { + break; + } + } + + // write some data and close + const char response[] = "HTTP/1.0 200 OK\r\n\r\nhello\r\n"; + int wr = TRACE(SSL_write(ssl, response, sizeof(response) - 1)); + dump_openssl_error_stack(); + assert(wr == sizeof(response) - 1); + TRACE(SSL_shutdown(ssl)); + dump_openssl_error_stack(); + + close(sock); + close(listener); + SSL_free(ssl); + SSL_CTX_free(ctx); + + printf("PASS\n\n"); + return 0; +}