GNU libmicrohttpd  1.0.1
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-2022 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 &=
70 #endif
71  /* Any network errors means that buffer is empty. */
72  connection->tls_read_ready = false;
73  return MHD_ERR_AGAIN_;
74  }
75  if (res < 0)
76  {
77  connection->tls_read_ready = false;
78  if ( (GNUTLS_E_DECRYPTION_FAILED == res) ||
79  (GNUTLS_E_INVALID_SESSION == res) ||
80  (GNUTLS_E_DECOMPRESSION_FAILED == res) ||
81  (GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER == res) ||
82  (GNUTLS_E_UNSUPPORTED_VERSION_PACKET == res) ||
83  (GNUTLS_E_UNEXPECTED_PACKET_LENGTH == res) ||
84  (GNUTLS_E_UNEXPECTED_PACKET == res) ||
85  (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET == res) ||
86  (GNUTLS_E_EXPIRED == res) ||
87  (GNUTLS_E_REHANDSHAKE == res) )
88  return MHD_ERR_TLS_;
89  if ( (GNUTLS_E_PULL_ERROR == res) ||
90  (GNUTLS_E_INTERNAL_ERROR == res) ||
91  (GNUTLS_E_CRYPTODEV_IOCTL_ERROR == res) ||
92  (GNUTLS_E_CRYPTODEV_DEVICE_ERROR == res) )
93  return MHD_ERR_PIPE_;
94 #if defined(GNUTLS_E_PREMATURE_TERMINATION)
95  if (GNUTLS_E_PREMATURE_TERMINATION == res)
96  return MHD_ERR_CONNRESET_;
97 #elif defined(GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
98  if (GNUTLS_E_UNEXPECTED_PACKET_LENGTH == res)
99  return MHD_ERR_CONNRESET_;
100 #endif /* GNUTLS_E_UNEXPECTED_PACKET_LENGTH */
101  if (GNUTLS_E_MEMORY_ERROR == res)
102  return MHD_ERR_NOMEM_;
103  /* Treat any other error as a hard error. */
104  return MHD_ERR_NOTCONN_;
105  }
106 
107 #ifdef EPOLL_SUPPORT
108  /* Unlike non-TLS connections, do not reset "read-ready" if
109  * received amount smaller than provided amount, as TLS
110  * connections may receive data by fixed-size chunks. */
111 #endif /* EPOLL_SUPPORT */
112 
113  /* Check whether TLS buffers still have some unread data. */
114  connection->tls_read_ready =
115  ( ((size_t) res == i) &&
116  (0 != gnutls_record_check_pending (connection->tls_session)) );
117  return res;
118 }
119 
120 
130 bool
132 {
133  int ret;
134 
135  if ((MHD_TLS_CONN_INIT == connection->tls_state) ||
136  (MHD_TLS_CONN_HANDSHAKING == connection->tls_state))
137  {
138 #if 0
139  /* According to real-live testing, Nagel's Algorithm is not blocking
140  * partial packets on just connected sockets on modern OSes. As TLS setup
141  * is performed as the fist action upon socket connection, the next
142  * optimisation typically is not required. If any specific OS will
143  * require this optimization, it could be enabled by allowing the next
144  * lines for this specific OS. */
145  if (_MHD_ON != connection->sk_nodelay)
146  MHD_connection_set_nodelay_state_ (connection, true);
147 #endif
148  ret = gnutls_handshake (connection->tls_session);
149  if (ret == GNUTLS_E_SUCCESS)
150  {
151  /* set connection TLS state to enable HTTP processing */
152  connection->tls_state = MHD_TLS_CONN_CONNECTED;
153  MHD_update_last_activity_ (connection);
154  return true;
155  }
156  if ( (GNUTLS_E_AGAIN == ret) ||
157  (GNUTLS_E_INTERRUPTED == ret) )
158  {
159  connection->tls_state = MHD_TLS_CONN_HANDSHAKING;
160  /* handshake not done */
161  return false;
162  }
163  /* handshake failed */
164  connection->tls_state = MHD_TLS_CONN_TLS_FAILED;
165 #ifdef HAVE_MESSAGES
166  MHD_DLOG (connection->daemon,
167  _ ("Error: received handshake message out of context.\n"));
168 #endif
169  MHD_connection_close_ (connection,
171  return false;
172  }
173  return true;
174 }
175 
176 
183 void
185 {
186  connection->recv_cls = &recv_tls_adapter;
187 }
188 
189 
196 bool
198 {
199  if (MHD_TLS_CONN_WR_CLOSED > connection->tls_state)
200  {
201  const int res =
202  gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR);
203  if (GNUTLS_E_SUCCESS == res)
204  {
205  connection->tls_state = MHD_TLS_CONN_WR_CLOSED;
206  return true;
207  }
208  if ((GNUTLS_E_AGAIN == res) ||
209  (GNUTLS_E_INTERRUPTED == res))
210  {
211  connection->tls_state = MHD_TLS_CONN_WR_CLOSING;
212  return true;
213  }
214  else
215  connection->tls_state = MHD_TLS_CONN_TLS_FAILED;
216  }
217  return false;
218 }
219 
220 
221 /* end of connection_https.c */
#define SSIZE_MAX
Definition: mhd_limits.h:121
void MHD_update_last_activity_(struct MHD_Connection *connection)
Methods for managing connections.
static ssize_t recv_tls_adapter(struct MHD_Connection *connection, void *other, size_t i)
internal monotonic clock functions implementations
#define MHD_ERR_TLS_
Definition: connection.h:78
#define MHD_ERR_AGAIN_
Definition: internal.h:1863
#define MHD_ERR_CONNRESET_
Definition: internal.h:1868
Methods for managing response objects.
struct MHD_Daemon * daemon
Definition: internal.h:675
#define MHD_ERR_NOMEM_
Definition: internal.h:1879
bool MHD_connection_set_nodelay_state_(struct MHD_Connection *connection, bool nodelay_state)
Definition: mhd_send.c:174
MHD internal shared structures.
void MHD_set_https_callbacks(struct MHD_Connection *connection)
void MHD_connection_close_(struct MHD_Connection *connection, enum MHD_RequestTerminationCode rtc)
Methods for managing connections.
#define MHD_ERR_PIPE_
Definition: connection.h:73
Declarations of send() wrappers.
MHD_EpollState
Definition: internal.h:587
ReceiveCallback recv_cls
Definition: internal.h:706
bool tls_read_ready
Definition: internal.h:769
bool MHD_run_tls_handshake_(struct MHD_Connection *connection)
#define MHD_ERR_NOTCONN_
Definition: internal.h:1874
enum MHD_tristate sk_nodelay
Definition: internal.h:1509
#define _(String)
Definition: mhd_options.h:42
bool MHD_tls_connection_shutdown(struct MHD_Connection *connection)