add client example code
[project/ustream-ssl.git] / ustream-openssl.c
1 /*
2  * ustream-ssl - library for SSL over ustream
3  *
4  * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include "ustream-ssl.h"
20 #include "ustream-internal.h"
21
22 __hidden struct ustream_ssl_ctx *
23 __ustream_ssl_context_new(bool server)
24 {
25         static bool _init = false;
26         const void *m;
27         SSL_CTX *c;
28
29         if (!_init) {
30                 SSL_load_error_strings();
31                 SSL_library_init();
32                 _init = true;
33         }
34
35 #ifdef CYASSL_OPENSSL_H_
36         if (server)
37                 m = SSLv23_server_method();
38         else
39                 m = SSLv23_client_method();
40 #else
41         if (server)
42                 m = TLSv1_server_method();
43         else
44                 m = TLSv1_client_method();
45 #endif
46
47         c = SSL_CTX_new((void *) m);
48         if (!c)
49                 return NULL;
50
51         if (server)
52                 SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
53
54         return (void *) c;
55 }
56
57 __hidden int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx *ctx, const char *file)
58 {
59         int ret;
60
61         ret = SSL_CTX_use_certificate_file((void *) ctx, file, SSL_FILETYPE_PEM);
62         if (ret < 1)
63                 ret = SSL_CTX_use_certificate_file((void *) ctx, file, SSL_FILETYPE_ASN1);
64
65         if (ret < 1)
66                 return -1;
67
68         return 0;
69 }
70
71 __hidden int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char *file)
72 {
73         int ret;
74
75         ret = SSL_CTX_use_PrivateKey_file((void *) ctx, file, SSL_FILETYPE_PEM);
76         if (ret < 1)
77                 ret = SSL_CTX_use_PrivateKey_file((void *) ctx, file, SSL_FILETYPE_ASN1);
78
79         if (ret < 1)
80                 return -1;
81
82         return 0;
83 }
84
85 __hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx)
86 {
87         SSL_CTX_free((void *) ctx);
88 }
89
90 static void ustream_ssl_error(struct ustream_ssl *us, int ret)
91 {
92         us->error = ret;
93         uloop_timeout_set(&us->error_timer, 0);
94 }
95
96 __hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us)
97 {
98         void *ssl = us->ssl;
99         int r;
100
101         if (us->server)
102                 r = SSL_accept(ssl);
103         else
104                 r = SSL_connect(ssl);
105
106         if (r == 1)
107                 return U_SSL_OK;
108
109         r = SSL_get_error(ssl, r);
110         if (r == SSL_ERROR_WANT_READ || r == SSL_ERROR_WANT_WRITE)
111                 return U_SSL_PENDING;
112
113         ustream_ssl_error(us, r);
114         return U_SSL_ERROR;
115 }
116
117 __hidden int __ustream_ssl_write(struct ustream_ssl *us, const char *buf, int len)
118 {
119         void *ssl = us->ssl;
120         int ret = SSL_write(ssl, buf, len);
121
122         if (ret < 0) {
123                 int err = SSL_get_error(ssl, ret);
124                 if (err == SSL_ERROR_WANT_WRITE)
125                         return 0;
126
127                 ustream_ssl_error(us, err);
128                 return -1;
129         }
130
131         return ret;
132 }
133
134 __hidden int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len)
135 {
136         int ret = SSL_read(us->ssl, buf, len);
137
138         if (ret < 0) {
139                 ret = SSL_get_error(us->ssl, ret);
140                 if (ret == SSL_ERROR_WANT_READ)
141                         return U_SSL_PENDING;
142
143                 ustream_ssl_error(us, ret);
144                 return U_SSL_ERROR;
145         }
146
147         return ret;
148 }
149