Loading CHANGES +4 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,10 @@ Changelog Daniel S (23 July 2007) - Implemented the parts of Patrick Monnerat's OS/400 patch that introduces support for the OS/400 Secure Sockets Layer library. Dan F (23 July 2007) - Implemented only the parts of Patrick Monnerat's OS/400 patch that renamed some few internal identifiers to avoid conflicts, which could be useful on Loading RELEASE-NOTES +1 −1 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ Curl and libcurl 7.16.5 This release includes the following changes: o o support for OS/400 Secure Sockets Layer library This release includes the following bugfixes: Loading lib/Makefile.inc +14 −14 Original line number Diff line number Diff line Loading @@ -4,20 +4,20 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ ldap.c ssluse.c version.c getenv.c escape.c mprintf.c telnet.c \ netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c \ krb5.c \ memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c multi.c \ content_encoding.c share.c http_digest.c md5.c http_negotiate.c \ http_ntlm.c inet_pton.c strtoofft.c strerror.c hostares.c hostasyn.c \ hostip4.c hostip6.c hostsyn.c hostthre.c inet_ntop.c parsedate.c \ select.c gtls.c sslgen.c tftp.c splay.c strdup.c socks.c ssh.c nss.c krb5.c memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c \ multi.c content_encoding.c share.c http_digest.c md5.c \ http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c \ hostares.c hostasyn.c hostip4.c hostip6.c hostsyn.c hostthre.c \ inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c \ strdup.c socks.c ssh.c nss.c qssl.c HHEADERS = arpa_telnet.h netrc.h file.h timeval.h base64.h hostip.h \ progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \ if2ip.h speedcheck.h urldata.h ldap.h ssluse.h escape.h telnet.h \ getinfo.h strequal.h krb4.h memdebug.h inet_ntoa_r.h \ http_chunks.h strtok.h connect.h llist.h hash.h content_encoding.h \ share.h md5.h http_digest.h http_negotiate.h http_ntlm.h ca-bundle.h \ inet_pton.h strtoofft.h strerror.h inet_ntop.h curlx.h memory.h \ setup.h transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h \ gtls.h tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h \ nssg.h getinfo.h strequal.h krb4.h memdebug.h inet_ntoa_r.h http_chunks.h \ strtok.h connect.h llist.h hash.h content_encoding.h share.h md5.h \ http_digest.h http_negotiate.h http_ntlm.h ca-bundle.h inet_pton.h \ strtoofft.h strerror.h inet_ntop.h curlx.h memory.h setup.h \ transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h \ tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h \ qssl.h lib/qssl.c 0 → 100644 +496 −0 Original line number Diff line number Diff line /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * $Id$ ***************************************************************************/ #include "setup.h" #ifdef USE_QSOSSL #include <qsossl.h> #include <errno.h> #include <string.h> #include <curl/curl.h> #include "urldata.h" #include "sendf.h" #include "qssl.h" #include "sslgen.h" #include "connect.h" /* for the connect timeout */ #include "select.h" #include "memory.h" /* The last #include file should be: */ #include "memdebug.h" static bool qsossl_inited = FALSE; int Curl_qsossl_init(void) { /* Nothing to do here. We must have connection data to initialize ssl, so * defer. */ return 1; } void Curl_qsossl_cleanup(void) { /* Nothing to do. */ } static CURLcode Curl_qsossl_init_session(struct SessionHandle * data) { int rc; char * certname; SSLInit initstr; SSLInitApp initappstr; /* Initialize the job for SSL according to the current parameters. * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an * application identifier to select certificates in the main certificate * store, and SSL_Init() that uses named keyring files and a password. * It is not possible to have different keyrings for the CAs and the * local certificate. We thus use the certificate name to identify the * keyring if given, else the CA file name. * If the key file name is given, it is taken as the password for the * keyring in certificate file. * We first try to SSL_Init_Application(), then SSL_Init() if it failed. */ certname = data->set.cert; if (!certname) { certname = data->set.ssl.CAfile; if (!certname) return CURLE_OK; /* Use previous setup. */ } memset((char *) &initappstr, 0, sizeof initappstr); initappstr.applicationID = certname; initappstr.applicationIDLen = strlen(certname); initappstr.protocol = SSL_VERSION_CURRENT; initappstr.sessionType = SSL_REGISTERED_AS_CLIENT; rc = SSL_Init_Application(&initappstr); if (rc == SSL_ERROR_NOT_REGISTERED) { initstr.keyringFileName = certname; initstr.keyringPassword = data->set.key; initstr.cipherSuiteList = NULL; /* Use default. */ initstr.cipherSuiteListLen = 0; rc = SSL_Init(&initstr); } switch (rc) { case 0: /* No error. */ break; case SSL_ERROR_IO: failf(data, "SSL_Init() I/O error: %s\n", strerror(errno)); return CURLE_SSL_CONNECT_ERROR; case SSL_ERROR_BAD_CIPHER_SUITE: return CURLE_SSL_CIPHER; case SSL_ERROR_KEYPASSWORD_EXPIRED: case SSL_ERROR_NOT_REGISTERED: return CURLE_SSL_CONNECT_ERROR; case SSL_ERROR_NO_KEYRING: return CURLE_SSL_CACERT; case SSL_ERROR_CERT_EXPIRED: return CURLE_SSL_CERTPROBLEM; default: failf(data, "SSL_Init(): %s\n", SSL_Strerror(rc, NULL)); return CURLE_SSL_CONNECT_ERROR; } return CURLE_OK; } static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex) { SSLHandle * h; struct ssl_connect_data * connssl = &conn->ssl[sockindex]; h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT); if (!h) { failf(conn->data, "SSL_Create() I/O error: %s\n", strerror(errno)); return CURLE_SSL_CONNECT_ERROR; } connssl->handle = h; return CURLE_OK; } static int Curl_qsossl_trap_cert(SSLHandle * h) { return 1; /* Accept certificate. */ } static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex) { int rc; struct SessionHandle * data = conn->data; struct ssl_connect_data * connssl = &conn->ssl[sockindex]; SSLHandle * h = connssl->handle; long timeout_ms; h->exitPgm = NULL; if (!data->set.ssl.verifyhost) h->exitPgm = Curl_qsossl_trap_cert; if (data->set.connecttimeout) { timeout_ms = data->set.connecttimeout; if (data->set.timeout) if (timeout_ms > data->set.timeout) timeout_ms = data->set.timeout; } else if (data->set.timeout) timeout_ms = data->set.timeout; else timeout_ms = DEFAULT_CONNECT_TIMEOUT; /* SSL_Handshake() timeout resolution is second, so round up. */ h->timeout = (timeout_ms + 1000 - 1) / 1000; /* Set-up protocol. */ switch(data->set.ssl.version) { default: case CURL_SSLVERSION_DEFAULT: h->protocol = SSL_VERSION_CURRENT; break; case CURL_SSLVERSION_TLSv1: h->protocol = TLS_VERSION_1; break; case CURL_SSLVERSION_SSLv2: h->protocol = SSL_VERSION_2; break; case CURL_SSLVERSION_SSLv3: h->protocol = SSL_VERSION_3; break; } rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT); switch (rc) { case 0: /* No error. */ break; case SSL_ERROR_BAD_CERTIFICATE: case SSL_ERROR_BAD_CERT_SIG: case SSL_ERROR_NOT_TRUSTED_ROOT: return CURLE_SSL_PEER_CERTIFICATE; case SSL_ERROR_BAD_CIPHER_SUITE: case SSL_ERROR_NO_CIPHERS: return CURLE_SSL_CIPHER; case SSL_ERROR_CERTIFICATE_REJECTED: case SSL_ERROR_CERT_EXPIRED: case SSL_ERROR_NO_CERTIFICATE: return CURLE_SSL_CERTPROBLEM; case SSL_ERROR_IO: failf(data, "SSL_Handshake(): %s\n", SSL_Strerror(rc, NULL)); return CURLE_SSL_CONNECT_ERROR; default: failf(data, "SSL_Init(): %s\n", SSL_Strerror(rc, NULL)); return CURLE_SSL_CONNECT_ERROR; } return CURLE_OK; } CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex) { struct SessionHandle * data = conn->data; struct ssl_connect_data * connssl = &conn->ssl[sockindex]; int rc; rc = Curl_qsossl_init_session(data); if (rc == CURLE_OK) { rc = Curl_qsossl_create(conn, sockindex); if (rc == CURLE_OK) rc = Curl_qsossl_handshake(conn, sockindex); else { SSL_Destroy(connssl->handle); connssl->handle = NULL; connssl->use = FALSE; } } return rc; } static int Curl_qsossl_close_one(struct ssl_connect_data * conn, struct SessionHandle * data) { int rc; if (!conn->handle) return 0; rc = SSL_Destroy(conn->handle); if(rc) { if (rc == SSL_ERROR_IO) { failf(data, "SSL_Destroy() I/O error: %s\n", strerror(errno)); return -1; } /* An SSL error. */ failf(data, "SSL_Destroy() returned error %d\n", SSL_Strerror(rc, NULL)); return -1; } conn->use = FALSE; /* get back to ordinary socket usage */ conn->handle = NULL; return 0; } void Curl_qsossl_close(struct connectdata * conn) { struct SessionHandle * data = conn->data; struct ssl_connect_data * connssl = conn->ssl; if(connssl->use) (void) Curl_qsossl_close_one(connssl, data); connssl++; if(connssl->use) (void) Curl_qsossl_close_one(connssl, data); } int Curl_qsossl_close_all(struct SessionHandle * data) { /* Unimplemented. */ (void) data; return 0; } int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex) { struct ssl_connect_data * connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; ssize_t nread; int what; int rc; char buf[120]; if (!connssl->handle) return 0; if (data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) return 0; if (Curl_qsossl_close_one(connssl, data)) return -1; rc = 0; what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); for (;;) { if (what < 0) { /* anything that gets here is fatally bad */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); rc = -1; break; } if (!what) { /* timeout */ failf(data, "SSL shutdown timeout"); break; } /* Something to read, let's do it and hope that it is the close notify alert from the server. No way to SSL_Read now, so use read(). */ nread = read(conn->sock[sockindex], buf, sizeof(buf)); if (nread < 0) { failf(data, "read: %s\n", strerror(errno)); rc = -1; } if (nread <= 0) break; what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); } return rc; } ssize_t Curl_qsossl_send(struct connectdata * conn, int sockindex, void * mem, size_t len) { /* SSL_Write() is said to return 'int' while write() and send() returns 'size_t' */ int rc; rc = SSL_Write(conn->ssl[sockindex].handle, mem, (int) len); if(rc < 0) { switch(rc) { case SSL_ERROR_BAD_STATE: /* The operation did not complete; the same SSL I/O function should be called again later. This is basicly an EWOULDBLOCK equivalent. */ return 0; case SSL_ERROR_IO: switch (errno) { case EWOULDBLOCK: case EINTR: return 0; } failf(conn->data, "SSL_Write() I/O error: %s\n", strerror(errno)); return -1; } /* An SSL error. */ failf(conn->data, "SSL_Write() returned error %d\n", SSL_Strerror(rc, NULL)); return -1; } return (ssize_t) rc; /* number of bytes */ } ssize_t Curl_qsossl_recv(struct connectdata * conn, int num, char * buf, size_t buffersize, bool * wouldblock) { char error_buffer[120]; /* OpenSSL documents that this must be at least 120 bytes long. */ unsigned long sslerror; int nread; nread = SSL_Read(conn->ssl[num].handle, buf, (int) buffersize); *wouldblock = FALSE; if(nread < 0) { /* failed SSL_read */ switch (nread) { case SSL_ERROR_BAD_STATE: /* there's data pending, re-invoke SSL_Read(). */ *wouldblock = TRUE; return -1; /* basically EWOULDBLOCK */ case SSL_ERROR_IO: switch (errno) { case EWOULDBLOCK: *wouldblock = TRUE; return -1; } failf(conn->data, "SSL_Read() I/O error: %s\n", strerror(errno)); return -1; default: failf(conn->data, "SSL read error: %s\n", SSL_Strerror(nread, NULL)); return -1; } } return (ssize_t) nread; } size_t Curl_qsossl_version(char * buffer, size_t size) { strncpy(buffer, "IBM OS/400 SSL", size); return strlen(buffer); } int Curl_qsossl_check_cxn(struct connectdata * cxn) { int err; int errlen; /* The only thing that can be tested here is at the socket level. */ if (!cxn->ssl[FIRSTSOCKET].handle) return 0; /* connection has been closed */ err = 0; errlen = sizeof err; if (getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR, (unsigned char *) &err, &errlen) || errlen != sizeof err || err) return 0; /* connection has been closed */ return -1; /* connection status unknown */ } #endif /* USE_QSOSSL */ lib/qssl.h 0 → 100644 +52 −0 Original line number Diff line number Diff line #ifndef __QSSL_H #define __QSSL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * $Id$ ***************************************************************************/ /* * This header should only be needed to get included by sslgen.c and qssl.c */ #include "urldata.h" int Curl_qsossl_init(void); void Curl_qsossl_cleanup(void); CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex); void Curl_qsossl_close(struct connectdata * conn); /* close a SSL connection */ int Curl_qsossl_close_all(struct SessionHandle * data); int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex); ssize_t Curl_qsossl_send(struct connectdata * conn, int sockindex, void * mem, size_t len); ssize_t Curl_qsossl_recv(struct connectdata * conn, /* connection data */ int num, /* socketindex */ char * buf, /* store read data here */ size_t buffersize, /* max amount to read */ bool * wouldblock); size_t Curl_qsossl_version(char * buffer, size_t size); int Curl_qsossl_check_cxn(struct connectdata * cxn); #endif Loading
CHANGES +4 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,10 @@ Changelog Daniel S (23 July 2007) - Implemented the parts of Patrick Monnerat's OS/400 patch that introduces support for the OS/400 Secure Sockets Layer library. Dan F (23 July 2007) - Implemented only the parts of Patrick Monnerat's OS/400 patch that renamed some few internal identifiers to avoid conflicts, which could be useful on Loading
RELEASE-NOTES +1 −1 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ Curl and libcurl 7.16.5 This release includes the following changes: o o support for OS/400 Secure Sockets Layer library This release includes the following bugfixes: Loading
lib/Makefile.inc +14 −14 Original line number Diff line number Diff line Loading @@ -4,20 +4,20 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ ldap.c ssluse.c version.c getenv.c escape.c mprintf.c telnet.c \ netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c \ krb5.c \ memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c multi.c \ content_encoding.c share.c http_digest.c md5.c http_negotiate.c \ http_ntlm.c inet_pton.c strtoofft.c strerror.c hostares.c hostasyn.c \ hostip4.c hostip6.c hostsyn.c hostthre.c inet_ntop.c parsedate.c \ select.c gtls.c sslgen.c tftp.c splay.c strdup.c socks.c ssh.c nss.c krb5.c memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c \ multi.c content_encoding.c share.c http_digest.c md5.c \ http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c \ hostares.c hostasyn.c hostip4.c hostip6.c hostsyn.c hostthre.c \ inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c \ strdup.c socks.c ssh.c nss.c qssl.c HHEADERS = arpa_telnet.h netrc.h file.h timeval.h base64.h hostip.h \ progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \ if2ip.h speedcheck.h urldata.h ldap.h ssluse.h escape.h telnet.h \ getinfo.h strequal.h krb4.h memdebug.h inet_ntoa_r.h \ http_chunks.h strtok.h connect.h llist.h hash.h content_encoding.h \ share.h md5.h http_digest.h http_negotiate.h http_ntlm.h ca-bundle.h \ inet_pton.h strtoofft.h strerror.h inet_ntop.h curlx.h memory.h \ setup.h transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h \ gtls.h tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h \ nssg.h getinfo.h strequal.h krb4.h memdebug.h inet_ntoa_r.h http_chunks.h \ strtok.h connect.h llist.h hash.h content_encoding.h share.h md5.h \ http_digest.h http_negotiate.h http_ntlm.h ca-bundle.h inet_pton.h \ strtoofft.h strerror.h inet_ntop.h curlx.h memory.h setup.h \ transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h \ tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h \ qssl.h
lib/qssl.c 0 → 100644 +496 −0 Original line number Diff line number Diff line /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * $Id$ ***************************************************************************/ #include "setup.h" #ifdef USE_QSOSSL #include <qsossl.h> #include <errno.h> #include <string.h> #include <curl/curl.h> #include "urldata.h" #include "sendf.h" #include "qssl.h" #include "sslgen.h" #include "connect.h" /* for the connect timeout */ #include "select.h" #include "memory.h" /* The last #include file should be: */ #include "memdebug.h" static bool qsossl_inited = FALSE; int Curl_qsossl_init(void) { /* Nothing to do here. We must have connection data to initialize ssl, so * defer. */ return 1; } void Curl_qsossl_cleanup(void) { /* Nothing to do. */ } static CURLcode Curl_qsossl_init_session(struct SessionHandle * data) { int rc; char * certname; SSLInit initstr; SSLInitApp initappstr; /* Initialize the job for SSL according to the current parameters. * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an * application identifier to select certificates in the main certificate * store, and SSL_Init() that uses named keyring files and a password. * It is not possible to have different keyrings for the CAs and the * local certificate. We thus use the certificate name to identify the * keyring if given, else the CA file name. * If the key file name is given, it is taken as the password for the * keyring in certificate file. * We first try to SSL_Init_Application(), then SSL_Init() if it failed. */ certname = data->set.cert; if (!certname) { certname = data->set.ssl.CAfile; if (!certname) return CURLE_OK; /* Use previous setup. */ } memset((char *) &initappstr, 0, sizeof initappstr); initappstr.applicationID = certname; initappstr.applicationIDLen = strlen(certname); initappstr.protocol = SSL_VERSION_CURRENT; initappstr.sessionType = SSL_REGISTERED_AS_CLIENT; rc = SSL_Init_Application(&initappstr); if (rc == SSL_ERROR_NOT_REGISTERED) { initstr.keyringFileName = certname; initstr.keyringPassword = data->set.key; initstr.cipherSuiteList = NULL; /* Use default. */ initstr.cipherSuiteListLen = 0; rc = SSL_Init(&initstr); } switch (rc) { case 0: /* No error. */ break; case SSL_ERROR_IO: failf(data, "SSL_Init() I/O error: %s\n", strerror(errno)); return CURLE_SSL_CONNECT_ERROR; case SSL_ERROR_BAD_CIPHER_SUITE: return CURLE_SSL_CIPHER; case SSL_ERROR_KEYPASSWORD_EXPIRED: case SSL_ERROR_NOT_REGISTERED: return CURLE_SSL_CONNECT_ERROR; case SSL_ERROR_NO_KEYRING: return CURLE_SSL_CACERT; case SSL_ERROR_CERT_EXPIRED: return CURLE_SSL_CERTPROBLEM; default: failf(data, "SSL_Init(): %s\n", SSL_Strerror(rc, NULL)); return CURLE_SSL_CONNECT_ERROR; } return CURLE_OK; } static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex) { SSLHandle * h; struct ssl_connect_data * connssl = &conn->ssl[sockindex]; h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT); if (!h) { failf(conn->data, "SSL_Create() I/O error: %s\n", strerror(errno)); return CURLE_SSL_CONNECT_ERROR; } connssl->handle = h; return CURLE_OK; } static int Curl_qsossl_trap_cert(SSLHandle * h) { return 1; /* Accept certificate. */ } static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex) { int rc; struct SessionHandle * data = conn->data; struct ssl_connect_data * connssl = &conn->ssl[sockindex]; SSLHandle * h = connssl->handle; long timeout_ms; h->exitPgm = NULL; if (!data->set.ssl.verifyhost) h->exitPgm = Curl_qsossl_trap_cert; if (data->set.connecttimeout) { timeout_ms = data->set.connecttimeout; if (data->set.timeout) if (timeout_ms > data->set.timeout) timeout_ms = data->set.timeout; } else if (data->set.timeout) timeout_ms = data->set.timeout; else timeout_ms = DEFAULT_CONNECT_TIMEOUT; /* SSL_Handshake() timeout resolution is second, so round up. */ h->timeout = (timeout_ms + 1000 - 1) / 1000; /* Set-up protocol. */ switch(data->set.ssl.version) { default: case CURL_SSLVERSION_DEFAULT: h->protocol = SSL_VERSION_CURRENT; break; case CURL_SSLVERSION_TLSv1: h->protocol = TLS_VERSION_1; break; case CURL_SSLVERSION_SSLv2: h->protocol = SSL_VERSION_2; break; case CURL_SSLVERSION_SSLv3: h->protocol = SSL_VERSION_3; break; } rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT); switch (rc) { case 0: /* No error. */ break; case SSL_ERROR_BAD_CERTIFICATE: case SSL_ERROR_BAD_CERT_SIG: case SSL_ERROR_NOT_TRUSTED_ROOT: return CURLE_SSL_PEER_CERTIFICATE; case SSL_ERROR_BAD_CIPHER_SUITE: case SSL_ERROR_NO_CIPHERS: return CURLE_SSL_CIPHER; case SSL_ERROR_CERTIFICATE_REJECTED: case SSL_ERROR_CERT_EXPIRED: case SSL_ERROR_NO_CERTIFICATE: return CURLE_SSL_CERTPROBLEM; case SSL_ERROR_IO: failf(data, "SSL_Handshake(): %s\n", SSL_Strerror(rc, NULL)); return CURLE_SSL_CONNECT_ERROR; default: failf(data, "SSL_Init(): %s\n", SSL_Strerror(rc, NULL)); return CURLE_SSL_CONNECT_ERROR; } return CURLE_OK; } CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex) { struct SessionHandle * data = conn->data; struct ssl_connect_data * connssl = &conn->ssl[sockindex]; int rc; rc = Curl_qsossl_init_session(data); if (rc == CURLE_OK) { rc = Curl_qsossl_create(conn, sockindex); if (rc == CURLE_OK) rc = Curl_qsossl_handshake(conn, sockindex); else { SSL_Destroy(connssl->handle); connssl->handle = NULL; connssl->use = FALSE; } } return rc; } static int Curl_qsossl_close_one(struct ssl_connect_data * conn, struct SessionHandle * data) { int rc; if (!conn->handle) return 0; rc = SSL_Destroy(conn->handle); if(rc) { if (rc == SSL_ERROR_IO) { failf(data, "SSL_Destroy() I/O error: %s\n", strerror(errno)); return -1; } /* An SSL error. */ failf(data, "SSL_Destroy() returned error %d\n", SSL_Strerror(rc, NULL)); return -1; } conn->use = FALSE; /* get back to ordinary socket usage */ conn->handle = NULL; return 0; } void Curl_qsossl_close(struct connectdata * conn) { struct SessionHandle * data = conn->data; struct ssl_connect_data * connssl = conn->ssl; if(connssl->use) (void) Curl_qsossl_close_one(connssl, data); connssl++; if(connssl->use) (void) Curl_qsossl_close_one(connssl, data); } int Curl_qsossl_close_all(struct SessionHandle * data) { /* Unimplemented. */ (void) data; return 0; } int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex) { struct ssl_connect_data * connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; ssize_t nread; int what; int rc; char buf[120]; if (!connssl->handle) return 0; if (data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) return 0; if (Curl_qsossl_close_one(connssl, data)) return -1; rc = 0; what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); for (;;) { if (what < 0) { /* anything that gets here is fatally bad */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); rc = -1; break; } if (!what) { /* timeout */ failf(data, "SSL shutdown timeout"); break; } /* Something to read, let's do it and hope that it is the close notify alert from the server. No way to SSL_Read now, so use read(). */ nread = read(conn->sock[sockindex], buf, sizeof(buf)); if (nread < 0) { failf(data, "read: %s\n", strerror(errno)); rc = -1; } if (nread <= 0) break; what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); } return rc; } ssize_t Curl_qsossl_send(struct connectdata * conn, int sockindex, void * mem, size_t len) { /* SSL_Write() is said to return 'int' while write() and send() returns 'size_t' */ int rc; rc = SSL_Write(conn->ssl[sockindex].handle, mem, (int) len); if(rc < 0) { switch(rc) { case SSL_ERROR_BAD_STATE: /* The operation did not complete; the same SSL I/O function should be called again later. This is basicly an EWOULDBLOCK equivalent. */ return 0; case SSL_ERROR_IO: switch (errno) { case EWOULDBLOCK: case EINTR: return 0; } failf(conn->data, "SSL_Write() I/O error: %s\n", strerror(errno)); return -1; } /* An SSL error. */ failf(conn->data, "SSL_Write() returned error %d\n", SSL_Strerror(rc, NULL)); return -1; } return (ssize_t) rc; /* number of bytes */ } ssize_t Curl_qsossl_recv(struct connectdata * conn, int num, char * buf, size_t buffersize, bool * wouldblock) { char error_buffer[120]; /* OpenSSL documents that this must be at least 120 bytes long. */ unsigned long sslerror; int nread; nread = SSL_Read(conn->ssl[num].handle, buf, (int) buffersize); *wouldblock = FALSE; if(nread < 0) { /* failed SSL_read */ switch (nread) { case SSL_ERROR_BAD_STATE: /* there's data pending, re-invoke SSL_Read(). */ *wouldblock = TRUE; return -1; /* basically EWOULDBLOCK */ case SSL_ERROR_IO: switch (errno) { case EWOULDBLOCK: *wouldblock = TRUE; return -1; } failf(conn->data, "SSL_Read() I/O error: %s\n", strerror(errno)); return -1; default: failf(conn->data, "SSL read error: %s\n", SSL_Strerror(nread, NULL)); return -1; } } return (ssize_t) nread; } size_t Curl_qsossl_version(char * buffer, size_t size) { strncpy(buffer, "IBM OS/400 SSL", size); return strlen(buffer); } int Curl_qsossl_check_cxn(struct connectdata * cxn) { int err; int errlen; /* The only thing that can be tested here is at the socket level. */ if (!cxn->ssl[FIRSTSOCKET].handle) return 0; /* connection has been closed */ err = 0; errlen = sizeof err; if (getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR, (unsigned char *) &err, &errlen) || errlen != sizeof err || err) return 0; /* connection has been closed */ return -1; /* connection status unknown */ } #endif /* USE_QSOSSL */
lib/qssl.h 0 → 100644 +52 −0 Original line number Diff line number Diff line #ifndef __QSSL_H #define __QSSL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * $Id$ ***************************************************************************/ /* * This header should only be needed to get included by sslgen.c and qssl.c */ #include "urldata.h" int Curl_qsossl_init(void); void Curl_qsossl_cleanup(void); CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex); void Curl_qsossl_close(struct connectdata * conn); /* close a SSL connection */ int Curl_qsossl_close_all(struct SessionHandle * data); int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex); ssize_t Curl_qsossl_send(struct connectdata * conn, int sockindex, void * mem, size_t len); ssize_t Curl_qsossl_recv(struct connectdata * conn, /* connection data */ int num, /* socketindex */ char * buf, /* store read data here */ size_t buffersize, /* max amount to read */ bool * wouldblock); size_t Curl_qsossl_version(char * buffer, size_t size); int Curl_qsossl_check_cxn(struct connectdata * cxn); #endif