1 #include <openssl/ssl.h> 2 3 /* 4 * Demo 3: Client — Client Creates FD — Blocking 5 * ============================================= 6 * 7 * This is an example of (part of) an application which uses libssl in a simple, 8 * synchronous, blocking fashion. The client is responsible for creating the 9 * socket and passing it to libssl. The functions show all interactions with 10 * libssl the application makes, and would hypothetically be linked into a 11 * larger application. 12 */ 13 14 /* 15 * The application is initializing and wants an SSL_CTX which it will use for 16 * some number of outgoing connections, which it creates in subsequent calls to 17 * new_conn. The application may also call this function multiple times to 18 * create multiple SSL_CTX. 19 */ 20 SSL_CTX *create_ssl_ctx(void) 21 { 22 SSL_CTX *ctx; 23 24 #ifdef USE_QUIC 25 ctx = SSL_CTX_new(OSSL_QUIC_client_method()); 26 #else 27 ctx = SSL_CTX_new(TLS_client_method()); 28 #endif 29 if (ctx == NULL) 30 return NULL; 31 32 /* Enable trust chain verification. */ 33 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 34 35 /* Load default root CA store. */ 36 if (SSL_CTX_set_default_verify_paths(ctx) == 0) { 37 SSL_CTX_free(ctx); 38 return NULL; 39 } 40 41 return ctx; 42 } 43 44 /* 45 * The application wants to create a new outgoing connection using a given 46 * SSL_CTX. 47 * 48 * hostname is a string like "openssl.org" used for certificate validation. 49 */ 50 SSL *new_conn(SSL_CTX *ctx, int fd, const char *bare_hostname) 51 { 52 SSL *ssl; 53 #ifdef USE_QUIC 54 static const unsigned char alpn[] = {5, 'd', 'u', 'm', 'm', 'y'}; 55 #endif 56 57 ssl = SSL_new(ctx); 58 if (ssl == NULL) 59 return NULL; 60 61 SSL_set_connect_state(ssl); /* cannot fail */ 62 63 if (SSL_set_fd(ssl, fd) <= 0) { 64 SSL_free(ssl); 65 return NULL; 66 } 67 68 if (SSL_set1_host(ssl, bare_hostname) <= 0) { 69 SSL_free(ssl); 70 return NULL; 71 } 72 73 if (SSL_set_tlsext_host_name(ssl, bare_hostname) <= 0) { 74 SSL_free(ssl); 75 return NULL; 76 } 77 78 #ifdef USE_QUIC 79 /* Configure ALPN, which is required for QUIC. */ 80 if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) { 81 /* Note: SSL_set_alpn_protos returns 1 for failure. */ 82 SSL_free(ssl); 83 return NULL; 84 } 85 #endif 86 87 return ssl; 88 } 89 90 /* 91 * The application wants to send some block of data to the peer. 92 * This is a blocking call. 93 */ 94 int tx(SSL *ssl, const void *buf, int buf_len) 95 { 96 return SSL_write(ssl, buf, buf_len); 97 } 98 99 /* 100 * The application wants to receive some block of data from 101 * the peer. This is a blocking call. 102 */ 103 int rx(SSL *ssl, void *buf, int buf_len) 104 { 105 return SSL_read(ssl, buf, buf_len); 106 } 107 108 /* 109 * The application wants to close the connection and free bookkeeping 110 * structures. 111 */ 112 void teardown(SSL *ssl) 113 { 114 SSL_free(ssl); 115 } 116 117 /* 118 * The application is shutting down and wants to free a previously 119 * created SSL_CTX. 120 */ 121 void teardown_ctx(SSL_CTX *ctx) 122 { 123 SSL_CTX_free(ctx); 124 } 125 126 /* 127 * ============================================================================ 128 * Example driver for the above code. This is just to demonstrate that the code 129 * works and is not intended to be representative of a real application. 130 */ 131 #include <sys/types.h> 132 #include <sys/socket.h> 133 #include <sys/signal.h> 134 #include <netdb.h> 135 #include <unistd.h> 136 137 int main(int argc, char **argv) 138 { 139 int rc, fd = -1, l, mlen, res = 1; 140 static char msg[300]; 141 struct addrinfo hints = {0}, *result = NULL; 142 SSL *ssl = NULL; 143 SSL_CTX *ctx = NULL; 144 char buf[2048]; 145 146 if (argc < 3) { 147 fprintf(stderr, "usage: %s host port\n", argv[0]); 148 goto fail; 149 } 150 151 mlen = snprintf(msg, sizeof(msg), 152 "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", argv[1]); 153 154 ctx = create_ssl_ctx(); 155 if (ctx == NULL) { 156 fprintf(stderr, "cannot create context\n"); 157 goto fail; 158 } 159 160 hints.ai_family = AF_INET; 161 hints.ai_socktype = SOCK_STREAM; 162 hints.ai_flags = AI_PASSIVE; 163 rc = getaddrinfo(argv[1], argv[2], &hints, &result); 164 if (rc < 0) { 165 fprintf(stderr, "cannot resolve\n"); 166 goto fail; 167 } 168 169 signal(SIGPIPE, SIG_IGN); 170 171 #ifdef USE_QUIC 172 fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 173 #else 174 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 175 #endif 176 if (fd < 0) { 177 fprintf(stderr, "cannot create socket\n"); 178 goto fail; 179 } 180 181 rc = connect(fd, result->ai_addr, result->ai_addrlen); 182 if (rc < 0) { 183 fprintf(stderr, "cannot connect\n"); 184 goto fail; 185 } 186 187 ssl = new_conn(ctx, fd, argv[1]); 188 if (ssl == NULL) { 189 fprintf(stderr, "cannot create connection\n"); 190 goto fail; 191 } 192 193 l = tx(ssl, msg, mlen); 194 if (l < mlen) { 195 fprintf(stderr, "tx error\n"); 196 goto fail; 197 } 198 199 for (;;) { 200 l = rx(ssl, buf, sizeof(buf)); 201 if (l <= 0) 202 break; 203 fwrite(buf, 1, l, stdout); 204 } 205 206 res = 0; 207 fail: 208 if (ssl != NULL) 209 teardown(ssl); 210 if (ctx != NULL) 211 teardown_ctx(ctx); 212 if (fd >= 0) 213 close(fd); 214 if (result != NULL) 215 freeaddrinfo(result); 216 return res; 217 } 218