1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. 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#include "curl_setup.h" 24 25#ifdef USE_QSOSSL 26 27#include <qsossl.h> 28 29#ifdef HAVE_LIMITS_H 30# include <limits.h> 31#endif 32 33#include <curl/curl.h> 34#include "urldata.h" 35#include "sendf.h" 36#include "qssl.h" 37#include "sslgen.h" 38#include "connect.h" /* for the connect timeout */ 39#include "select.h" 40#include "curl_memory.h" 41/* The last #include file should be: */ 42#include "memdebug.h" 43 44 45int Curl_qsossl_init(void) 46 47{ 48 /* Nothing to do here. We must have connection data to initialize ssl, so 49 * defer. 50 */ 51 52 return 1; 53} 54 55 56void Curl_qsossl_cleanup(void) 57 58{ 59 /* Nothing to do. */ 60} 61 62 63static CURLcode Curl_qsossl_init_session(struct SessionHandle * data) 64 65{ 66 int rc; 67 char * certname; 68 SSLInit initstr; 69 SSLInitApp initappstr; 70 71 /* Initialize the job for SSL according to the current parameters. 72 * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an 73 * application identifier to select certificates in the main certificate 74 * store, and SSL_Init() that uses named keyring files and a password. 75 * It is not possible to have different keyrings for the CAs and the 76 * local certificate. We thus use the certificate name to identify the 77 * keyring if given, else the CA file name. 78 * If the key file name is given, it is taken as the password for the 79 * keyring in certificate file. 80 * We first try to SSL_Init_Application(), then SSL_Init() if it failed. 81 */ 82 83 certname = data->set.str[STRING_CERT]; 84 85 if(!certname) { 86 certname = data->set.str[STRING_SSL_CAFILE]; 87 88 if(!certname) 89 return CURLE_OK; /* Use previous setup. */ 90 } 91 92 memset((char *) &initappstr, 0, sizeof initappstr); 93 initappstr.applicationID = certname; 94 initappstr.applicationIDLen = strlen(certname); 95 initappstr.protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */ 96 initappstr.sessionType = SSL_REGISTERED_AS_CLIENT; 97 rc = SSL_Init_Application(&initappstr); 98 99 if(rc == SSL_ERROR_NOT_REGISTERED) { 100 initstr.keyringFileName = certname; 101 initstr.keyringPassword = data->set.str[STRING_KEY]; 102 initstr.cipherSuiteList = NULL; /* Use default. */ 103 initstr.cipherSuiteListLen = 0; 104 rc = SSL_Init(&initstr); 105 } 106 107 switch (rc) { 108 109 case 0: /* No error. */ 110 break; 111 112 case SSL_ERROR_IO: 113 failf(data, "SSL_Init() I/O error: %s", strerror(errno)); 114 return CURLE_SSL_CONNECT_ERROR; 115 116 case SSL_ERROR_BAD_CIPHER_SUITE: 117 return CURLE_SSL_CIPHER; 118 119 case SSL_ERROR_KEYPASSWORD_EXPIRED: 120 case SSL_ERROR_NOT_REGISTERED: 121 return CURLE_SSL_CONNECT_ERROR; 122 123 case SSL_ERROR_NO_KEYRING: 124 return CURLE_SSL_CACERT; 125 126 case SSL_ERROR_CERT_EXPIRED: 127 return CURLE_SSL_CERTPROBLEM; 128 129 default: 130 failf(data, "SSL_Init(): %s", SSL_Strerror(rc, NULL)); 131 return CURLE_SSL_CONNECT_ERROR; 132 } 133 134 return CURLE_OK; 135} 136 137 138static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex) 139 140{ 141 SSLHandle * h; 142 struct ssl_connect_data * connssl = &conn->ssl[sockindex]; 143 144 h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT); 145 146 if(!h) { 147 failf(conn->data, "SSL_Create() I/O error: %s", strerror(errno)); 148 return CURLE_SSL_CONNECT_ERROR; 149 } 150 151 connssl->handle = h; 152 return CURLE_OK; 153} 154 155 156static int Curl_qsossl_trap_cert(SSLHandle * h) 157 158{ 159 return 1; /* Accept certificate. */ 160} 161 162 163static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex) 164 165{ 166 int rc; 167 struct SessionHandle * data = conn->data; 168 struct ssl_connect_data * connssl = &conn->ssl[sockindex]; 169 SSLHandle * h = connssl->handle; 170 long timeout_ms; 171 172 h->exitPgm = NULL; 173 174 if(!data->set.ssl.verifyhost) 175 h->exitPgm = Curl_qsossl_trap_cert; 176 177 /* figure out how long time we should wait at maximum */ 178 timeout_ms = Curl_timeleft(data, NULL, TRUE); 179 180 if(timeout_ms < 0) { 181 /* time-out, bail out, go home */ 182 failf(data, "Connection time-out"); 183 return CURLE_OPERATION_TIMEDOUT; 184 } 185 186 /* SSL_Handshake() timeout resolution is second, so round up. */ 187 h->timeout = (timeout_ms + 1000 - 1) / 1000; 188 189 /* Set-up protocol. */ 190 191 switch (data->set.ssl.version) { 192 193 default: 194 case CURL_SSLVERSION_DEFAULT: 195 h->protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */ 196 break; 197 198 case CURL_SSLVERSION_TLSv1: 199 h->protocol = TLS_VERSION_1; 200 break; 201 202 case CURL_SSLVERSION_SSLv2: 203 h->protocol = SSL_VERSION_2; 204 break; 205 206 case CURL_SSLVERSION_SSLv3: 207 h->protocol = SSL_VERSION_3; 208 break; 209 } 210 211 rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT); 212 213 switch (rc) { 214 215 case 0: /* No error. */ 216 break; 217 218 case SSL_ERROR_BAD_CERTIFICATE: 219 case SSL_ERROR_BAD_CERT_SIG: 220 case SSL_ERROR_NOT_TRUSTED_ROOT: 221 return CURLE_PEER_FAILED_VERIFICATION; 222 223 case SSL_ERROR_BAD_CIPHER_SUITE: 224 case SSL_ERROR_NO_CIPHERS: 225 return CURLE_SSL_CIPHER; 226 227 case SSL_ERROR_CERTIFICATE_REJECTED: 228 case SSL_ERROR_CERT_EXPIRED: 229 case SSL_ERROR_NO_CERTIFICATE: 230 return CURLE_SSL_CERTPROBLEM; 231 232 case SSL_ERROR_IO: 233 failf(data, "SSL_Handshake() I/O error: %s", strerror(errno)); 234 return CURLE_SSL_CONNECT_ERROR; 235 236 default: 237 failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL)); 238 return CURLE_SSL_CONNECT_ERROR; 239 } 240 241 return CURLE_OK; 242} 243 244 245static Curl_recv qsossl_recv; 246static Curl_send qsossl_send; 247 248CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex) 249 250{ 251 struct SessionHandle * data = conn->data; 252 struct ssl_connect_data * connssl = &conn->ssl[sockindex]; 253 int rc; 254 255 rc = Curl_qsossl_init_session(data); 256 257 if(rc == CURLE_OK) { 258 rc = Curl_qsossl_create(conn, sockindex); 259 260 if(rc == CURLE_OK) 261 rc = Curl_qsossl_handshake(conn, sockindex); 262 else { 263 SSL_Destroy(connssl->handle); 264 connssl->handle = NULL; 265 connssl->use = FALSE; 266 connssl->state = ssl_connection_none; 267 } 268 } 269 if(rc == CURLE_OK) { 270 connssl->state = ssl_connection_complete; 271 conn->recv[sockindex] = qsossl_recv; 272 conn->send[sockindex] = qsossl_send; 273 } 274 275 return rc; 276} 277 278 279static int Curl_qsossl_close_one(struct ssl_connect_data * conn, 280 struct SessionHandle * data) 281 282{ 283 int rc; 284 285 if(!conn->handle) 286 return 0; 287 288 rc = SSL_Destroy(conn->handle); 289 290 if(rc) { 291 if(rc == SSL_ERROR_IO) { 292 failf(data, "SSL_Destroy() I/O error: %s", strerror(errno)); 293 return -1; 294 } 295 296 /* An SSL error. */ 297 failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL)); 298 return -1; 299 } 300 301 conn->handle = NULL; 302 return 0; 303} 304 305 306void Curl_qsossl_close(struct connectdata *conn, int sockindex) 307 308{ 309 struct SessionHandle *data = conn->data; 310 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 311 312 if(connssl->use) 313 (void) Curl_qsossl_close_one(connssl, data); 314} 315 316 317int Curl_qsossl_close_all(struct SessionHandle * data) 318 319{ 320 /* Unimplemented. */ 321 (void) data; 322 return 0; 323} 324 325 326int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex) 327 328{ 329 struct ssl_connect_data * connssl = &conn->ssl[sockindex]; 330 struct SessionHandle *data = conn->data; 331 ssize_t nread; 332 int what; 333 int rc; 334 char buf[120]; 335 336 if(!connssl->handle) 337 return 0; 338 339 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) 340 return 0; 341 342 if(Curl_qsossl_close_one(connssl, data)) 343 return -1; 344 345 rc = 0; 346 347 what = Curl_socket_ready(conn->sock[sockindex], 348 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); 349 350 for(;;) { 351 if(what < 0) { 352 /* anything that gets here is fatally bad */ 353 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); 354 rc = -1; 355 break; 356 } 357 358 if(!what) { /* timeout */ 359 failf(data, "SSL shutdown timeout"); 360 break; 361 } 362 363 /* Something to read, let's do it and hope that it is the close 364 notify alert from the server. No way to SSL_Read now, so use read(). */ 365 366 nread = read(conn->sock[sockindex], buf, sizeof(buf)); 367 368 if(nread < 0) { 369 failf(data, "read: %s", strerror(errno)); 370 rc = -1; 371 } 372 373 if(nread <= 0) 374 break; 375 376 what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); 377 } 378 379 return rc; 380} 381 382 383static ssize_t qsossl_send(struct connectdata * conn, int sockindex, 384 const void * mem, size_t len, CURLcode * curlcode) 385 386{ 387 /* SSL_Write() is said to return 'int' while write() and send() returns 388 'size_t' */ 389 int rc; 390 391 rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len); 392 393 if(rc < 0) { 394 switch(rc) { 395 396 case SSL_ERROR_BAD_STATE: 397 /* The operation did not complete; the same SSL I/O function 398 should be called again later. This is basically an EWOULDBLOCK 399 equivalent. */ 400 *curlcode = CURLE_AGAIN; 401 return -1; 402 403 case SSL_ERROR_IO: 404 switch (errno) { 405 case EWOULDBLOCK: 406 case EINTR: 407 *curlcode = CURLE_AGAIN; 408 return -1; 409 } 410 411 failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno)); 412 *curlcode = CURLE_SEND_ERROR; 413 return -1; 414 } 415 416 /* An SSL error. */ 417 failf(conn->data, "SSL_Write() returned error %s", 418 SSL_Strerror(rc, NULL)); 419 *curlcode = CURLE_SEND_ERROR; 420 return -1; 421 } 422 423 return (ssize_t) rc; /* number of bytes */ 424} 425 426 427static ssize_t qsossl_recv(struct connectdata * conn, int num, char * buf, 428 size_t buffersize, CURLcode * curlcode) 429 430{ 431 char error_buffer[120]; /* OpenSSL documents that this must be at 432 least 120 bytes long. */ 433 unsigned long sslerror; 434 int buffsize; 435 int nread; 436 437 buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; 438 nread = SSL_Read(conn->ssl[num].handle, buf, buffsize); 439 440 if(nread < 0) { 441 /* failed SSL_read */ 442 443 switch (nread) { 444 445 case SSL_ERROR_BAD_STATE: 446 /* there's data pending, re-invoke SSL_Read(). */ 447 *curlcode = CURLE_AGAIN; 448 return -1; 449 450 case SSL_ERROR_IO: 451 switch (errno) { 452 case EWOULDBLOCK: 453 *curlcode = CURLE_AGAIN; 454 return -1; 455 } 456 457 failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno)); 458 *curlcode = CURLE_RECV_ERROR; 459 return -1; 460 461 default: 462 failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL)); 463 *curlcode = CURLE_RECV_ERROR; 464 return -1; 465 } 466 } 467 return (ssize_t) nread; 468} 469 470 471size_t Curl_qsossl_version(char * buffer, size_t size) 472 473{ 474 strncpy(buffer, "IBM OS/400 SSL", size); 475 return strlen(buffer); 476} 477 478 479int Curl_qsossl_check_cxn(struct connectdata * cxn) 480 481{ 482 int err; 483 int errlen; 484 485 /* The only thing that can be tested here is at the socket level. */ 486 487 if(!cxn->ssl[FIRSTSOCKET].handle) 488 return 0; /* connection has been closed */ 489 490 err = 0; 491 errlen = sizeof err; 492 493 if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR, 494 (unsigned char *) &err, &errlen) || 495 errlen != sizeof err || err) 496 return 0; /* connection has been closed */ 497 498 return -1; /* connection status unknown */ 499} 500 501#endif /* USE_QSOSSL */ 502