std::streamsize Connection::read(char* buf, std::size_t n, std::streamsize maxImport) { log_trace("Connection::read"); std::streambuf* sb = _ios->rdbuf(); if( ! sb) return 0; if(maxImport == 0) maxImport = sb->in_avail(); std::size_t processed = 0; _isReading = true; _maxImport = maxImport; OSStatus error = SSLRead(_context, buf, n, &processed); _isReading = false; log_trace("Connection::read: " << error); if(error == errSSLClosedGraceful) { _receivedShutdown = true; } else if(error != noErr && error != errSSLWouldBlock) { throw SslError("decoding failed"); } return static_cast<std::streamsize>(processed); }
bool Connection::readHandshake() { log_trace("Connection::readHandshake"); std::streambuf* sb = _ios->rdbuf(); if( ! sb) return true; while(_ios->rdbuf()->in_avail() > 0) { const std::streamsize bufsize = 2000; char buf[bufsize]; std::streamsize gsize = std::min( sb->in_avail(), bufsize ); std::streamsize n = sb->sgetn(buf, gsize); const int written = BIO_write(_in, buf, static_cast<int>(n)); assert(written == n); if(written <= 0 || written != n) throw SslError("BIO_write"); log_debug("read " << n << " bytes from input"); } int ret = SSL_do_handshake(_ssl); log_debug("SSL_do_handshake returns " << ret); if( ret <= 0 ) { int sslerr = SSL_get_error(_ssl, ret); if( sslerr != SSL_ERROR_WANT_READ && sslerr != SSL_ERROR_WANT_WRITE) { if(sslerr == SSL_ERROR_SSL) { char buf[255]; ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); log_warn("handshake failed: " << buf); } throw HandshakeFailed("SSL handshake failed"); } } if( ret == 1 && BIO_pending(_out) <= 0 ) { _connected = true; } return BIO_pending(_out) <= 0 && SSL_want_read(_ssl); }
int SslOcspStapling::certVerify(OCSP_RESPONSE *pResponse, OCSP_BASICRESP *pBasicResp, X509_STORE *pXstore) { int n, iResult = -1; STACK_OF(X509) *pXchain; ASN1_GENERALIZEDTIME *pThisupdate, *pNextupdate; struct stat st; pXchain = m_pCtx->extra_certs; if (OCSP_basic_verify(pBasicResp, pXchain, pXstore, OCSP_NOVERIFY) == 1) { if ((m_pCertId != NULL) && (OCSP_resp_find_status(pBasicResp, m_pCertId, &n, NULL, NULL, &pThisupdate, &pNextupdate) == 1) && (n == V_OCSP_CERTSTATUS_GOOD) && (OCSP_check_validity(pThisupdate, pNextupdate, 300, -1) == 1)) { iResult = 0; updateRespData(pResponse); unlink(m_sRespfile.c_str()); rename(m_sRespfileTmp.c_str(), m_sRespfile.c_str()); if (::stat(m_sRespfile.c_str(), &st) == 0) m_RespTime = st.st_mtime; } } else Logger::getRootLogger()->error("OCSP_basic_verify() failed: %s\n", SslError().what()); if (iResult) { setLastErrMsg("%s", SslError().what()); ERR_clear_error(); if (m_pHttpFetch) m_pHttpFetch->writeLog(s_ErrMsg.c_str()); } return iResult; }
std::streamsize Connection::write(const char* buf, std::size_t n) { std::streambuf* sb = _ios->rdbuf(); if( ! sb) return 0; std::size_t processed = 0; OSStatus error = SSLWrite(_context, buf, n, &processed); if(error != noErr && error != errSSLWouldBlock) throw SslError("encoding failed"); return static_cast<std::streamsize>(processed); }
bool Connection::writeHandshake() { log_trace("Connection::writeHandshake"); std::streambuf* sb = _ios->rdbuf(); if( ! sb) return false; int ret = SSL_do_handshake(_ssl); log_debug("SSL_do_handshake returns " << ret); if(ret <= 0) { const int sslerr = SSL_get_error(_ssl, ret); if(sslerr != SSL_ERROR_WANT_READ && sslerr != SSL_ERROR_WANT_WRITE) { if(sslerr == SSL_ERROR_SSL) { char buf[255]; ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); log_warn("handshake failed: " << buf); } throw HandshakeFailed("SSL handshake failed"); } } if(ret == 1) { _connected = true; } if( BIO_pending(_out) ) { char buff[1000]; const int n = BIO_read(_out, buff, sizeof(buff)); log_debug("wrote " << n << " bytes to output"); if(n <= 0) throw SslError("BIO_read"); sb->sputn(buff, n); return true; } return SSL_want_write(_ssl); }
int ProxyConn::connectSSL() { if (!m_ssl.getSSL()) { m_ssl.setSSL(getSslConn()); if (!m_ssl.getSSL()) return LS_FAIL; m_ssl.setfd(getfd()); HttpReq *pReq = getConnector()->getHttpSession()->getReq(); char *pHostName; int hostLen = pReq->getNewHostLen(); if (hostLen > 0) pHostName = (char *)pReq->getNewHost(); else { pHostName = (char *)pReq->getHeader(HttpHeader::H_HOST); hostLen = pReq->getHeaderLen(HttpHeader::H_HOST); } if (pHostName) { char ch = *(pHostName + hostLen); *(pHostName + hostLen) = 0; m_ssl.setTlsExtHostName(pHostName); *(pHostName + hostLen) = ch; } } int ret = m_ssl.connect(); switch (ret) { case 0: setSSLAgain(); break; case 1: LS_DBG_L(this, "[SSL] connected!"); break; default: if (errno == EIO) LS_DBG_L(this, "SSL_connect() failed!: %s ", SslError().what()); break; } return ret; }
std::streamsize Connection::read(char* buf, std::size_t n, std::streamsize maxImport) { std::streambuf* sb = _ios->rdbuf(); if( ! sb) return 0; if(maxImport == 0) maxImport = sb->in_avail(); while(true) { // even if we could not refill the BIO, we might still get data from the SSL const int readSize = SSL_read(_ssl, buf, n); log_debug("Read " << readSize << " bytes from _ssl"); log_debug("SSL_get_shutdown() = " << SSL_get_shutdown(_ssl)); if(readSize > 0) { return readSize; } long sslerr = SSL_get_error(_ssl, readSize); // happens when the peer has send the shutdown alert if(sslerr == SSL_ERROR_ZERO_RETURN) { log_debug("SSL_ERROR_ZERO_RETURN"); return 0; } if(sslerr != SSL_ERROR_WANT_READ) { log_debug("ssl error occured"); while( sslerr = ERR_get_error() ) { log_debug("ERR_error_string = " << ERR_error_string(sslerr, 0)); } throw SslError("SSL_read"); } if(maxImport == 0) return 0; // Refill the BIO with encoded bytes for decoding BUF_MEM* bm = 0; BIO_get_mem_ptr(_in, &bm); if(bm->max == bm->length) continue; const std::streamsize refill = std::min(static_cast<std::streamsize>(bm->max - bm->length), maxImport); log_debug("get " << refill << " bytes from _ios"); std::streamsize gcount = sb->sgetn(bm->data + bm->length, refill); if(gcount <= 0) return 0; bm->length += static_cast<int>( gcount ); log_debug("Wrote " << gcount << " bytes from _ios to _in BUF_MEM"); maxImport -= gcount; } return 0; }
bool Connection::shutdown() { log_debug("Connection::shutdown"); if( ! _connected ) return true; std::streambuf* sb = _ios->rdbuf(); if( ! sb) return false; int state = SSL_get_shutdown(_ssl); log_debug("SSL_get_shutdown() = " << state); bool shutdownSent = (SSL_SENT_SHUTDOWN & state) == SSL_SENT_SHUTDOWN; if( ! shutdownSent ) { // write shutdown notify log_debug("write shutdown notify"); int r = SSL_shutdown(_ssl); log_debug("SSL_shutdown() = " << r); char buf[1000]; const int n = BIO_read(_out, buf, sizeof(buf)); if(n <= 0) throw SslError("BIO_read"); sb->sputn(buf, n); log_debug("wrote " << n << " bytes to output"); if(r == 1) { log_debug("shutdown complete"); SSL_clear(_ssl); _connected = false; return true; } } // read shutdown notify log_debug("read shutdown notify"); BUF_MEM* bm = 0; BIO_get_mem_ptr(_in, &bm); std::streamsize avail = sb->in_avail(); std::streamsize refill = std::min(static_cast<std::streamsize>(bm->max - bm->length), avail); log_debug("refill " << refill << " bytes"); std::streamsize gcount = sb->sgetn(bm->data + bm->length, refill); bm->length += static_cast<int>( gcount ); log_debug("got " << gcount << " bytes from input stream"); int r = SSL_shutdown(_ssl); log_debug("SSL_shutdown() = " << r); if(r == 1) { log_debug("shutdown complete"); SSL_clear(_ssl); _connected = false; return true; } return false; }
bool Connection::shutdown() { if( ! _connected ) return true; std::streambuf* sb = _ios->rdbuf(); if( ! sb) return false; if( ! _sentShutdown) { // write shutdown notify log_debug("write shutdown notify"); _isWriting = true; OSStatus error = SSLClose(_context); _isWriting = false; log_debug("SSLClose: " << error); if(error == errSSLWouldBlock) { // need to read shutdown alert log_debug("want to read shutdown alert"); _sentShutdown = true; return false; } if(error != noErr) throw SslError("shutdown failed"); log_debug("shutdown complete"); _connected = false; _sentShutdown = false; _receivedShutdown = false; return true; } // read shutdown notify log_debug("read shutdown notify"); _maxImport = sb->in_avail(); _wantRead = false; _isReading = true; OSStatus error = SSLClose(_context); _isReading = false; log_debug("SSLClose: " << error); if(error == errSSLWouldBlock) { return false; } if(error != noErr) throw SslError("shutdown failed"); log_debug("shutdown complete"); _connected = false; _sentShutdown = false; _receivedShutdown = false; return true; }