Update the OpenSSL Guide tutorials with changes to the demos

The demo code has changed to accept the hostname/port on the command line.
We update the tutorials to keep in sync with the demo code.

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22552)
This commit is contained in:
Matt Caswell 2023-10-30 12:39:37 +00:00 committed by Hugo Landau
parent cb8107b632
commit 9e973eb297
4 changed files with 84 additions and 26 deletions

View File

@ -341,13 +341,26 @@ data on a retry. An optional mode does exist
the buffer being written to change from one retry to the next. However, in this
case, you must still retry exactly the same data - even though the buffer that
contains that data may change location. See L<SSL_CTX_set_mode(3)> for further
details.
details. As in the TLS tutorials (L<ossl-guide-tls-client-block(7)>) we write
the request in three chunks.
/* Write an HTTP GET request to the peer */
while (!SSL_write_ex(ssl, request, strlen(request), &written)) {
while (!SSL_write_ex(ssl, request_start, strlen(request_start), &written)) {
if (handle_io_failure(ssl, 0) == 1)
continue; /* Retry */
printf("Failed to write HTTP request\n");
printf("Failed to write start of HTTP request\n");
goto end; /* Cannot retry: error */
}
while (!SSL_write_ex(ssl, hostname, strlen(hostname), &written)) {
if (handle_io_failure(ssl, 0) == 1)
continue; /* Retry */
printf("Failed to write hostname in HTTP request\n");
goto end; /* Cannot retry: error */
}
while (!SSL_write_ex(ssl, request_end, strlen(request_end), &written)) {
if (handle_io_failure(ssl, 0) == 1)
continue; /* Retry */
printf("Failed to write end of HTTP request\n");
goto end; /* Cannot retry: error */
}

View File

@ -213,23 +213,43 @@ uni-directional one:
=head2 Writing data to the streams
Once the streams are successfully created we can start writing data to them. In
this example we will be sending a different HTTP request on each stream. We
assume the strings B<request1> and B<request2> hold the appropriate HTTP
requests. For the sake of simplicity this example does this sequentially,
writing to B<stream1> first and, when this is successful, writing to B<stream2>
second. Remember that our client is blocking so these calls will only return
once they have been successfully completed. A real application would not need to
do these writes sequentially or in any particular order. For example we could
start two threads (one for each stream) and write the requests to each stream
simultaneously.
this example we will be sending a different HTTP request on each stream. To
avoid repeating too much code we write a simple helper function to send an HTTP
request to a stream:
int write_a_request(SSL *stream, const char *request_start,
const char *hostname)
{
const char *request_end = "\r\n\r\n";
size_t written;
if (!SSL_write_ex(stream, request_start, strlen(request_start), &written))
return 0;
if (!SSL_write_ex(stream, hostname, strlen(hostname), &written))
return 0;
if (!SSL_write_ex(stream, request_end, strlen(request_end), &written))
return 0;
return 1;
}
We assume the strings B<request1_start> and B<request2_start> hold the
appropriate HTTP requests. We can then call our helper function above to send
the requests on the two streams. For the sake of simplicity this example does
this sequentially, writing to B<stream1> first and, when this is successful,
writing to B<stream2> second. Remember that our client is blocking so these
calls will only return once they have been successfully completed. A real
application would not need to do these writes sequentially or in any particular
order. For example we could start two threads (one for each stream) and write
the requests to each stream simultaneously.
/* Write an HTTP GET request on each of our streams to the peer */
if (!SSL_write_ex(stream1, request1, strlen(request1), &written)) {
if (!write_a_request(stream1, request1_start, hostname)) {
printf("Failed to write HTTP request on stream 1\n");
goto end;
}
if (!SSL_write_ex(stream2, request2, strlen(request2), &written)) {
if (!write_a_request(stream2, request2_start, hostname)) {
printf("Failed to write HTTP request on stream 2\n");
goto end;
}

View File

@ -272,13 +272,13 @@ like this:
* Tell the server during the handshake which hostname we are attempting
* to connect to in case the server supports multiple hosts.
*/
if (!SSL_set_tlsext_host_name(ssl, HOSTNAME)) {
if (!SSL_set_tlsext_host_name(ssl, hostname)) {
printf("Failed to set the SNI hostname\n");
goto end;
}
Here the HOSTNAME argument is a string representing the hostname of the server,
e.g. "www.example.com".
Here the C<hostname> argument is a string representing the hostname of the
server, e.g. "www.example.com".
Secondly, we need to tell OpenSSL what hostname we expect to see in the
certificate coming back from the server. This is almost always the same one that
@ -293,7 +293,7 @@ itself. We do this via the L<SSL_set1_host(3)> function:
* Virtually all clients should do this unless you really know what you
* are doing.
*/
if (!SSL_set1_host(ssl, HOSTNAME)) {
if (!SSL_set1_host(ssl, hostname)) {
printf("Failed to set the certificate verification hostname");
goto end;
}
@ -345,15 +345,26 @@ connection.
To send data to the server we use the L<SSL_write_ex(3)> function and to receive
data from the server we use the L<SSL_read_ex(3)> function. In HTTP 1.0 the
client always writes data first.
client always writes data first. Our HTTP request will include the hostname that
we are connecting to. For simplicitly, we write the HTTP request in three
chunks. First we write the start of the request. Secondly we write the hostname
we are sending the request to. Finally we send the end of the request.
size_t written;
const char *request =
"GET / HTTP/1.0\r\nConnection: close\r\nHost: "HOSTNAME"\r\n\r\n";
const char *request_start = "GET / HTTP/1.0\r\nConnection: close\r\nHost: ";
const char *request_end = "\r\n\r\n";
/* Write an HTTP GET request to the peer */
if (!SSL_write_ex(ssl, request, strlen(request), &written)) {
printf("Failed to write HTTP request\n");
if (!SSL_write_ex(ssl, request_start, strlen(request_start), &written)) {
printf("Failed to write start of HTTP request\n");
goto end;
}
if (!SSL_write_ex(ssl, hostname, strlen(hostname), &written)) {
printf("Failed to write hostname in HTTP request\n");
goto end;
}
if (!SSL_write_ex(ssl, request_end, strlen(request_end), &written)) {
printf("Failed to write end of HTTP request\n");
goto end;
}

View File

@ -252,13 +252,27 @@ retry. An optional mode does exist (B<SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER>)
which will configure OpenSSL to allow the buffer being written to change from
one retry to the next. However, in this case, you must still retry exactly the
same data - even though the buffer that contains that data may change location.
See L<SSL_CTX_set_mode(3)> for further details.
See L<SSL_CTX_set_mode(3)> for further details. As in the TLS client
blocking tutorial (L<ossl-guide-tls-client-block(7)>) we write the request
in three chunks.
/* Write an HTTP GET request to the peer */
while (!SSL_write_ex(ssl, request, strlen(request), &written)) {
while (!SSL_write_ex(ssl, request_start, strlen(request_start), &written)) {
if (handle_io_failure(ssl, 0) == 1)
continue; /* Retry */
printf("Failed to write HTTP request\n");
printf("Failed to write start of HTTP request\n");
goto end; /* Cannot retry: error */
}
while (!SSL_write_ex(ssl, hostname, strlen(hostname), &written)) {
if (handle_io_failure(ssl, 0) == 1)
continue; /* Retry */
printf("Failed to write hostname in HTTP request\n");
goto end; /* Cannot retry: error */
}
while (!SSL_write_ex(ssl, request_end, strlen(request_end), &written)) {
if (handle_io_failure(ssl, 0) == 1)
continue; /* Retry */
printf("Failed to write end of HTTP request\n");
goto end; /* Cannot retry: error */
}