From f37dea418b777478bee7b1d812e3adb5fb71d0ee Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Wed, 11 Sep 2024 10:13:55 +0900 Subject: [PATCH] s_server: Support reading HTTP request from early data This would be useful when testing with browsers / downloaders which support 0-RTT only through HTTP. Signed-off-by: Daiki Ueno Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/16055) --- apps/s_server.c | 45 ++++++++++++++++++++++++++++---- doc/man1/openssl-s_server.pod.in | 2 -- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/apps/s_server.c b/apps/s_server.c index e47691655e9..888e8f62cf0 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -1757,9 +1757,9 @@ int s_server_main(int argc, char *argv[]) goto end; } #endif - if (early_data && (www > 0 || rev)) { + if (early_data && rev) { BIO_printf(bio_err, - "Can't use -early_data in combination with -www, -WWW, -HTTP, or -rev\n"); + "Can't use -early_data in combination with -rev\n"); goto end; } @@ -3156,7 +3156,7 @@ static int www_body(int s, int stype, int prot, unsigned char *context) int i, j, k, dot; SSL *con; const SSL_CIPHER *c; - BIO *io, *ssl_bio, *sbio; + BIO *io, *ssl_bio, *sbio, *edio; #ifdef RENEG int total_bytes = 0; #endif @@ -3178,7 +3178,8 @@ static int www_body(int s, int stype, int prot, unsigned char *context) p = buf = app_malloc(bufsize + 1, "server www buffer"); io = BIO_new(BIO_f_buffer()); ssl_bio = BIO_new(BIO_f_ssl()); - if ((io == NULL) || (ssl_bio == NULL)) + edio = BIO_new(BIO_s_mem()); + if ((io == NULL) || (ssl_bio == NULL) || (edio == NULL)) goto err; if (s_nbio) { @@ -3238,6 +3239,12 @@ static int www_body(int s, int stype, int prot, unsigned char *context) goto err; io = BIO_push(filter, io); + + filter = BIO_new(BIO_f_ebcdic_filter()); + if (filter == NULL) + goto err; + + edio = BIO_push(filter, edio); #endif if (s_debug) { @@ -3254,8 +3261,35 @@ static int www_body(int s, int stype, int prot, unsigned char *context) SSL_set_msg_callback_arg(con, bio_s_msg ? bio_s_msg : bio_s_out); } + if (early_data) { + int edret = SSL_READ_EARLY_DATA_ERROR; + size_t readbytes; + + while (edret != SSL_READ_EARLY_DATA_FINISH) { + for (;;) { + edret = SSL_read_early_data(con, buf, bufsize, &readbytes); + if (edret != SSL_READ_EARLY_DATA_ERROR) + break; + + switch (SSL_get_error(con, 0)) { + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_ASYNC: + case SSL_ERROR_WANT_READ: + /* Just keep trying - busy waiting */ + continue; + default: + BIO_printf(bio_err, "Error reading early data\n"); + ERR_print_errors(bio_err); + goto err; + } + } + if (readbytes > 0) + BIO_write(edio, buf, (int)readbytes); + } + } + for (;;) { - i = BIO_gets(io, buf, bufsize + 1); + i = BIO_gets(!BIO_eof(edio) ? edio : io, buf, bufsize + 1); if (i < 0) { /* error */ if (!BIO_should_retry(io) && !SSL_waiting_for_async(con)) { if (!s_quiet) @@ -3595,6 +3629,7 @@ static int www_body(int s, int stype, int prot, unsigned char *context) OPENSSL_free(buf); BIO_free(ssl_bio); BIO_free_all(io); + BIO_free_all(edio); return ret; } diff --git a/doc/man1/openssl-s_server.pod.in b/doc/man1/openssl-s_server.pod.in index 80f8c329929..b5ec29ad5f3 100644 --- a/doc/man1/openssl-s_server.pod.in +++ b/doc/man1/openssl-s_server.pod.in @@ -412,7 +412,6 @@ information about the ciphers used and various session parameters. The output is in HTML format so this option can be used with a web browser. The special URL C turns on client cert validation, and C tells the server to request renegotiation. -The B<-early_data> option cannot be used with this option. =item B<-WWW>, B<-HTTP> @@ -428,7 +427,6 @@ Extensions of C, C, and C are C and all others are C. In addition, the special URL C will return status information like the B<-www> option. -Neither of these options can be used in conjunction with B<-early_data>. =item B<-http_server_binmode> -- 2.47.2