openssl: fix subjectAltNames leak
[project/ustream-ssl.git] / ustream-example-client.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 #include <libubox/usock.h>
6 #include <libubox/uloop.h>
7 #include "ustream-ssl.h"
8
9 static struct uloop_fd fd;
10
11 static struct ustream_fd stream, s_input;
12 static struct ustream_ssl ssl;
13 static const char *host, *port;
14
15 static void *ctx;
16
17 static void client_teardown(void)
18 {
19         if (s_input.fd.registered)
20                 ustream_free(&s_input.stream);
21
22         ustream_free(&ssl.stream);
23         ustream_free(&stream.stream);
24         close(stream.fd.fd);
25         uloop_end();
26 }
27
28 static void client_input_notify_read(struct ustream *s, int bytes)
29 {
30         char *buf;
31         int len;
32
33         buf = ustream_get_read_buf(s, &len);
34         ustream_write(&ssl.stream, buf, len, false);
35         ustream_consume(s, len);
36 }
37
38 static void client_ssl_notify_read(struct ustream *s, int bytes)
39 {
40         char *buf;
41         int len;
42
43         buf = ustream_get_read_buf(s, &len);
44         fwrite(buf, len, 1, stdout);
45         fflush(stdout);
46         ustream_consume(s, len);
47 }
48
49 static void client_notify_connected(struct ustream_ssl *ssl)
50 {
51         fprintf(stderr, "SSL connection established (CN verified: %d)\n", ssl->valid_cn);
52         s_input.stream.notify_read = client_input_notify_read;
53         ustream_fd_init(&s_input, 0);
54 }
55
56 static void client_notify_error(struct ustream_ssl *ssl, int error, const char *str)
57 {
58         fprintf(stderr, "SSL connection error(%d): %s\n", error, str);
59         client_teardown();
60 }
61
62 static void client_notify_verify_error(struct ustream_ssl *ssl, int error, const char *str)
63 {
64         fprintf(stderr, "WARNING: SSL certificate error(%d): %s\n", error, str);
65 }
66
67 static void client_notify_state(struct ustream *us)
68 {
69         if (!us->write_error && !us->eof)
70                 return;
71
72         fprintf(stderr, "Connection closed\n");
73         client_teardown();
74 }
75
76 static void example_connect_ssl(int fd)
77 {
78         fprintf(stderr, "Starting SSL negnotiation\n");
79
80         ssl.notify_error = client_notify_error;
81         ssl.notify_verify_error = client_notify_verify_error;
82         ssl.notify_connected = client_notify_connected;
83         ssl.stream.notify_read = client_ssl_notify_read;
84         ssl.stream.notify_state = client_notify_state;
85
86         ustream_fd_init(&stream, fd);
87         ustream_ssl_init(&ssl, &stream.stream, ctx, false);
88         ustream_ssl_set_peer_cn(&ssl, host);
89 }
90
91 static void example_connect_cb(struct uloop_fd *f, unsigned int events)
92 {
93         if (fd.eof || fd.error) {
94                 fprintf(stderr, "Connection failed\n");
95                 uloop_end();
96                 return;
97         }
98
99         fprintf(stderr, "Connection established\n");
100         uloop_fd_delete(&fd);
101         example_connect_ssl(fd.fd);
102 }
103
104 static void connect_client(void)
105 {
106         fd.fd = usock(USOCK_TCP | USOCK_NONBLOCK, host, port);
107         fd.cb = example_connect_cb;
108         uloop_fd_add(&fd, ULOOP_WRITE | ULOOP_EDGE_TRIGGER);
109 }
110
111 static int usage(const char *progname)
112 {
113         fprintf(stderr,
114                 "Usage: %s [options] <hostname> <port>\n"
115                 "Options:\n"
116                 "       -c <cert>:         Load CA certificates from file <cert>\n"
117                 "\n", progname);
118         return 1;
119 }
120
121 int main(int argc, char **argv)
122 {
123         const char *progname = argv[0];
124         int ch;
125
126         ctx = ustream_ssl_context_new(false);
127
128         while ((ch = getopt(argc, argv, "c:")) != -1) {
129                 switch(ch) {
130                 case 'c':
131                         ustream_ssl_context_add_ca_crt_file(ctx, optarg);
132                         break;
133                 default:
134                         return usage(progname);
135                 }
136         }
137
138         argv += optind;
139         argc -= optind;
140
141         if (argc != 2)
142                 return usage(progname);
143
144         uloop_init();
145         host = argv[0];
146         port = argv[1];
147         connect_client();
148         uloop_run();
149
150         close(fd.fd);
151         uloop_done();
152         return 0;
153 }