int SslSocket::getError() const { int result; socklen_t rSize = sizeof (result); if (::getsockopt(impl->fd, SOL_SOCKET, SO_ERROR, &result, &rSize) < 0) throw QPID_POSIX_ERROR(errno); return result; }
SslSocket* SslSocket::accept() const { int afd = ::accept(impl->fd, 0, 0); if ( afd >= 0) { return new SslSocket(new IOHandlePrivate(afd), prototype); } else if (errno == EAGAIN) { return 0; } else { throw QPID_POSIX_ERROR(errno); } }
Socket* SslSocket::accept() const { QPID_LOG(trace, "Accepting SSL connection."); int afd = ::accept(fd, 0, 0); if ( afd >= 0) { return new SslSocket(afd, prototype); } else if (errno == EAGAIN) { return 0; } else { throw QPID_POSIX_ERROR(errno); } }
Socket* SslMuxSocket::accept() const { int afd = ::accept(fd, 0, 0); if (afd >= 0) { QPID_LOG(trace, "Accepting connection with optional SSL wrapper."); if (isSslStream(afd)) { QPID_LOG(trace, "Accepted SSL connection."); return new SslSocket(afd, prototype); } else { QPID_LOG(trace, "Accepted Plaintext connection."); return new BSDSocket(afd); } } else if (errno == EAGAIN) { return 0; } else { throw QPID_POSIX_ERROR(errno); } }
int SslSocket::listen(uint16_t port, int backlog, const std::string& certName, bool clientAuth) const { //configure prototype socket: prototype = SSL_ImportFD(0, PR_NewTCPSocket()); if (clientAuth) { NSS_CHECK(SSL_OptionSet(prototype, SSL_REQUEST_CERTIFICATE, PR_TRUE)); NSS_CHECK(SSL_OptionSet(prototype, SSL_REQUIRE_CERTIFICATE, PR_TRUE)); } //get certificate and key (is this the correct way?) CERTCertificate *cert = PK11_FindCertFromNickname(const_cast<char*>(certName.c_str()), 0); if (!cert) throw Exception(QPID_MSG("Failed to load certificate '" << certName << "'")); SECKEYPrivateKey *key = PK11_FindKeyByAnyCert(cert, 0); if (!key) throw Exception(QPID_MSG("Failed to retrieve private key from certificate")); NSS_CHECK(SSL_ConfigSecureServer(prototype, cert, key, NSS_FindCertKEAType(cert))); SECKEY_DestroyPrivateKey(key); CERT_DestroyCertificate(cert); //bind and listen const int& socket = impl->fd; int yes=1; QPID_POSIX_CHECK(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes))); struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = htons(port); name.sin_addr.s_addr = 0; if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0) throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(errno))); if (::listen(socket, backlog) < 0) throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(errno))); socklen_t namelen = sizeof(name); if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0) throw QPID_POSIX_ERROR(errno); return ntohs(name.sin_port); }
static bool isSslStream(int afd) { int retries = SSL_STREAM_MAX_RETRIES; unsigned char buf[5] = {}; do { struct pollfd fd = {afd, POLLIN, 0}; /* * Note that this is blocking the accept thread, so connections that * send no data can limit the rate at which we can accept new * connections. */ if (::poll(&fd, 1, SSL_STREAM_MAX_WAIT_ms) > 0) { errno = 0; int result = recv(afd, buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT); if (result == sizeof(buf)) { break; } if (errno && errno != EAGAIN) { int err = errno; ::close(afd); throw QPID_POSIX_ERROR(err); } } } while (retries-- > 0); if (retries < 0) { return false; } /* * SSLv2 Client Hello format * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html * * Bytes 0-1: RECORD-LENGTH * Byte 2: MSG-CLIENT-HELLO (1) * Byte 3: CLIENT-VERSION-MSB * Byte 4: CLIENT-VERSION-LSB * * Allowed versions: * 2.0 - SSLv2 * 3.0 - SSLv3 * 3.1 - TLS 1.0 * 3.2 - TLS 1.1 * 3.3 - TLS 1.2 * * The version sent in the Client-Hello is the latest version supported by * the client. NSS may send version 3.x in an SSLv2 header for * maximum compatibility. */ bool isSSL2Handshake = buf[2] == 1 && // MSG-CLIENT-HELLO ((buf[3] == 3 && buf[4] <= 3) || // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3) (buf[3] == 2 && buf[4] == 0)); // SSL 2 /* * SSLv3/TLS Client Hello format * RFC 2246 * * Byte 0: ContentType (handshake - 22) * Bytes 1-2: ProtocolVersion {major, minor} * * Allowed versions: * 3.0 - SSLv3 * 3.1 - TLS 1.0 * 3.2 - TLS 1.1 * 3.3 - TLS 1.2 */ bool isSSL3Handshake = buf[0] == 22 && // handshake (buf[1] == 3 && buf[2] <= 3); // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3) return isSSL2Handshake || isSSL3Handshake; }
SslSocket::SslSocket() : IOHandle(new IOHandlePrivate()), socket(0), prototype(0) { impl->fd = ::socket (PF_INET, SOCK_STREAM, 0); if (impl->fd < 0) throw QPID_POSIX_ERROR(errno); socket = SSL_ImportFD(0, PR_ImportTCPSocket(impl->fd)); }