Path: blob/main/crypto/openssl/demos/guide/tls-client-block.c
34876 views
/*1* Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89/*10* NB: Changes to this file should also be reflected in11* doc/man7/ossl-guide-tls-client-block.pod12*/1314#include <string.h>1516/* Include the appropriate header file for SOCK_STREAM */17#ifdef _WIN32 /* Windows */18# include <winsock2.h>19#else /* Linux/Unix */20# include <sys/socket.h>21#endif2223#include <openssl/bio.h>24#include <openssl/ssl.h>25#include <openssl/err.h>2627/* Helper function to create a BIO connected to the server */28static BIO *create_socket_bio(const char *hostname, const char *port, int family)29{30int sock = -1;31BIO_ADDRINFO *res;32const BIO_ADDRINFO *ai = NULL;33BIO *bio;3435/*36* Lookup IP address info for the server.37*/38if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_STREAM, 0,39&res))40return NULL;4142/*43* Loop through all the possible addresses for the server and find one44* we can connect to.45*/46for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) {47/*48* Create a TCP socket. We could equally use non-OpenSSL calls such49* as "socket" here for this and the subsequent connect and close50* functions. But for portability reasons and also so that we get51* errors on the OpenSSL stack in the event of a failure we use52* OpenSSL's versions of these functions.53*/54sock = BIO_socket(BIO_ADDRINFO_family(ai), SOCK_STREAM, 0, 0);55if (sock == -1)56continue;5758/* Connect the socket to the server's address */59if (!BIO_connect(sock, BIO_ADDRINFO_address(ai), BIO_SOCK_NODELAY)) {60BIO_closesocket(sock);61sock = -1;62continue;63}6465/* We have a connected socket so break out of the loop */66break;67}6869/* Free the address information resources we allocated earlier */70BIO_ADDRINFO_free(res);7172/* If sock is -1 then we've been unable to connect to the server */73if (sock == -1)74return NULL;7576/* Create a BIO to wrap the socket */77bio = BIO_new(BIO_s_socket());78if (bio == NULL) {79BIO_closesocket(sock);80return NULL;81}8283/*84* Associate the newly created BIO with the underlying socket. By85* passing BIO_CLOSE here the socket will be automatically closed when86* the BIO is freed. Alternatively you can use BIO_NOCLOSE, in which87* case you must close the socket explicitly when it is no longer88* needed.89*/90BIO_set_fd(bio, sock, BIO_CLOSE);9192return bio;93}9495/*96* Simple application to send a basic HTTP/1.0 request to a server and97* print the response on the screen.98*/99int main(int argc, char *argv[])100{101SSL_CTX *ctx = NULL;102SSL *ssl = NULL;103BIO *bio = NULL;104int res = EXIT_FAILURE;105int ret;106const char *request_start = "GET / HTTP/1.0\r\nConnection: close\r\nHost: ";107const char *request_end = "\r\n\r\n";108size_t written, readbytes;109char buf[160];110char *hostname, *port;111int argnext = 1;112int ipv6 = 0;113114if (argc < 3) {115printf("Usage: tls-client-block [-6] hostname port\n");116goto end;117}118119if (!strcmp(argv[argnext], "-6")) {120if (argc < 4) {121printf("Usage: tls-client-block [-6] hostname port\n");122goto end;123}124ipv6 = 1;125argnext++;126}127hostname = argv[argnext++];128port = argv[argnext];129130/*131* Create an SSL_CTX which we can use to create SSL objects from. We132* want an SSL_CTX for creating clients so we use TLS_client_method()133* here.134*/135ctx = SSL_CTX_new(TLS_client_method());136if (ctx == NULL) {137printf("Failed to create the SSL_CTX\n");138goto end;139}140141/*142* Configure the client to abort the handshake if certificate143* verification fails. Virtually all clients should do this unless you144* really know what you are doing.145*/146SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);147148/* Use the default trusted certificate store */149if (!SSL_CTX_set_default_verify_paths(ctx)) {150printf("Failed to set the default trusted certificate store\n");151goto end;152}153154/*155* TLSv1.1 or earlier are deprecated by IETF and are generally to be156* avoided if possible. We require a minimum TLS version of TLSv1.2.157*/158if (!SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION)) {159printf("Failed to set the minimum TLS protocol version\n");160goto end;161}162163/* Create an SSL object to represent the TLS connection */164ssl = SSL_new(ctx);165if (ssl == NULL) {166printf("Failed to create the SSL object\n");167goto end;168}169170/*171* Create the underlying transport socket/BIO and associate it with the172* connection.173*/174bio = create_socket_bio(hostname, port, ipv6 ? AF_INET6 : AF_INET);175if (bio == NULL) {176printf("Failed to create the BIO\n");177goto end;178}179SSL_set_bio(ssl, bio, bio);180181/*182* Tell the server during the handshake which hostname we are attempting183* to connect to in case the server supports multiple hosts.184*/185if (!SSL_set_tlsext_host_name(ssl, hostname)) {186printf("Failed to set the SNI hostname\n");187goto end;188}189190/*191* Ensure we check during certificate verification that the server has192* supplied a certificate for the hostname that we were expecting.193* Virtually all clients should do this unless you really know what you194* are doing.195*/196if (!SSL_set1_host(ssl, hostname)) {197printf("Failed to set the certificate verification hostname");198goto end;199}200201/* Do the handshake with the server */202if (SSL_connect(ssl) < 1) {203printf("Failed to connect to the server\n");204/*205* If the failure is due to a verification error we can get more206* information about it from SSL_get_verify_result().207*/208if (SSL_get_verify_result(ssl) != X509_V_OK)209printf("Verify error: %s\n",210X509_verify_cert_error_string(SSL_get_verify_result(ssl)));211goto end;212}213214/* Write an HTTP GET request to the peer */215if (!SSL_write_ex(ssl, request_start, strlen(request_start), &written)) {216printf("Failed to write start of HTTP request\n");217goto end;218}219if (!SSL_write_ex(ssl, hostname, strlen(hostname), &written)) {220printf("Failed to write hostname in HTTP request\n");221goto end;222}223if (!SSL_write_ex(ssl, request_end, strlen(request_end), &written)) {224printf("Failed to write end of HTTP request\n");225goto end;226}227228/*229* Get up to sizeof(buf) bytes of the response. We keep reading until the230* server closes the connection.231*/232while (SSL_read_ex(ssl, buf, sizeof(buf), &readbytes)) {233/*234* OpenSSL does not guarantee that the returned data is a string or235* that it is NUL terminated so we use fwrite() to write the exact236* number of bytes that we read. The data could be non-printable or237* have NUL characters in the middle of it. For this simple example238* we're going to print it to stdout anyway.239*/240fwrite(buf, 1, readbytes, stdout);241}242/* In case the response didn't finish with a newline we add one now */243printf("\n");244245/*246* Check whether we finished the while loop above normally or as the247* result of an error. The 0 argument to SSL_get_error() is the return248* code we received from the SSL_read_ex() call. It must be 0 in order249* to get here. Normal completion is indicated by SSL_ERROR_ZERO_RETURN.250*/251if (SSL_get_error(ssl, 0) != SSL_ERROR_ZERO_RETURN) {252/*253* Some error occurred other than a graceful close down by the254* peer.255*/256printf ("Failed reading remaining data\n");257goto end;258}259260/*261* The peer already shutdown gracefully (we know this because of the262* SSL_ERROR_ZERO_RETURN above). We should do the same back.263*/264ret = SSL_shutdown(ssl);265if (ret < 1) {266/*267* ret < 0 indicates an error. ret == 0 would be unexpected here268* because that means "we've sent a close_notify and we're waiting269* for one back". But we already know we got one from the peer270* because of the SSL_ERROR_ZERO_RETURN above.271*/272printf("Error shutting down\n");273goto end;274}275276/* Success! */277res = EXIT_SUCCESS;278end:279/*280* If something bad happened then we will dump the contents of the281* OpenSSL error stack to stderr. There might be some useful diagnostic282* information there.283*/284if (res == EXIT_FAILURE)285ERR_print_errors_fp(stderr);286287/*288* Free the resources we allocated. We do not free the BIO object here289* because ownership of it was immediately transferred to the SSL object290* via SSL_set_bio(). The BIO will be freed when we free the SSL object.291*/292SSL_free(ssl);293SSL_CTX_free(ctx);294return res;295}296297298