1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23/*
24 * Source file for all PolarSSL-specific code for the TLS/SSL layer. No code
25 * but sslgen.c should ever call or use these functions.
26 *
27 */
28
29#include "setup.h"
30#ifdef USE_POLARSSL
31
32#include <string.h>
33#include <stdlib.h>
34#include <ctype.h>
35#ifdef HAVE_SYS_SOCKET_H
36#include <sys/socket.h>
37#endif
38
39#include <polarssl/net.h>
40#include <polarssl/ssl.h>
41#include <polarssl/havege.h>
42#include <polarssl/certs.h>
43#include <polarssl/x509.h>
44
45#include "urldata.h"
46#include "sendf.h"
47#include "inet_pton.h"
48#include "polarssl.h"
49#include "sslgen.h"
50#include "parsedate.h"
51#include "connect.h" /* for the connect timeout */
52#include "select.h"
53#include "rawstr.h"
54
55#define _MPRINTF_REPLACE /* use our functions only */
56#include <curl/mprintf.h>
57#include "curl_memory.h"
58/* The last #include file should be: */
59#include "memdebug.h"
60
61/* Define this to enable lots of debugging for PolarSSL */
62#undef POLARSSL_DEBUG
63
64#ifdef POLARSSL_DEBUG
65static void polarssl_debug(void *context, int level, char *line)
66{
67  struct SessionHandle *data = NULL;
68
69  if(!context)
70    return;
71
72  data = (struct SessionHandle *)context;
73
74  infof(data, "%s", line);
75}
76#else
77#endif
78
79static Curl_recv polarssl_recv;
80static Curl_send polarssl_send;
81
82/*
83 * This function loads all the client/CA certificates and CRLs. Setup the TLS
84 * layer and do all necessary magic.
85 */
86CURLcode
87Curl_polarssl_connect(struct connectdata *conn,
88                      int sockindex)
89{
90  struct SessionHandle *data = conn->data;
91  bool sni = TRUE; /* default is SNI enabled */
92  int ret = -1;
93#ifdef ENABLE_IPV6
94  struct in6_addr addr;
95#else
96  struct in_addr addr;
97#endif
98  void *old_session = NULL;
99  size_t old_session_size = 0;
100  char buffer[1024];
101
102  if(conn->ssl[sockindex].state == ssl_connection_complete)
103    return CURLE_OK;
104
105  /* PolarSSL only supports SSLv3 and TLSv1 */
106  if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
107    failf(data, "PolarSSL does not support SSLv2");
108    return CURLE_SSL_CONNECT_ERROR;
109  }
110  else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
111    sni = FALSE; /* SSLv3 has no SNI */
112
113  havege_init(&conn->ssl[sockindex].hs);
114
115  /* Load the trusted CA */
116  memset(&conn->ssl[sockindex].cacert, 0, sizeof(x509_cert));
117
118  if(data->set.str[STRING_SSL_CAFILE]) {
119    ret = x509parse_crtfile(&conn->ssl[sockindex].cacert,
120                            data->set.str[STRING_SSL_CAFILE]);
121
122    if(ret) {
123      failf(data, "Error reading ca cert file %s: -0x%04X",
124            data->set.str[STRING_SSL_CAFILE], -ret);
125
126      if(data->set.ssl.verifypeer)
127        return CURLE_SSL_CACERT_BADFILE;
128    }
129  }
130
131  /* Load the client certificate */
132  memset(&conn->ssl[sockindex].clicert, 0, sizeof(x509_cert));
133
134  if(data->set.str[STRING_CERT]) {
135    ret = x509parse_crtfile(&conn->ssl[sockindex].clicert,
136                            data->set.str[STRING_CERT]);
137
138    if(ret) {
139      failf(data, "Error reading client cert file %s: -0x%04X",
140            data->set.str[STRING_CERT], -ret);
141      return CURLE_SSL_CERTPROBLEM;
142    }
143  }
144
145  /* Load the client private key */
146  if(data->set.str[STRING_KEY]) {
147    ret = x509parse_keyfile(&conn->ssl[sockindex].rsa,
148                            data->set.str[STRING_KEY],
149                            data->set.str[STRING_KEY_PASSWD]);
150
151    if(ret) {
152      failf(data, "Error reading private key %s: -0x%04X",
153            data->set.str[STRING_KEY], -ret);
154      return CURLE_SSL_CERTPROBLEM;
155    }
156  }
157
158  /* Load the CRL */
159  memset(&conn->ssl[sockindex].crl, 0, sizeof(x509_crl));
160
161  if(data->set.str[STRING_SSL_CRLFILE]) {
162    ret = x509parse_crlfile(&conn->ssl[sockindex].crl,
163                            data->set.str[STRING_SSL_CRLFILE]);
164
165    if(ret) {
166      failf(data, "Error reading CRL file %s: -0x%04X",
167            data->set.str[STRING_SSL_CRLFILE], -ret);
168      return CURLE_SSL_CRL_BADFILE;
169    }
170  }
171
172  infof(data, "PolarSSL: Connected to %s:%d\n",
173        conn->host.name, conn->remote_port);
174
175  havege_init(&conn->ssl[sockindex].hs);
176
177  if(ssl_init(&conn->ssl[sockindex].ssl)) {
178    failf(data, "PolarSSL: ssl_init failed");
179    return CURLE_SSL_CONNECT_ERROR;
180  }
181
182  ssl_set_endpoint(&conn->ssl[sockindex].ssl, SSL_IS_CLIENT);
183  ssl_set_authmode(&conn->ssl[sockindex].ssl, SSL_VERIFY_OPTIONAL);
184
185  ssl_set_rng(&conn->ssl[sockindex].ssl, havege_rand,
186              &conn->ssl[sockindex].hs);
187  ssl_set_bio(&conn->ssl[sockindex].ssl,
188              net_recv, &conn->sock[sockindex],
189              net_send, &conn->sock[sockindex]);
190
191  ssl_set_ciphers(&conn->ssl[sockindex].ssl, ssl_default_ciphers);
192
193  if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) {
194    memcpy(&conn->ssl[sockindex].ssn, old_session, old_session_size);
195    infof(data, "PolarSSL re-using session\n");
196  }
197
198  ssl_set_session(&conn->ssl[sockindex].ssl, 1, 600,
199                  &conn->ssl[sockindex].ssn);
200
201  ssl_set_ca_chain(&conn->ssl[sockindex].ssl,
202                   &conn->ssl[sockindex].cacert,
203                   &conn->ssl[sockindex].crl,
204                   conn->host.name);
205
206  ssl_set_own_cert(&conn->ssl[sockindex].ssl,
207                   &conn->ssl[sockindex].clicert, &conn->ssl[sockindex].rsa);
208
209  if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) &&
210#ifdef ENABLE_IPV6
211     !Curl_inet_pton(AF_INET6, conn->host.name, &addr) &&
212#endif
213     sni && ssl_set_hostname(&conn->ssl[sockindex].ssl, conn->host.name)) {
214     infof(data, "WARNING: failed to configure "
215                 "server name indication (SNI) TLS extension\n");
216  }
217
218  infof(data, "PolarSSL: performing SSL/TLS handshake...\n");
219
220#ifdef POLARSSL_DEBUG
221  ssl_set_dbg(&conn->ssl[sockindex].ssl, polarssl_debug, data);
222#endif
223
224  for(;;) {
225    if(!(ret = ssl_handshake(&conn->ssl[sockindex].ssl)))
226      break;
227    else if(ret != POLARSSL_ERR_NET_TRY_AGAIN) {
228      failf(data, "ssl_handshake returned -0x%04X", -ret);
229      return CURLE_SSL_CONNECT_ERROR;
230    }
231    else {
232      /* wait for data from server... */
233      long timeout_ms = Curl_timeleft(data, NULL, TRUE);
234
235      if(timeout_ms < 0) {
236        failf(data, "SSL connection timeout");
237        return CURLE_OPERATION_TIMEDOUT;
238      }
239
240      switch(Curl_socket_ready(conn->sock[sockindex],
241                               CURL_SOCKET_BAD, timeout_ms)) {
242      case 0:
243        failf(data, "SSL handshake timeout");
244        return CURLE_OPERATION_TIMEDOUT;
245        break;
246      case CURL_CSELECT_IN:
247        continue;
248        break;
249      default:
250        return CURLE_SSL_CONNECT_ERROR;
251        break;
252      }
253    }
254  }
255
256  infof(data, "PolarSSL: Handshake complete, cipher is %s\n",
257        ssl_get_cipher(&conn->ssl[sockindex].ssl));
258
259  ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl);
260
261  if(ret && data->set.ssl.verifypeer) {
262    if(ret & BADCERT_EXPIRED)
263      failf(data, "Cert verify failed: BADCERT_EXPIRED\n");
264
265    if(ret & BADCERT_REVOKED)
266      failf(data, "Cert verify failed: BADCERT_REVOKED");
267
268    if(ret & BADCERT_CN_MISMATCH)
269      failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
270
271    if(ret & BADCERT_NOT_TRUSTED)
272      failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
273
274    return CURLE_SSL_CACERT;
275  }
276
277  if(conn->ssl[sockindex].ssl.peer_cert) {
278    /* If the session was resumed, there will be no peer certs */
279    memset(buffer, 0, sizeof(buffer));
280
281    if(x509parse_cert_info(buffer, sizeof(buffer), (char *)"* ",
282                           conn->ssl[sockindex].ssl.peer_cert) != -1)
283      infof(data, "Dumping cert info:\n%s\n", buffer);
284  }
285
286  conn->ssl[sockindex].state = ssl_connection_complete;
287  conn->recv[sockindex] = polarssl_recv;
288  conn->send[sockindex] = polarssl_send;
289
290  /* Save the current session data for possible re-use */
291  {
292    void *new_session = malloc(sizeof(conn->ssl[sockindex].ssn));
293
294    if(new_session) {
295      memcpy(new_session, &conn->ssl[sockindex].ssn,
296             sizeof(conn->ssl[sockindex].ssn));
297
298      if(old_session)
299        Curl_ssl_delsessionid(conn, old_session);
300
301      return Curl_ssl_addsessionid(conn, new_session,
302                                   sizeof(conn->ssl[sockindex].ssn));
303    }
304  }
305
306  return CURLE_OK;
307}
308
309static ssize_t polarssl_send(struct connectdata *conn,
310                             int sockindex,
311                             const void *mem,
312                             size_t len,
313                             CURLcode *curlcode)
314{
315  int ret = -1;
316
317  ret = ssl_write(&conn->ssl[sockindex].ssl,
318                  (unsigned char *)mem, len);
319
320  if(ret < 0) {
321    *curlcode = (ret == POLARSSL_ERR_NET_TRY_AGAIN) ?
322      CURLE_AGAIN : CURLE_SEND_ERROR;
323    ret = -1;
324  }
325
326  return ret;
327}
328
329void Curl_polarssl_close_all(struct SessionHandle *data)
330{
331  (void)data;
332}
333
334void Curl_polarssl_close(struct connectdata *conn, int sockindex)
335{
336  rsa_free(&conn->ssl[sockindex].rsa);
337  x509_free(&conn->ssl[sockindex].clicert);
338  x509_free(&conn->ssl[sockindex].cacert);
339  x509_crl_free(&conn->ssl[sockindex].crl);
340  ssl_free(&conn->ssl[sockindex].ssl);
341}
342
343static ssize_t polarssl_recv(struct connectdata *conn,
344                             int num,
345                             char *buf,
346                             size_t buffersize,
347                             CURLcode *curlcode)
348{
349  int ret = -1;
350  ssize_t len = -1;
351
352  memset(buf, 0, buffersize);
353  ret = ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, buffersize);
354
355  if(ret <= 0) {
356    if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
357      return 0;
358
359    *curlcode = (ret == POLARSSL_ERR_NET_TRY_AGAIN) ?
360      CURLE_AGAIN : CURLE_RECV_ERROR;
361    return -1;
362  }
363
364  len = ret;
365
366  return len;
367}
368
369void Curl_polarssl_session_free(void *ptr)
370{
371  free(ptr);
372}
373
374size_t Curl_polarssl_version(char *buffer, size_t size)
375{
376  return snprintf(buffer, size, "PolarSSL");
377}
378
379#endif
380