v / vlib / net / openssl / openssl.c.v
197 lines · 145 sloc · 6.16 KB · 8e3e67eff2703ee6a931953575b6c236e7349712
Raw
1module openssl
2
3#define OPENSSL_API_COMPAT 0x30000000L
4
5// On Linux, prefer a locally built openssl, because it is
6// much more likely for it to be newer, than the system
7// openssl from libssl-dev. If there is no local openssl,
8// the next #pkgconfig flag is harmless, since it will still
9// use the (older) system openssl.
10#flag linux -I/usr/local/include/openssl
11#flag linux -L/usr/local/lib64
12// On FreeBSD, prefer openssl from the ports collection, because
13// it is much more likely for it to be newer, than the system
14// openssl.
15#flag freebsd -I/usr/local/include
16#flag freebsd -L/usr/local/lib
17
18// Installed through choco:
19#flag windows -IC:/Program Files/OpenSSL-Win64/include
20#flag windows -LC:/Program Files/OpenSSL-Win64/lib/VC/x64/MD
21
22// Installed on the CI:
23#flag windows -IC:/Program Files/OpenSSL/include
24#flag windows -LC:/Program Files/OpenSSL/lib/VC/x64/MD
25
26$if $pkgconfig('openssl') {
27 #pkgconfig --cflags --libs openssl
28} $else {
29 #flag windows -l libssl -l libcrypto
30 $if !windows {
31 #flag -lssl -lcrypto
32 }
33 #flag linux -ldl -lpthread
34 // Prefer a single matching macOS OpenSSL prefix to avoid mixing Intel and arm64 installs.
35 $if arm64 {
36 #flag darwin -I$when_first_existing('/opt/local/include','/opt/homebrew/opt/openssl/include','/opt/homebrew/opt/openssl@3/include','/opt/procursus/include','/usr/local/opt/openssl/include','/usr/local/opt/openssl@3/include')
37 #flag darwin -L$when_first_existing('/opt/local/lib','/opt/homebrew/opt/openssl/lib','/opt/homebrew/opt/openssl@3/lib','/opt/procursus/lib','/usr/local/opt/openssl/lib','/usr/local/opt/openssl@3/lib')
38 } $else {
39 #flag darwin -I$when_first_existing('/opt/local/include','/usr/local/opt/openssl/include','/usr/local/opt/openssl@3/include','/opt/procursus/include','/opt/homebrew/opt/openssl/include','/opt/homebrew/opt/openssl@3/include')
40 #flag darwin -L$when_first_existing('/opt/local/lib','/usr/local/opt/openssl/lib','/usr/local/opt/openssl@3/lib','/opt/procursus/lib','/opt/homebrew/opt/openssl/lib','/opt/homebrew/opt/openssl@3/lib')
41 }
42}
43
44#include <openssl/rand.h> # Please install OpenSSL development headers
45#include <openssl/ssl.h>
46#include <openssl/err.h>
47#insert "@VEXEROOT/vlib/net/openssl/openssl_compat.h"
48
49@[typedef]
50pub struct C.SSL {
51}
52
53@[typedef]
54pub struct C.BIO {
55}
56
57@[typedef]
58pub struct C.SSL_METHOD {
59}
60
61@[typedef]
62pub struct C.X509 {
63}
64
65@[typedef]
66pub struct C.SSL_CTX {
67}
68
69// The above C structs, have incomplete declarations in the OpenSSL headers.
70// For this reason, we have to prevent the automatic str() generation for them,
71// by adding manual implementations of their .str() methods, that are defined on
72// pointers to them:
73fn (s &C.SSL) str() string {
74 return 'C.SSL(0x${voidptr(s)})'
75}
76
77fn (c &C.SSL_CTX) str() string {
78 return 'C.SSL_CTX(0x${voidptr(c)})'
79}
80
81fn C.BIO_new_ssl_connect(ctx &C.SSL_CTX) &C.BIO
82
83fn C.BIO_set_conn_hostname(b &C.BIO, name &char) i32
84
85// there are actually 2 macros for BIO_get_ssl
86// fn C.BIO_get_ssl(bp &C.BIO, ssl charptr, c int)
87// fn C.BIO_get_ssl(bp &C.BIO, sslp charptr)
88fn C.BIO_get_ssl(bp &C.BIO, vargs ...voidptr)
89
90fn C.BIO_do_connect(b &C.BIO) i32
91
92fn C.BIO_do_handshake(b &C.BIO) i32
93
94fn C.BIO_puts(b &C.BIO, buf &char)
95
96fn C.BIO_read(b &C.BIO, buf voidptr, len i32) i32
97
98fn C.BIO_free_all(a &C.BIO)
99
100fn C.SSL_CTX_new(method &C.SSL_METHOD) &C.SSL_CTX
101
102fn C.SSL_CTX_set_options(ctx &C.SSL_CTX, options i32)
103
104fn C.SSL_CTX_set_verify_depth(s &C.SSL_CTX, depth i32)
105
106fn C.SSL_CTX_load_verify_locations(ctx &C.SSL_CTX, const_file &char, ca_path &char) i32
107
108fn C.SSL_CTX_free(ctx &C.SSL_CTX)
109
110fn C.SSL_CTX_use_certificate_file(ctx &C.SSL_CTX, const_file &char, file_type i32) i32
111
112fn C.SSL_CTX_use_PrivateKey_file(ctx &C.SSL_CTX, const_file &char, file_type i32) i32
113
114fn C.SSL_new(&C.SSL_CTX) &C.SSL
115
116fn C.SSL_set_fd(ssl &C.SSL, fd i32) i32
117
118fn C.SSL_connect(&C.SSL) i32
119
120fn C.SSL_do_handshake(&C.SSL) i32
121
122fn C.SSL_set_cipher_list(ctx &C.SSL, str &char) i32
123
124fn C.v_net_openssl_get1_peer_certificate(ssl &C.SSL) &C.X509
125
126fn C.X509_free(const_cert &C.X509)
127
128fn C.ERR_clear_error()
129
130fn C.SSL_get_error(ssl &C.SSL, ret i32) i32
131
132fn C.SSL_get_verify_result(ssl &C.SSL) i32
133
134fn C.SSL_set_tlsext_host_name(s &C.SSL, name &char) i32
135
136// The ALPN calls go through small version-guarded shims in openssl_compat.h,
137// so the module still links against OpenSSL versions older than 1.0.2 that
138// predate ALPN. v_net_openssl_set_alpn_protos returns 0 on success (like the
139// underlying SSL_set_alpn_protos) and non-zero when ALPN is unavailable.
140// `data` is `const unsigned char **`; declared as voidptr so V emits a clean
141// `(void*)` cast and avoids -cstrict nested-pointer const warnings.
142fn C.v_net_openssl_set_alpn_protos(ssl &C.SSL, protos &u8, protos_len u32) i32
143
144fn C.v_net_openssl_get0_alpn_selected(ssl &C.SSL, data voidptr, len &u32)
145
146fn C.SSL_shutdown(&C.SSL) i32
147
148fn C.SSL_free(&C.SSL)
149
150fn C.SSL_write(ssl &C.SSL, buf voidptr, buflen i32) i32
151
152fn C.SSL_read(ssl &C.SSL, buf voidptr, buflen i32) i32
153
154fn C.SSLv23_client_method() &C.SSL_METHOD
155
156fn C.TLS_method() voidptr
157
158fn C.TLSv1_2_method() voidptr
159
160fn C.v_net_openssl_init_ssl() i32
161
162fn init() {
163 C.v_net_openssl_init_ssl()
164}
165
166// ssl_error returns non error ssl code or error if unrecoverable and we should panic
167fn ssl_error(ret int, ssl voidptr) !SSLError {
168 res := C.SSL_get_error(ssl, ret)
169 $if trace_ssl ? {
170 eprintln('${@METHOD} ret: ${ret} | ssl: ${ssl:x} | res: ${res}')
171 }
172 match unsafe { SSLError(res) } {
173 .ssl_error_syscall {
174 return error_with_code('net.openssl unrecoverable syscall (${res})', res)
175 }
176 .ssl_error_ssl {
177 return error_with_code('net.openssl unrecoverable ssl protocol error (${res})', res)
178 }
179 else {
180 return unsafe { SSLError(res) }
181 }
182 }
183}
184
185enum SSLError {
186 ssl_error_none = C.SSL_ERROR_NONE
187 ssl_error_ssl = C.SSL_ERROR_SSL
188 ssl_error_want_read = C.SSL_ERROR_WANT_READ
189 ssl_error_want_write = C.SSL_ERROR_WANT_WRITE
190 ssl_error_want_x509_lookup = C.SSL_ERROR_WANT_X509_LOOKUP
191 ssl_error_syscall = C.SSL_ERROR_SYSCALL
192 ssl_error_zero_return = C.SSL_ERROR_ZERO_RETURN
193 ssl_error_want_connect = C.SSL_ERROR_WANT_CONNECT
194 ssl_error_want_accept = C.SSL_ERROR_WANT_ACCEPT
195 ssl_error_want_async = C.SSL_ERROR_WANT_ASYNC
196 ssl_error_want_async_job = C.SSL_ERROR_WANT_ASYNC_JOB
197}
198