Bug 1013: Don't assume errno is between 0 and 100000
[elinks.git] / src / network / ssl / socket.c
blob45b4b4a8887d2b54c12321a107c1b5a5d7382e85
1 /* SSL socket workshop */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #ifdef CONFIG_OPENSSL
8 #include <openssl/ssl.h>
9 #elif defined(CONFIG_GNUTLS)
10 #include <gnutls/gnutls.h>
11 #else
12 #error "Huh?! You have SSL enabled, but not OPENSSL nor GNUTLS!! And then you want exactly *what* from me?"
13 #endif
15 #include <errno.h>
17 #include "elinks.h"
19 #include "config/options.h"
20 #include "main/select.h"
21 #include "network/connection.h"
22 #include "network/socket.h"
23 #include "network/ssl/socket.h"
24 #include "network/ssl/ssl.h"
25 #include "util/memory.h"
28 /* SSL errors */
29 #ifdef CONFIG_OPENSSL
30 #define SSL_ERROR_WANT_READ2 9999 /* XXX */
31 #define SSL_ERROR_WANT_WRITE2 SSL_ERROR_WANT_WRITE
32 #define SSL_ERROR_SYSCALL2 SSL_ERROR_SYSCALL
33 #elif defined(CONFIG_GNUTLS)
34 #define SSL_ERROR_NONE GNUTLS_E_SUCCESS
35 #define SSL_ERROR_WANT_READ GNUTLS_E_AGAIN
36 #define SSL_ERROR_WANT_READ2 GNUTLS_E_INTERRUPTED
37 #define SSL_ERROR_WANT_WRITE GNUTLS_E_AGAIN
38 #define SSL_ERROR_WANT_WRITE2 GNUTLS_E_INTERRUPTED
39 #define SSL_ERROR_SYSCALL GNUTLS_E_PUSH_ERROR
40 #define SSL_ERROR_SYSCALL2 GNUTLS_E_PULL_ERROR
41 #endif
43 #ifdef CONFIG_OPENSSL
45 #define ssl_do_connect(socket) SSL_get_error(socket->ssl, SSL_connect(socket->ssl))
46 #define ssl_do_write(socket, data, len) SSL_write(socket->ssl, data, len)
47 #define ssl_do_read(socket, data, len) SSL_read(socket->ssl, data, len)
48 #define ssl_do_close(socket) /* Hmh? No idea.. */
50 #elif defined(CONFIG_GNUTLS)
52 #define ssl_do_connect(conn) gnutls_handshake(*((ssl_t *) socket->ssl))
53 #define ssl_do_write(socket, data, len) gnutls_record_send(*((ssl_t *) socket->ssl), data, len)
54 #define ssl_do_read(socket, data, len) gnutls_record_recv(*((ssl_t *) socket->ssl), data, len)
55 /* We probably don't handle this entirely correctly.. */
56 #define ssl_do_close(socket) gnutls_bye(*((ssl_t *) socket->ssl), GNUTLS_SHUT_RDWR);
58 #endif
61 /* Refuse to negotiate TLS 1.0 and later protocols on @socket->ssl.
62 * Without this, connecting to <https://www-s.uiuc.edu/> with GnuTLS
63 * 1.3.5 would result in an SSL error. The bug may be in the server
64 * (Netscape-Enterprise/3.6 SP3), in GnuTLS, or in ELinks; please log
65 * your findings to ELinks bug 712. */
66 static void
67 ssl_set_no_tls(struct socket *socket)
69 #ifdef CONFIG_OPENSSL
70 ((ssl_t *) socket->ssl)->options |= SSL_OP_NO_TLSv1;
71 #elif defined(CONFIG_GNUTLS)
73 /* GnuTLS does not support SSLv2 because it is "insecure".
74 * That leaves only SSLv3. */
75 static const int protocol_priority[] = {
76 GNUTLS_SSL3,
80 gnutls_protocol_set_priority(*(ssl_t *) socket->ssl, protocol_priority);
82 #endif
85 static void
86 ssl_want_read(struct socket *socket)
88 if (socket->no_tls)
89 ssl_set_no_tls(socket);
91 switch (ssl_do_connect(socket)) {
92 case SSL_ERROR_NONE:
93 #ifdef CONFIG_GNUTLS
94 if (get_opt_bool("connection.ssl.cert_verify")
95 && gnutls_certificate_verify_peers(*((ssl_t *) socket->ssl))) {
96 socket->ops->retry(socket, connection_state(S_SSL_ERROR));
97 return;
99 #endif
101 /* Report successful SSL connection setup. */
102 complete_connect_socket(socket, NULL, NULL);
103 break;
105 case SSL_ERROR_WANT_READ:
106 case SSL_ERROR_WANT_READ2:
107 break;
109 default:
110 socket->no_tls = !socket->no_tls;
111 socket->ops->retry(socket, connection_state(S_SSL_ERROR));
115 /* Return -1 on error, 0 or success. */
117 ssl_connect(struct socket *socket)
119 int ret;
121 if (init_ssl_connection(socket) == S_SSL_ERROR) {
122 socket->ops->done(socket, connection_state(S_SSL_ERROR));
123 return -1;
126 if (socket->no_tls)
127 ssl_set_no_tls(socket);
129 #ifdef CONFIG_OPENSSL
130 SSL_set_fd(socket->ssl, socket->fd);
132 if (get_opt_bool("connection.ssl.cert_verify"))
133 SSL_set_verify(socket->ssl, SSL_VERIFY_PEER
134 | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
135 NULL);
137 if (get_opt_bool("connection.ssl.client_cert.enable")) {
138 unsigned char *client_cert;
140 client_cert = get_opt_str("connection.ssl.client_cert.file");
141 if (!*client_cert) {
142 client_cert = getenv("X509_CLIENT_CERT");
143 if (client_cert && !*client_cert)
144 client_cert = NULL;
147 if (client_cert) {
148 SSL_CTX *ctx = ((SSL *) socket->ssl)->ctx;
150 SSL_CTX_use_certificate_chain_file(ctx, client_cert);
151 SSL_CTX_use_PrivateKey_file(ctx, client_cert,
152 SSL_FILETYPE_PEM);
156 #elif defined(CONFIG_GNUTLS)
157 /* GnuTLS uses function pointers for network I/O. The default
158 * functions take a file descriptor, but it must be passed in
159 * as a pointer. GnuTLS uses the GNUTLS_INT_TO_POINTER and
160 * GNUTLS_POINTER_TO_INT macros for these conversions, but
161 * those are unfortunately not in any public header. So
162 * ELinks must just cast the pointer the best it can and hope
163 * that the conversions match. */
164 gnutls_transport_set_ptr(*((ssl_t *) socket->ssl),
165 (gnutls_transport_ptr) (longptr_T) socket->fd);
167 /* TODO: Some certificates fuss. --pasky */
168 #endif
170 ret = ssl_do_connect(socket);
172 switch (ret) {
173 case SSL_ERROR_WANT_READ:
174 case SSL_ERROR_WANT_READ2:
175 socket->ops->set_state(socket, connection_state(S_SSL_NEG));
176 set_handlers(socket->fd, (select_handler_T) ssl_want_read,
177 NULL, (select_handler_T) dns_exception, socket);
178 return -1;
180 case SSL_ERROR_NONE:
181 #ifdef CONFIG_GNUTLS
182 if (!get_opt_bool("connection.ssl.cert_verify"))
183 break;
185 if (!gnutls_certificate_verify_peers(*((ssl_t *) socket->ssl)))
186 #endif
187 break;
189 default:
190 if (ret != SSL_ERROR_NONE) {
191 /* DBG("sslerr %s", gnutls_strerror(ret)); */
192 socket->no_tls = !socket->no_tls;
195 connect_socket(socket, connection_state(S_SSL_ERROR));
196 return -1;
199 return 0;
202 /* Return enum socket_error on error, bytes written on success. */
203 ssize_t
204 ssl_write(struct socket *socket, unsigned char *data, int len)
206 ssize_t wr = ssl_do_write(socket, data, len);
208 if (wr <= 0) {
209 #ifdef CONFIG_OPENSSL
210 int err = SSL_get_error(socket->ssl, wr);
211 #elif defined(CONFIG_GNUTLS)
212 int err = wr;
213 #endif
214 if (err == SSL_ERROR_WANT_WRITE ||
215 err == SSL_ERROR_WANT_WRITE2) {
216 return -1;
219 if (!wr) return SOCKET_CANT_WRITE;
221 if (err == SSL_ERROR_SYSCALL)
222 return SOCKET_SYSCALL_ERROR;
224 errno = S_SSL_ERROR;
225 return SOCKET_INTERNAL_ERROR;
228 return wr;
231 /* Return enum socket_error on error, bytes read on success. */
232 ssize_t
233 ssl_read(struct socket *socket, unsigned char *data, int len)
235 ssize_t rd = ssl_do_read(socket, data, len);
237 if (rd <= 0) {
238 #ifdef CONFIG_OPENSSL
239 int err = SSL_get_error(socket->ssl, rd);
240 #elif defined(CONFIG_GNUTLS)
241 int err = rd;
242 #endif
244 #ifdef CONFIG_GNUTLS
245 if (err == GNUTLS_E_REHANDSHAKE)
246 return -1;
247 #endif
249 if (err == SSL_ERROR_WANT_READ ||
250 err == SSL_ERROR_WANT_READ2) {
251 return SOCKET_SSL_WANT_READ;
254 if (!rd) return SOCKET_CANT_READ;
256 if (err == SSL_ERROR_SYSCALL2)
257 return SOCKET_SYSCALL_ERROR;
259 errno = S_SSL_ERROR;
260 return SOCKET_INTERNAL_ERROR;
263 return rd;
267 ssl_close(struct socket *socket)
269 ssl_do_close(socket);
270 done_ssl_connection(socket);
272 return 0;