1 #include <openssl/ssl.h> 2 3 /* 4 * Demo 1: Client — Managed Connection — Blocking 5 * ============================================== 6 * 7 * This is an example of (part of) an application which uses libssl in a simple, 8 * synchronous, blocking fashion. The functions show all interactions with 9 * libssl the application makes, and would hypothetically be linked into a 10 * larger application. 11 */ 12 13 /* 14 * The application is initializing and wants an SSL_CTX which it will use for 15 * some number of outgoing connections, which it creates in subsequent calls to 16 * new_conn. The application may also call this function multiple times to 17 * create multiple SSL_CTX. 18 */ 19 SSL_CTX *create_ssl_ctx(void) 20 { 21 SSL_CTX *ctx; 22 23 #ifdef USE_QUIC 24 ctx = SSL_CTX_new(OSSL_QUIC_client_method()); 25 #else 26 ctx = SSL_CTX_new(TLS_client_method()); 27 #endif 28 if (ctx == NULL) 29 return NULL; 30 31 /* Enable trust chain verification. */ 32 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 33 34 /* Load default root CA store. */ 35 if (SSL_CTX_set_default_verify_paths(ctx) == 0) { 36 SSL_CTX_free(ctx); 37 return NULL; 38 } 39 40 return ctx; 41 } 42 43 /* 44 * The application wants to create a new outgoing connection using a given 45 * SSL_CTX. 46 * 47 * hostname is a string like "openssl.org:443" or "[::1]:443". 48 */ 49 BIO *new_conn(SSL_CTX *ctx, const char *hostname) 50 { 51 BIO *out; 52 SSL *ssl = NULL; 53 const char *bare_hostname; 54 #ifdef USE_QUIC 55 static const unsigned char alpn[] = {5, 'd', 'u', 'm', 'm', 'y'}; 56 #endif 57 58 out = BIO_new_ssl_connect(ctx); 59 if (out == NULL) 60 return NULL; 61 62 if (BIO_get_ssl(out, &ssl) == 0) { 63 BIO_free_all(out); 64 return NULL; 65 } 66 67 if (BIO_set_conn_hostname(out, hostname) == 0) { 68 BIO_free_all(out); 69 return NULL; 70 } 71 72 /* Returns the parsed hostname extracted from the hostname:port string. */ 73 bare_hostname = BIO_get_conn_hostname(out); 74 if (bare_hostname == NULL) { 75 BIO_free_all(out); 76 return NULL; 77 } 78 79 /* Tell the SSL object the hostname to check certificates against. */ 80 if (SSL_set1_host(ssl, bare_hostname) <= 0) { 81 BIO_free_all(out); 82 return NULL; 83 } 84 85 #ifdef USE_QUIC 86 /* Configure ALPN, which is required for QUIC. */ 87 if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) { 88 /* Note: SSL_set_alpn_protos returns 1 for failure. */ 89 BIO_free_all(out); 90 return NULL; 91 } 92 #endif 93 94 return out; 95 } 96 97 /* 98 * The application wants to send some block of data to the peer. 99 * This is a blocking call. 100 */ 101 int tx(BIO *bio, const void *buf, int buf_len) 102 { 103 return BIO_write(bio, buf, buf_len); 104 } 105 106 /* 107 * The application wants to receive some block of data from 108 * the peer. This is a blocking call. 109 */ 110 int rx(BIO *bio, void *buf, int buf_len) 111 { 112 return BIO_read(bio, buf, buf_len); 113 } 114 115 /* 116 * The application wants to close the connection and free bookkeeping 117 * structures. 118 */ 119 void teardown(BIO *bio) 120 { 121 BIO_free_all(bio); 122 } 123 124 /* 125 * The application is shutting down and wants to free a previously 126 * created SSL_CTX. 127 */ 128 void teardown_ctx(SSL_CTX *ctx) 129 { 130 SSL_CTX_free(ctx); 131 } 132 133 /* 134 * ============================================================================ 135 * Example driver for the above code. This is just to demonstrate that the code 136 * works and is not intended to be representative of a real application. 137 */ 138 int main(int argc, char **argv) 139 { 140 static char msg[384], host_port[300]; 141 SSL_CTX *ctx = NULL; 142 BIO *b = NULL; 143 char buf[2048]; 144 int l, mlen, res = 1; 145 146 if (argc < 3) { 147 fprintf(stderr, "usage: %s host port\n", argv[0]); 148 goto fail; 149 } 150 151 snprintf(host_port, sizeof(host_port), "%s:%s", argv[1], argv[2]); 152 mlen = snprintf(msg, sizeof(msg), 153 "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", argv[1]); 154 155 ctx = create_ssl_ctx(); 156 if (ctx == NULL) { 157 fprintf(stderr, "could not create context\n"); 158 goto fail; 159 } 160 161 b = new_conn(ctx, host_port); 162 if (b == NULL) { 163 fprintf(stderr, "could not create connection\n"); 164 goto fail; 165 } 166 167 l = tx(b, msg, mlen); 168 if (l < mlen) { 169 fprintf(stderr, "tx error\n"); 170 goto fail; 171 } 172 173 for (;;) { 174 l = rx(b, buf, sizeof(buf)); 175 if (l <= 0) 176 break; 177 fwrite(buf, 1, l, stdout); 178 } 179 180 res = 0; 181 fail: 182 if (b != NULL) 183 teardown(b); 184 if (ctx != NULL) 185 teardown_ctx(ctx); 186 return res; 187 } 188