Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/demos/guide/tls-client-block.c
34876 views
1
/*
2
* Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved.
3
*
4
* Licensed under the Apache License 2.0 (the "License"). You may not use
5
* this file except in compliance with the License. You can obtain a copy
6
* in the file LICENSE in the source distribution or at
7
* https://www.openssl.org/source/license.html
8
*/
9
10
/*
11
* NB: Changes to this file should also be reflected in
12
* doc/man7/ossl-guide-tls-client-block.pod
13
*/
14
15
#include <string.h>
16
17
/* Include the appropriate header file for SOCK_STREAM */
18
#ifdef _WIN32 /* Windows */
19
# include <winsock2.h>
20
#else /* Linux/Unix */
21
# include <sys/socket.h>
22
#endif
23
24
#include <openssl/bio.h>
25
#include <openssl/ssl.h>
26
#include <openssl/err.h>
27
28
/* Helper function to create a BIO connected to the server */
29
static BIO *create_socket_bio(const char *hostname, const char *port, int family)
30
{
31
int sock = -1;
32
BIO_ADDRINFO *res;
33
const BIO_ADDRINFO *ai = NULL;
34
BIO *bio;
35
36
/*
37
* Lookup IP address info for the server.
38
*/
39
if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_STREAM, 0,
40
&res))
41
return NULL;
42
43
/*
44
* Loop through all the possible addresses for the server and find one
45
* we can connect to.
46
*/
47
for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) {
48
/*
49
* Create a TCP socket. We could equally use non-OpenSSL calls such
50
* as "socket" here for this and the subsequent connect and close
51
* functions. But for portability reasons and also so that we get
52
* errors on the OpenSSL stack in the event of a failure we use
53
* OpenSSL's versions of these functions.
54
*/
55
sock = BIO_socket(BIO_ADDRINFO_family(ai), SOCK_STREAM, 0, 0);
56
if (sock == -1)
57
continue;
58
59
/* Connect the socket to the server's address */
60
if (!BIO_connect(sock, BIO_ADDRINFO_address(ai), BIO_SOCK_NODELAY)) {
61
BIO_closesocket(sock);
62
sock = -1;
63
continue;
64
}
65
66
/* We have a connected socket so break out of the loop */
67
break;
68
}
69
70
/* Free the address information resources we allocated earlier */
71
BIO_ADDRINFO_free(res);
72
73
/* If sock is -1 then we've been unable to connect to the server */
74
if (sock == -1)
75
return NULL;
76
77
/* Create a BIO to wrap the socket */
78
bio = BIO_new(BIO_s_socket());
79
if (bio == NULL) {
80
BIO_closesocket(sock);
81
return NULL;
82
}
83
84
/*
85
* Associate the newly created BIO with the underlying socket. By
86
* passing BIO_CLOSE here the socket will be automatically closed when
87
* the BIO is freed. Alternatively you can use BIO_NOCLOSE, in which
88
* case you must close the socket explicitly when it is no longer
89
* needed.
90
*/
91
BIO_set_fd(bio, sock, BIO_CLOSE);
92
93
return bio;
94
}
95
96
/*
97
* Simple application to send a basic HTTP/1.0 request to a server and
98
* print the response on the screen.
99
*/
100
int main(int argc, char *argv[])
101
{
102
SSL_CTX *ctx = NULL;
103
SSL *ssl = NULL;
104
BIO *bio = NULL;
105
int res = EXIT_FAILURE;
106
int ret;
107
const char *request_start = "GET / HTTP/1.0\r\nConnection: close\r\nHost: ";
108
const char *request_end = "\r\n\r\n";
109
size_t written, readbytes;
110
char buf[160];
111
char *hostname, *port;
112
int argnext = 1;
113
int ipv6 = 0;
114
115
if (argc < 3) {
116
printf("Usage: tls-client-block [-6] hostname port\n");
117
goto end;
118
}
119
120
if (!strcmp(argv[argnext], "-6")) {
121
if (argc < 4) {
122
printf("Usage: tls-client-block [-6] hostname port\n");
123
goto end;
124
}
125
ipv6 = 1;
126
argnext++;
127
}
128
hostname = argv[argnext++];
129
port = argv[argnext];
130
131
/*
132
* Create an SSL_CTX which we can use to create SSL objects from. We
133
* want an SSL_CTX for creating clients so we use TLS_client_method()
134
* here.
135
*/
136
ctx = SSL_CTX_new(TLS_client_method());
137
if (ctx == NULL) {
138
printf("Failed to create the SSL_CTX\n");
139
goto end;
140
}
141
142
/*
143
* Configure the client to abort the handshake if certificate
144
* verification fails. Virtually all clients should do this unless you
145
* really know what you are doing.
146
*/
147
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
148
149
/* Use the default trusted certificate store */
150
if (!SSL_CTX_set_default_verify_paths(ctx)) {
151
printf("Failed to set the default trusted certificate store\n");
152
goto end;
153
}
154
155
/*
156
* TLSv1.1 or earlier are deprecated by IETF and are generally to be
157
* avoided if possible. We require a minimum TLS version of TLSv1.2.
158
*/
159
if (!SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION)) {
160
printf("Failed to set the minimum TLS protocol version\n");
161
goto end;
162
}
163
164
/* Create an SSL object to represent the TLS connection */
165
ssl = SSL_new(ctx);
166
if (ssl == NULL) {
167
printf("Failed to create the SSL object\n");
168
goto end;
169
}
170
171
/*
172
* Create the underlying transport socket/BIO and associate it with the
173
* connection.
174
*/
175
bio = create_socket_bio(hostname, port, ipv6 ? AF_INET6 : AF_INET);
176
if (bio == NULL) {
177
printf("Failed to create the BIO\n");
178
goto end;
179
}
180
SSL_set_bio(ssl, bio, bio);
181
182
/*
183
* Tell the server during the handshake which hostname we are attempting
184
* to connect to in case the server supports multiple hosts.
185
*/
186
if (!SSL_set_tlsext_host_name(ssl, hostname)) {
187
printf("Failed to set the SNI hostname\n");
188
goto end;
189
}
190
191
/*
192
* Ensure we check during certificate verification that the server has
193
* supplied a certificate for the hostname that we were expecting.
194
* Virtually all clients should do this unless you really know what you
195
* are doing.
196
*/
197
if (!SSL_set1_host(ssl, hostname)) {
198
printf("Failed to set the certificate verification hostname");
199
goto end;
200
}
201
202
/* Do the handshake with the server */
203
if (SSL_connect(ssl) < 1) {
204
printf("Failed to connect to the server\n");
205
/*
206
* If the failure is due to a verification error we can get more
207
* information about it from SSL_get_verify_result().
208
*/
209
if (SSL_get_verify_result(ssl) != X509_V_OK)
210
printf("Verify error: %s\n",
211
X509_verify_cert_error_string(SSL_get_verify_result(ssl)));
212
goto end;
213
}
214
215
/* Write an HTTP GET request to the peer */
216
if (!SSL_write_ex(ssl, request_start, strlen(request_start), &written)) {
217
printf("Failed to write start of HTTP request\n");
218
goto end;
219
}
220
if (!SSL_write_ex(ssl, hostname, strlen(hostname), &written)) {
221
printf("Failed to write hostname in HTTP request\n");
222
goto end;
223
}
224
if (!SSL_write_ex(ssl, request_end, strlen(request_end), &written)) {
225
printf("Failed to write end of HTTP request\n");
226
goto end;
227
}
228
229
/*
230
* Get up to sizeof(buf) bytes of the response. We keep reading until the
231
* server closes the connection.
232
*/
233
while (SSL_read_ex(ssl, buf, sizeof(buf), &readbytes)) {
234
/*
235
* OpenSSL does not guarantee that the returned data is a string or
236
* that it is NUL terminated so we use fwrite() to write the exact
237
* number of bytes that we read. The data could be non-printable or
238
* have NUL characters in the middle of it. For this simple example
239
* we're going to print it to stdout anyway.
240
*/
241
fwrite(buf, 1, readbytes, stdout);
242
}
243
/* In case the response didn't finish with a newline we add one now */
244
printf("\n");
245
246
/*
247
* Check whether we finished the while loop above normally or as the
248
* result of an error. The 0 argument to SSL_get_error() is the return
249
* code we received from the SSL_read_ex() call. It must be 0 in order
250
* to get here. Normal completion is indicated by SSL_ERROR_ZERO_RETURN.
251
*/
252
if (SSL_get_error(ssl, 0) != SSL_ERROR_ZERO_RETURN) {
253
/*
254
* Some error occurred other than a graceful close down by the
255
* peer.
256
*/
257
printf ("Failed reading remaining data\n");
258
goto end;
259
}
260
261
/*
262
* The peer already shutdown gracefully (we know this because of the
263
* SSL_ERROR_ZERO_RETURN above). We should do the same back.
264
*/
265
ret = SSL_shutdown(ssl);
266
if (ret < 1) {
267
/*
268
* ret < 0 indicates an error. ret == 0 would be unexpected here
269
* because that means "we've sent a close_notify and we're waiting
270
* for one back". But we already know we got one from the peer
271
* because of the SSL_ERROR_ZERO_RETURN above.
272
*/
273
printf("Error shutting down\n");
274
goto end;
275
}
276
277
/* Success! */
278
res = EXIT_SUCCESS;
279
end:
280
/*
281
* If something bad happened then we will dump the contents of the
282
* OpenSSL error stack to stderr. There might be some useful diagnostic
283
* information there.
284
*/
285
if (res == EXIT_FAILURE)
286
ERR_print_errors_fp(stderr);
287
288
/*
289
* Free the resources we allocated. We do not free the BIO object here
290
* because ownership of it was immediately transferred to the SSL object
291
* via SSL_set_bio(). The BIO will be freed when we free the SSL object.
292
*/
293
SSL_free(ssl);
294
SSL_CTX_free(ctx);
295
return res;
296
}
297
298