Path: blob/main/crypto/openssl/doc/designs/ddd/ddd-03-fd-blocking.c
34889 views
#include <openssl/ssl.h>12/*3* Demo 3: Client — Client Creates FD — Blocking4* =============================================5*6* This is an example of (part of) an application which uses libssl in a simple,7* synchronous, blocking fashion. The client is responsible for creating the8* socket and passing it to libssl. The functions show all interactions with9* libssl the application makes, and would hypothetically be linked into a10* larger application.11*/1213/*14* The application is initializing and wants an SSL_CTX which it will use for15* some number of outgoing connections, which it creates in subsequent calls to16* new_conn. The application may also call this function multiple times to17* create multiple SSL_CTX.18*/19SSL_CTX *create_ssl_ctx(void)20{21SSL_CTX *ctx;2223#ifdef USE_QUIC24ctx = SSL_CTX_new(OSSL_QUIC_client_method());25#else26ctx = SSL_CTX_new(TLS_client_method());27#endif28if (ctx == NULL)29return NULL;3031/* Enable trust chain verification. */32SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);3334/* Load default root CA store. */35if (SSL_CTX_set_default_verify_paths(ctx) == 0) {36SSL_CTX_free(ctx);37return NULL;38}3940return ctx;41}4243/*44* The application wants to create a new outgoing connection using a given45* SSL_CTX.46*47* hostname is a string like "openssl.org" used for certificate validation.48*/49SSL *new_conn(SSL_CTX *ctx, int fd, const char *bare_hostname)50{51SSL *ssl;52#ifdef USE_QUIC53static const unsigned char alpn[] = {5, 'd', 'u', 'm', 'm', 'y'};54#endif5556ssl = SSL_new(ctx);57if (ssl == NULL)58return NULL;5960SSL_set_connect_state(ssl); /* cannot fail */6162if (SSL_set_fd(ssl, fd) <= 0) {63SSL_free(ssl);64return NULL;65}6667if (SSL_set1_host(ssl, bare_hostname) <= 0) {68SSL_free(ssl);69return NULL;70}7172if (SSL_set_tlsext_host_name(ssl, bare_hostname) <= 0) {73SSL_free(ssl);74return NULL;75}7677#ifdef USE_QUIC78/* Configure ALPN, which is required for QUIC. */79if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) {80/* Note: SSL_set_alpn_protos returns 1 for failure. */81SSL_free(ssl);82return NULL;83}84#endif8586return ssl;87}8889/*90* The application wants to send some block of data to the peer.91* This is a blocking call.92*/93int tx(SSL *ssl, const void *buf, int buf_len)94{95return SSL_write(ssl, buf, buf_len);96}9798/*99* The application wants to receive some block of data from100* the peer. This is a blocking call.101*/102int rx(SSL *ssl, void *buf, int buf_len)103{104return SSL_read(ssl, buf, buf_len);105}106107/*108* The application wants to close the connection and free bookkeeping109* structures.110*/111void teardown(SSL *ssl)112{113SSL_free(ssl);114}115116/*117* The application is shutting down and wants to free a previously118* created SSL_CTX.119*/120void teardown_ctx(SSL_CTX *ctx)121{122SSL_CTX_free(ctx);123}124125/*126* ============================================================================127* Example driver for the above code. This is just to demonstrate that the code128* works and is not intended to be representative of a real application.129*/130#include <sys/types.h>131#include <sys/socket.h>132#include <sys/signal.h>133#include <netdb.h>134#include <unistd.h>135136int main(int argc, char **argv)137{138int rc, fd = -1, l, mlen, res = 1;139static char msg[300];140struct addrinfo hints = {0}, *result = NULL;141SSL *ssl = NULL;142SSL_CTX *ctx = NULL;143char buf[2048];144145if (argc < 3) {146fprintf(stderr, "usage: %s host port\n", argv[0]);147goto fail;148}149150mlen = snprintf(msg, sizeof(msg),151"GET / HTTP/1.0\r\nHost: %s\r\n\r\n", argv[1]);152153ctx = create_ssl_ctx();154if (ctx == NULL) {155fprintf(stderr, "cannot create context\n");156goto fail;157}158159hints.ai_family = AF_INET;160hints.ai_socktype = SOCK_STREAM;161hints.ai_flags = AI_PASSIVE;162rc = getaddrinfo(argv[1], argv[2], &hints, &result);163if (rc < 0) {164fprintf(stderr, "cannot resolve\n");165goto fail;166}167168signal(SIGPIPE, SIG_IGN);169170#ifdef USE_QUIC171fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);172#else173fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);174#endif175if (fd < 0) {176fprintf(stderr, "cannot create socket\n");177goto fail;178}179180rc = connect(fd, result->ai_addr, result->ai_addrlen);181if (rc < 0) {182fprintf(stderr, "cannot connect\n");183goto fail;184}185186ssl = new_conn(ctx, fd, argv[1]);187if (ssl == NULL) {188fprintf(stderr, "cannot create connection\n");189goto fail;190}191192l = tx(ssl, msg, mlen);193if (l < mlen) {194fprintf(stderr, "tx error\n");195goto fail;196}197198for (;;) {199l = rx(ssl, buf, sizeof(buf));200if (l <= 0)201break;202fwrite(buf, 1, l, stdout);203}204205res = 0;206fail:207if (ssl != NULL)208teardown(ssl);209if (ctx != NULL)210teardown_ctx(ctx);211if (fd >= 0)212close(fd);213if (result != NULL)214freeaddrinfo(result);215return res;216}217218219