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