1 /*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2008, 2010 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19 */
20
21 /**
22 * @file connection_https.c
23 * @brief Methods for managing SSL/TLS connections. This file is only
24 * compiled if ENABLE_HTTPS is set.
25 * @author Sagie Amir
26 * @author Christian Grothoff
27 */
28
29 #include "internal.h"
30 #include "connection.h"
31 #include "memorypool.h"
32 #include "response.h"
33 #include "reason_phrase.h"
34 #include <openssl/ssl.h>
35
36
37 /**
38 * Give gnuTLS chance to work on the TLS handshake.
39 *
40 * @param connection connection to handshake on
41 * @return #MHD_YES on error or if the handshake is progressing
42 * #MHD_NO if the handshake has completed successfully
43 * and we should start to read/write data
44 */
45 static int
run_tls_handshake(struct MHD_Connection * connection)46 run_tls_handshake (struct MHD_Connection *connection)
47 {
48 int ret;
49 connection->last_activity = MHD_monotonic_time();
50 if (connection->state == MHD_TLS_CONNECTION_INIT)
51 {
52 ret = SSL_accept (connection->tls_session);
53 if (ret == 1)
54 {
55 /* set connection state to enable HTTP processing */
56 connection->state = MHD_CONNECTION_INIT;
57 return MHD_YES;
58 }
59 int error = SSL_get_error (connection->tls_session, ret);
60 if ( (error == SSL_ERROR_WANT_READ) ||
61 (error == SSL_ERROR_WANT_WRITE) )
62 {
63 /* handshake not done */
64 return MHD_YES;
65 }
66 /* handshake failed */
67 #if HAVE_MESSAGES
68 MHD_DLOG (connection->daemon,
69 "Error: received handshake message out of context\n");
70 #endif
71 MHD_connection_close (connection,
72 MHD_REQUEST_TERMINATED_WITH_ERROR);
73 return MHD_YES;
74 }
75 return MHD_NO;
76 }
77
78
79 /**
80 * This function handles a particular SSL/TLS connection when
81 * it has been determined that there is data to be read off a
82 * socket. Message processing is done by message type which is
83 * determined by peeking into the first message type byte of the
84 * stream.
85 *
86 * Error message handling: all fatal level messages cause the
87 * connection to be terminated.
88 *
89 * Application data is forwarded to the underlying daemon for
90 * processing.
91 *
92 * @param connection the source connection
93 * @return always #MHD_YES (we should continue to process the connection)
94 */
95 static int
MHD_tls_connection_handle_read(struct MHD_Connection * connection)96 MHD_tls_connection_handle_read (struct MHD_Connection *connection)
97 {
98 if (MHD_YES == run_tls_handshake (connection))
99 return MHD_YES;
100 return MHD_connection_handle_read (connection);
101 }
102
103
104 /**
105 * This function was created to handle writes to sockets when it has
106 * been determined that the socket can be written to. This function
107 * will forward all write requests to the underlying daemon unless
108 * the connection has been marked for closing.
109 *
110 * @return always #MHD_YES (we should continue to process the connection)
111 */
112 static int
MHD_tls_connection_handle_write(struct MHD_Connection * connection)113 MHD_tls_connection_handle_write (struct MHD_Connection *connection)
114 {
115 if (MHD_YES == run_tls_handshake (connection))
116 return MHD_YES;
117 return MHD_connection_handle_write (connection);
118 }
119
120
121 /**
122 * This function was created to handle per-connection processing that
123 * has to happen even if the socket cannot be read or written to. All
124 * implementations (multithreaded, external select, internal select)
125 * call this function.
126 *
127 * @param connection being handled
128 * @return #MHD_YES if we should continue to process the
129 * connection (not dead yet), #MHD_NO if it died
130 */
131 static int
MHD_tls_connection_handle_idle(struct MHD_Connection * connection)132 MHD_tls_connection_handle_idle (struct MHD_Connection *connection)
133 {
134 unsigned int timeout;
135
136 #if DEBUG_STATES
137 MHD_DLOG (connection->daemon,
138 "%s: state: %s\n",
139 __FUNCTION__,
140 MHD_state_to_string (connection->state));
141 #endif
142 timeout = connection->connection_timeout;
143 if ( (timeout != 0) && (timeout <= (MHD_monotonic_time() - connection->last_activity)))
144 MHD_connection_close (connection,
145 MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
146 switch (connection->state)
147 {
148 /* on newly created connections we might reach here before any reply has been received */
149 case MHD_TLS_CONNECTION_INIT:
150 break;
151 /* close connection if necessary */
152 case MHD_CONNECTION_CLOSED:
153 SSL_shutdown (connection->tls_session);
154 return MHD_connection_handle_idle (connection);
155 default:
156 if ( (0 != SSL_pending (connection->tls_session)) &&
157 (MHD_YES != MHD_tls_connection_handle_read (connection)) )
158 return MHD_YES;
159 return MHD_connection_handle_idle (connection);
160 }
161 #if EPOLL_SUPPORT
162 return MHD_connection_epoll_update_ (connection);
163 #else
164 return MHD_YES;
165 #endif
166 }
167
168
169 /**
170 * Set connection callback function to be used through out
171 * the processing of this secure connection.
172 *
173 * @param connection which callbacks should be modified
174 */
175 void
MHD_set_https_callbacks(struct MHD_Connection * connection)176 MHD_set_https_callbacks (struct MHD_Connection *connection)
177 {
178 connection->read_handler = &MHD_tls_connection_handle_read;
179 connection->write_handler = &MHD_tls_connection_handle_write;
180 connection->idle_handler = &MHD_tls_connection_handle_idle;
181 }
182
183 /* end of connection_https.c */
184