GNU libmicrohttpd  0.9.73
connection_https.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2007, 2008, 2010 Daniel Pittman and Christian Grothoff
4  Copyright (C) 2015-2021 Karlson2k (Evgeny Grin)
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 
20 */
21 
31 #include "internal.h"
32 #include "connection.h"
33 #include "connection_https.h"
34 #include "memorypool.h"
35 #include "response.h"
36 #include "mhd_mono_clock.h"
37 #include <gnutls/gnutls.h>
38 #include "mhd_send.h"
39 
40 
50 static ssize_t
51 recv_tls_adapter (struct MHD_Connection *connection,
52  void *other,
53  size_t i)
54 {
55  ssize_t res;
56 
57  if (i > SSIZE_MAX)
58  i = SSIZE_MAX;
59 
60  res = gnutls_record_recv (connection->tls_session,
61  other,
62  i);
63  if ( (GNUTLS_E_AGAIN == res) ||
64  (GNUTLS_E_INTERRUPTED == res) )
65  {
66 #ifdef EPOLL_SUPPORT
67  if (GNUTLS_E_AGAIN == res)
68  connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
69 #endif
70  /* Any network errors means that buffer is empty. */
71  connection->tls_read_ready = false;
72  return MHD_ERR_AGAIN_;
73  }
74  if (res < 0)
75  {
76  connection->tls_read_ready = false;
77  if ( (GNUTLS_E_DECRYPTION_FAILED == res) ||
78  (GNUTLS_E_INVALID_SESSION == res) ||
79  (GNUTLS_E_DECOMPRESSION_FAILED == res) ||
80  (GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER == res) ||
81  (GNUTLS_E_UNSUPPORTED_VERSION_PACKET == res) ||
82  (GNUTLS_E_UNEXPECTED_PACKET_LENGTH == res) ||
83  (GNUTLS_E_UNEXPECTED_PACKET == res) ||
84  (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET == res) ||
85  (GNUTLS_E_EXPIRED == res) ||
86  (GNUTLS_E_REHANDSHAKE == res) )
87  return MHD_ERR_TLS_;
88  if ( (GNUTLS_E_PULL_ERROR == res) ||
89  (GNUTLS_E_INTERNAL_ERROR == res) ||
90  (GNUTLS_E_CRYPTODEV_IOCTL_ERROR == res) ||
91  (GNUTLS_E_CRYPTODEV_DEVICE_ERROR == res) )
92  return MHD_ERR_PIPE_;
93  if (GNUTLS_E_PREMATURE_TERMINATION == res)
94  return MHD_ERR_CONNRESET_;
95  if (GNUTLS_E_MEMORY_ERROR == res)
96  return MHD_ERR_NOMEM_;
97  /* Treat any other error as a hard error. */
98  return MHD_ERR_NOTCONN_;
99  }
100 
101 #ifdef EPOLL_SUPPORT
102  /* Unlike non-TLS connections, do not reset "read-ready" if
103  * received amount smaller than provided amount, as TLS
104  * connections may receive data by fixed-size chunks. */
105 #endif /* EPOLL_SUPPORT */
106 
107  /* Check whether TLS buffers still have some unread data. */
108  connection->tls_read_ready = ( ((size_t) res == i) &&
109  (0 != gnutls_record_check_pending (
110  connection->tls_session)) );
111  return res;
112 }
113 
114 
124 bool
126 {
127  int ret;
128 
129  if ((MHD_TLS_CONN_INIT == connection->tls_state) ||
130  (MHD_TLS_CONN_HANDSHAKING == connection->tls_state))
131  {
132 #if 0
133  /* According to real-live testing, Nagel's Algorithm is not blocking
134  * partial packets on just connected sockets on modern OSes. As TLS setup
135  * is performed as the fist action upon socket connection, the next
136  * optimisation typically is not required. If any specific OS will
137  * require this optimization, it could be enabled by allowing the next
138  * lines for this specific OS. */
139  if (_MHD_ON != connection->sk_nodelay)
140  MHD_connection_set_nodelay_state_ (connection, true);
141 #endif
142  ret = gnutls_handshake (connection->tls_session);
143  if (ret == GNUTLS_E_SUCCESS)
144  {
145  /* set connection TLS state to enable HTTP processing */
146  connection->tls_state = MHD_TLS_CONN_CONNECTED;
147  MHD_update_last_activity_ (connection);
148  return true;
149  }
150  if ( (GNUTLS_E_AGAIN == ret) ||
151  (GNUTLS_E_INTERRUPTED == ret) )
152  {
153  connection->tls_state = MHD_TLS_CONN_HANDSHAKING;
154  /* handshake not done */
155  return false;
156  }
157  /* handshake failed */
158  connection->tls_state = MHD_TLS_CONN_TLS_FAILED;
159 #ifdef HAVE_MESSAGES
160  MHD_DLOG (connection->daemon,
161  _ ("Error: received handshake message out of context.\n"));
162 #endif
163  MHD_connection_close_ (connection,
165  return false;
166  }
167  return true;
168 }
169 
170 
177 void
179 {
180  connection->recv_cls = &recv_tls_adapter;
181 }
182 
183 
190 bool
192 {
193  if (MHD_TLS_CONN_WR_CLOSED > connection->tls_state)
194  {
195  const int res =
196  gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR);
197  if (GNUTLS_E_SUCCESS == res)
198  {
199  connection->tls_state = MHD_TLS_CONN_WR_CLOSED;
200  return true;
201  }
202  if ((GNUTLS_E_AGAIN == res) ||
203  (GNUTLS_E_INTERRUPTED == res))
204  {
205  connection->tls_state = MHD_TLS_CONN_WR_CLOSING;
206  return true;
207  }
208  else
209  connection->tls_state = MHD_TLS_CONN_TLS_FAILED;
210  }
211  return false;
212 }
213 
214 
215 /* end of connection_https.c */
MHD_Connection::recv_cls
ReceiveCallback recv_cls
Definition: internal.h:706
_
#define _(String)
Definition: mhd_options.h:42
MHD_TLS_CONN_WR_CLOSING
@ MHD_TLS_CONN_WR_CLOSING
Definition: internal.h:664
MHD_ERR_PIPE_
#define MHD_ERR_PIPE_
Definition: connection.h:72
_MHD_ON
@ _MHD_ON
Definition: internal.h:178
MHD_Connection::tls_read_ready
bool tls_read_ready
Definition: internal.h:769
MHD_ERR_AGAIN_
#define MHD_ERR_AGAIN_
Definition: internal.h:1863
memorypool.h
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...
MHD_run_tls_handshake_
bool MHD_run_tls_handshake_(struct MHD_Connection *connection)
Definition: connection_https.c:125
connection_https.h
Methods for managing connections.
MHD_Connection::sk_nodelay
enum MHD_tristate sk_nodelay
Definition: internal.h:1025
response.h
Methods for managing response objects.
MHD_connection_set_nodelay_state_
bool MHD_connection_set_nodelay_state_(struct MHD_Connection *connection, bool nodelay_state)
Definition: mhd_send.c:170
MHD_ERR_TLS_
#define MHD_ERR_TLS_
Definition: connection.h:77
recv_tls_adapter
static ssize_t recv_tls_adapter(struct MHD_Connection *connection, void *other, size_t i)
Definition: connection_https.c:51
internal.h
internal shared structures
MHD_connection_close_
void MHD_connection_close_(struct MHD_Connection *connection, enum MHD_RequestTerminationCode rtc)
Definition: connection_close.c:83
MHD_TLS_CONN_CONNECTED
@ MHD_TLS_CONN_CONNECTED
Definition: internal.h:663
MHD_TLS_CONN_TLS_FAILED
@ MHD_TLS_CONN_TLS_FAILED
Definition: internal.h:668
mhd_mono_clock.h
internal monotonic clock functions implementations
MHD_TLS_CONN_WR_CLOSED
@ MHD_TLS_CONN_WR_CLOSED
Definition: internal.h:665
MHD_ERR_CONNRESET_
#define MHD_ERR_CONNRESET_
Definition: internal.h:1868
MHD_ERR_NOMEM_
#define MHD_ERR_NOMEM_
Definition: internal.h:1879
MHD_TLS_CONN_HANDSHAKING
@ MHD_TLS_CONN_HANDSHAKING
Definition: internal.h:662
SSIZE_MAX
#define SSIZE_MAX
Definition: mhd_limits.h:111
MHD_update_last_activity_
void MHD_update_last_activity_(struct MHD_Connection *connection)
Definition: connection_options.c:88
connection.h
Methods for managing connections.
MHD_EPOLL_STATE_READ_READY
@ MHD_EPOLL_STATE_READ_READY
Definition: internal.h:600
MHD_Connection::daemon
struct MHD_Daemon * daemon
Definition: internal.h:675
MHD_REQUEST_TERMINATED_WITH_ERROR
@ MHD_REQUEST_TERMINATED_WITH_ERROR
Definition: microhttpd.h:1865
MHD_Connection
Definition: internal.h:634
MHD_ERR_NOTCONN_
#define MHD_ERR_NOTCONN_
Definition: internal.h:1874
mhd_send.h
Declarations of send() wrappers.
MHD_tls_connection_shutdown
bool MHD_tls_connection_shutdown(struct MHD_Connection *connection)
Definition: connection_https.c:191
MHD_TLS_CONN_INIT
@ MHD_TLS_CONN_INIT
Definition: internal.h:661
MHD_set_https_callbacks
void MHD_set_https_callbacks(struct MHD_Connection *connection)
Definition: connection_https.c:178