std::string WindowsServicePrincipalName::toString() { DWORD length = 512; DWORD status = ERROR_BUFFER_OVERFLOW; bool firstCall = true; std::string str; while (status == ERROR_BUFFER_OVERFLOW) { std::vector<wchar_t> value(length); /* length after this call will contain the required length if current length is not enough - so the next call should succeed */ status = dsMakeSpn(&length, vecptr(value)); if (status == ERROR_SUCCESS) { str = convertWStringToString(std::wstring(vecptr(value), length-1 /* trailing 0 character */)); break; } if ((firstCall == false) || (status != ERROR_BUFFER_OVERFLOW)) { std::stringstream errorString; boost::system::error_code errorCode(status, boost::system::system_category()); errorString << "Error creating Service Principal Name: status: 0x" << std::hex << status << ": " << errorCode.message(); /* Any other error will be a programming error */ throw std::runtime_error(errorString.str()); } firstCall = false; } SWIFT_LOG(debug) << "SPN: " << str << std::endl; return str; }
void OpenSSLContext::sendPendingDataToApplication() { SafeByteArray data; data.resize(SSL_READ_BUFFERSIZE); int ret = SSL_read(handle_, vecptr(data), data.size()); while (ret > 0) { data.resize(ret); onDataForApplication(data); data.resize(SSL_READ_BUFFERSIZE); ret = SSL_read(handle_, vecptr(data), data.size()); } if (ret < 0 && SSL_get_error(handle_, ret) != SSL_ERROR_WANT_READ) { state_ = Error; onError(boost::make_shared<TLSError>()); } }
ByteArray OpenSSLContext::getFinishMessage() const { ByteArray data; data.resize(MAX_FINISHED_SIZE); size_t size = SSL_get_finished(handle_, vecptr(data), data.size()); data.resize(size); return data; }
void OpenSSLContext::handleDataFromApplication(const SafeByteArray& data) { if (SSL_write(handle_, vecptr(data), data.size()) >= 0) { sendPendingDataToNetwork(); } else { state_ = Error; onError(boost::make_shared<TLSError>()); } }
void OpenSSLContext::sendPendingDataToNetwork() { int size = BIO_pending(writeBIO_); if (size > 0) { SafeByteArray data; data.resize(size); BIO_read(writeBIO_, vecptr(data), size); onDataForNetwork(data); } }
void SOCKS5BytestreamClientSession::handleDataRead(boost::shared_ptr<SafeByteArray> data) { SWIFT_LOG(debug) << "state: " << state << " data.size() = " << data->size() << std::endl; if (state != Reading) { append(unprocessedData, *data); process(); } else { writeBytestream->write(createByteArray(vecptr(*data), data->size())); //onBytesReceived(data->size()); } }
void OpenSSLContext::handleDataFromNetwork(const SafeByteArray& data) { BIO_write(readBIO_, vecptr(data), data.size()); switch (state_) { case Connecting: doConnect(); break; case Connected: sendPendingDataToApplication(); break; case Start: assert(false); break; case Error: /*assert(false);*/ break; } }
SafeByteArray ZLibCodecompressor::process(const SafeByteArray& input) { SafeByteArray output; p->stream.avail_in = static_cast<unsigned int>(input.size()); p->stream.next_in = reinterpret_cast<Bytef*>(const_cast<unsigned char*>(vecptr(input))); size_t outputPosition = 0; do { output.resize(outputPosition + CHUNK_SIZE); p->stream.avail_out = CHUNK_SIZE; p->stream.next_out = reinterpret_cast<Bytef*>(vecptr(output) + outputPosition); int result = processZStream(); if (result != Z_OK && result != Z_BUF_ERROR) { throw ZLibException(/* p->stream.msg */); } outputPosition += CHUNK_SIZE; } while (p->stream.avail_out == 0); if (p->stream.avail_in != 0) { throw ZLibException(); } output.resize(outputPosition - p->stream.avail_out); return output; }
bool OpenSSLContext::setClientCertificate(CertificateWithKey::ref certificate) { boost::shared_ptr<PKCS12Certificate> pkcs12Certificate = boost::dynamic_pointer_cast<PKCS12Certificate>(certificate); if (!pkcs12Certificate || pkcs12Certificate->isNull()) { return false; } // Create a PKCS12 structure BIO* bio = BIO_new(BIO_s_mem()); BIO_write(bio, vecptr(pkcs12Certificate->getData()), pkcs12Certificate->getData().size()); boost::shared_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(bio, NULL), PKCS12_free); BIO_free(bio); if (!pkcs12) { return false; } // Parse PKCS12 X509 *certPtr = 0; EVP_PKEY* privateKeyPtr = 0; STACK_OF(X509)* caCertsPtr = 0; int result = PKCS12_parse(pkcs12.get(), reinterpret_cast<const char*>(vecptr(pkcs12Certificate->getPassword())), &privateKeyPtr, &certPtr, &caCertsPtr); if (result != 1) { return false; } boost::shared_ptr<X509> cert(certPtr, X509_free); boost::shared_ptr<EVP_PKEY> privateKey(privateKeyPtr, EVP_PKEY_free); boost::shared_ptr<STACK_OF(X509)> caCerts(caCertsPtr, freeX509Stack); // Use the key & certificates if (SSL_CTX_use_certificate(context_, cert.get()) != 1) { return false; } if (SSL_CTX_use_PrivateKey(context_, privateKey.get()) != 1) { return false; } for (int i = 0; i < sk_X509_num(caCerts.get()); ++i) { SSL_CTX_add_extra_chain_cert(context_, sk_X509_value(caCerts.get(), i)); } return true; }
void CertificateFileStorage::addCertificate(Certificate::ref certificate) { boost::filesystem::path certificatePath = getCertificatePath(certificate); if (!boost::filesystem::exists(certificatePath.parent_path())) { try { boost::filesystem::create_directories(certificatePath.parent_path()); } catch (const boost::filesystem::filesystem_error& e) { std::cerr << "ERROR: " << e.what() << std::endl; } } boost::filesystem::ofstream file(certificatePath, boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out); ByteArray data = certificate->toDER(); file.write(reinterpret_cast<const char*>(vecptr(data)), boost::numeric_cast<std::streamsize>(data.size())); file.close(); }
std::vector<NetworkInterface> WindowsNetworkEnvironment::getNetworkInterfaces() const { std::vector<NetworkInterface> result; ByteArray adapters; ULONG bufferSize = 0; ULONG ret; ULONG flags = GAA_FLAG_INCLUDE_ALL_INTERFACES | GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; while ((ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, reinterpret_cast<IP_ADAPTER_ADDRESSES*>(vecptr(adapters)), &bufferSize)) == ERROR_BUFFER_OVERFLOW) { adapters.resize(bufferSize); }; if (ret != ERROR_SUCCESS) { return result; } std::map<std::string,NetworkInterface> interfaces; for (IP_ADAPTER_ADDRESSES* adapter = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(vecptr(adapters)); adapter; adapter = adapter->Next) { std::string name(adapter->AdapterName); if (adapter->OperStatus != IfOperStatusUp) { continue; } for (IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress; address; address = address->Next) { boost::optional<HostAddress> hostAddress; if (address->Address.lpSockaddr->sa_family == PF_INET) { sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(address->Address.lpSockaddr); hostAddress = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin_addr)), 4); } else if (address->Address.lpSockaddr->sa_family == PF_INET6) { sockaddr_in6* sa = reinterpret_cast<sockaddr_in6*>(address->Address.lpSockaddr); hostAddress = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin6_addr)), 16); } if (hostAddress) { std::map<std::string, NetworkInterface>::iterator i = interfaces.insert(std::make_pair(name, NetworkInterface(name, false))).first; i->second.addAddress(*hostAddress); } } } for (std::map<std::string,NetworkInterface>::const_iterator i = interfaces.begin(); i != interfaces.end(); ++i) { result.push_back(i->second); } return result; }
PCCERT_CONTEXT findCertificateInStore (HCERTSTORE certStoreHandle, const std::string &certName) { if (!boost::iequals(certName.substr(0, 5), "sha1:")) { // Find client certificate. Note that this sample just searches for a // certificate that contains the user name somewhere in the subject name. return CertFindCertificateInStore(certStoreHandle, X509_ASN_ENCODING, /*dwFindFlags*/ 0, CERT_FIND_SUBJECT_STR_A, /* *pvFindPara*/certName.c_str(), /*pPrevCertContext*/ NULL); } std::string hexstring = certName.substr(5); ByteArray byteArray = Hexify::unhexify(hexstring); CRYPT_HASH_BLOB HashBlob; if (byteArray.size() != SHA1_HASH_LEN) { return NULL; } HashBlob.cbData = SHA1_HASH_LEN; HashBlob.pbData = static_cast<BYTE *>(vecptr(byteArray)); // Find client certificate. Note that this sample just searches for a // certificate that contains the user name somewhere in the subject name. return CertFindCertificateInStore(certStoreHandle, X509_ASN_ENCODING, /* dwFindFlags */ 0, CERT_FIND_HASH, &HashBlob, /* pPrevCertContext */ NULL); }
boost::filesystem::path Paths::getExecutablePath() { #if defined(SWIFTEN_PLATFORM_MACOSX) ByteArray path; uint32_t size = 4096; path.resize(size); if (_NSGetExecutablePath(const_cast<char*>(reinterpret_cast<const char*>(vecptr(path))), &size) == 0) { return boost::filesystem::path(std::string(reinterpret_cast<const char*>(vecptr(path)), path.size()).c_str()).parent_path(); } #elif defined(SWIFTEN_PLATFORM_LINUX) ByteArray path; path.resize(4096); ssize_t size = readlink("/proc/self/exe", reinterpret_cast<char*>(vecptr(path)), path.size()); if (size > 0) { path.resize(size); return boost::filesystem::path(std::string(reinterpret_cast<const char*>(vecptr(path)), path.size()).c_str()).parent_path(); } #elif defined(SWIFTEN_PLATFORM_WINDOWS) ByteArray data; data.resize(2048); GetModuleFileName(NULL, reinterpret_cast<char*>(vecptr(data)), data.size()); return boost::filesystem::path(std::string(reinterpret_cast<const char*>(vecptr(data)), data.size()).c_str()).parent_path(); #endif return boost::filesystem::path(); }
bool WindowsGSSAPIClientAuthenticator::setChallenge(const boost::optional<ByteArray>& challengeData) { /* Following http://tools.ietf.org/html/rfc4752, https://msdn.microsoft.com/en-us/library/windows/desktop/aa380496%28v=vs.85%29.aspx */ if (step_ == BuildingSecurityContext) { buildSecurityContext(challengeData); } else if (step_ == SecurityLayerNegotiation) { if (!challengeData) { SWIFT_LOG(debug) << "Empty message received from the server" << std::endl; error_ = true; return false; } SafeByteArray challenge; errorCode_ = decryptMessage(&contextHandle_, challengeData.get(), challenge); if (isError()) { return false; } if (challenge.size() != 4) { SWIFT_LOG(debug) << "Token received from the server of incorrect length: " << challenge.size() << std::endl; error_ = true; return false; } unsigned char* challengePointer = vecptr(challenge); unsigned char serverSecurityLayer = challengePointer[0]; if (serverSecurityLayer == 0) { SWIFT_LOG(debug) << "Server supports unknown security layer, assuming no security layer" << std::endl; serverSecurityLayer = SECURITY_LAYER_NONE; } else if (serverSecurityLayer == SECURITY_LAYER_NONE) { SWIFT_LOG(debug) << "Server supports no security layer" << std::endl; } else { SWIFT_LOG(debug) << "Server supports security layer" << std::endl; } unsigned int serverMaximumBuffer = (challengePointer[1] << 16) | (challengePointer[2] << 8) | (challengePointer[3] << 0); if ((serverSecurityLayer == SECURITY_LAYER_NONE) && (serverMaximumBuffer != 0)) { SWIFT_LOG(debug) << "Server supports no security layer but has maximum buffer size" << serverMaximumBuffer << std::endl; error_ = true; return false; } SafeByteArray message(4); /* Commenting this out as streamSizes was not obtained before if (message.size() > streamSizes_.cbMaximumMessage) { error_ = true; return false; } */ unsigned char* messagePointer = vecptr(message); messagePointer[0] = SECURITY_LAYER_NONE; /* The next 3 bytes indicate the client's maximum size buffer which is set to 0 as we do not support a security layer */ messagePointer[1] = 0; messagePointer[2] = 0; messagePointer[3] = 0; /* The authorization identity is omitted as it is the same as the authentication identity */ errorCode_ = encryptMessage(&contextHandle_, sizes_, message, response_); if (isError()) { return false; } step_ = ServerAuthenticated; } if (isError()) { return false; } return true; }
std::vector<unsigned char> MD5::getHash() { ByteArray digest; digest.resize(16); md5_finish(state, reinterpret_cast<md5_byte_t*>(vecptr(digest))); return digest; }
MD5& MD5::update(const std::vector<unsigned char>& input) { md5_append(state, reinterpret_cast<const md5_byte_t*>(vecptr(input)), input.size()); return *this; }
void SOCKS5BytestreamClientSession::process() { SWIFT_LOG(debug) << "unprocessedData.size(): " << unprocessedData.size() << std::endl; ByteArray bndAddress; switch(state) { case Initial: hello(); break; case Hello: if (unprocessedData.size() > 1) { unsigned char version = unprocessedData[0]; unsigned char authMethod = unprocessedData[1]; if (version != 5 || authMethod != 0) { // signal failure to upper level finish(true); return; } unprocessedData.clear(); authenticate(); } break; case Authenticating: if (unprocessedData.size() < 5) { // need more data to start progressing break; } if (unprocessedData[0] != '\x05') { // wrong version // disconnect & signal failure finish(true); break; } if (unprocessedData[1] != '\x00') { // no success // disconnect & signal failure finish(true); break; } if (unprocessedData[3] != '\x03') { // we expect x'03' = DOMAINNAME here // discconect & signal failure finish(true); break; } if (static_cast<size_t>(unprocessedData[4]) + 1 > unprocessedData.size() + 5) { // complete domainname and port not available yet break; } bndAddress = createByteArray(&vecptr(unprocessedData)[5], unprocessedData[4]); if (unprocessedData[unprocessedData[4] + 5] != 0 && bndAddress == createByteArray(destination)) { // we expect a 0 as port // disconnect and fail finish(true); } unprocessedData.clear(); state = Ready; SWIFT_LOG(debug) << "session ready" << std::endl; // issue ready signal so the bytestream can be used for reading or writing weFailedTimeout->stop(); onSessionReady(false); break; case Ready: SWIFT_LOG(debug) << "Received further data in Ready state." << std::endl; break; case Reading: case Writing: case Finished: SWIFT_LOG(debug) << "Unexpected receive of data. Current state: " << state << std::endl; SWIFT_LOG(debug) << "Data: " << Hexify::hexify(unprocessedData) << std::endl; unprocessedData.clear(); //assert(false); } }
void PlatformDomainNameServiceQuery::runBlocking() { if (!serviceValid) { emitError(); return; } SWIFT_LOG(debug) << "Querying " << service << std::endl; std::vector<DomainNameServiceQuery::Result> records; #if defined(SWIFTEN_PLATFORM_WINDOWS) DNS_RECORD* responses; // FIXME: This conversion doesn't work if unicode is deffed above if (DnsQuery(service.c_str(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &responses, NULL) != ERROR_SUCCESS) { emitError(); return; } DNS_RECORD* currentEntry = responses; while (currentEntry) { if (currentEntry->wType == DNS_TYPE_SRV) { DomainNameServiceQuery::Result record; record.priority = currentEntry->Data.SRV.wPriority; record.weight = currentEntry->Data.SRV.wWeight; record.port = currentEntry->Data.SRV.wPort; // The pNameTarget is actually a PCWSTR, so I would have expected this // conversion to not work at all, but it does. // Actually, it doesn't. Fix this and remove explicit cast // Remove unicode undef above as well record.hostname = std::string((const char*) currentEntry->Data.SRV.pNameTarget); records.push_back(record); } currentEntry = currentEntry->pNext; } DnsRecordListFree(responses, DnsFreeRecordList); #else // Make sure we reinitialize the domain list every time res_init(); ByteArray response; response.resize(NS_PACKETSZ); int responseLength = res_query(const_cast<char*>(service.c_str()), ns_c_in, ns_t_srv, reinterpret_cast<u_char*>(vecptr(response)), response.size()); if (responseLength == -1) { SWIFT_LOG(debug) << "Error" << std::endl; emitError(); return; } // Parse header HEADER* header = reinterpret_cast<HEADER*>(vecptr(response)); unsigned char* messageStart = vecptr(response); unsigned char* messageEnd = messageStart + responseLength; unsigned char* currentEntry = messageStart + NS_HFIXEDSZ; // Skip over the queries int queriesCount = ntohs(header->qdcount); while (queriesCount > 0) { int entryLength = dn_skipname(currentEntry, messageEnd); if (entryLength < 0) { emitError(); return; } currentEntry += entryLength + NS_QFIXEDSZ; queriesCount--; } // Process the SRV answers int answersCount = ntohs(header->ancount); while (answersCount > 0) { DomainNameServiceQuery::Result record; int entryLength = dn_skipname(currentEntry, messageEnd); currentEntry += entryLength; currentEntry += NS_RRFIXEDSZ; // Priority if (currentEntry + 2 >= messageEnd) { emitError(); return; } record.priority = boost::numeric_cast<int>(ns_get16(currentEntry)); currentEntry += 2; // Weight if (currentEntry + 2 >= messageEnd) { emitError(); return; } record.weight = boost::numeric_cast<int>(ns_get16(currentEntry)); currentEntry += 2; // Port if (currentEntry + 2 >= messageEnd) { emitError(); return; } record.port = boost::numeric_cast<int>(ns_get16(currentEntry)); currentEntry += 2; // Hostname if (currentEntry >= messageEnd) { emitError(); return; } ByteArray entry; entry.resize(NS_MAXDNAME); entryLength = dn_expand(messageStart, messageEnd, currentEntry, reinterpret_cast<char*>(vecptr(entry)), entry.size()); if (entryLength < 0) { emitError(); return; } record.hostname = std::string(reinterpret_cast<const char*>(vecptr(entry))); records.push_back(record); currentEntry += entryLength; answersCount--; } #endif BoostRandomGenerator generator; DomainNameServiceQuery::sortResults(records, generator); //std::cout << "Sending out " << records.size() << " SRV results " << std::endl; eventLoop->postEvent(boost::bind(boost::ref(onResult), records), shared_from_this()); }
BOSHBodyExtractor::BOSHBodyExtractor(XMLParserFactory* parserFactory, const ByteArray& data) { // Look for the opening body element ByteArray::const_iterator i = data.begin(); while (i < data.end() && isWhitespace(*i)) { ++i; } if (std::distance(i, data.end()) < 6 || *i != '<' || *(i+1) != 'b' || *(i+2) != 'o' || *(i+3) != 'd' || *(i+4) != 'y' || !(isWhitespace(*(i+5)) || *(i+5) == '>' || *(i+5) == '/')) { return; } i += 5; // Parse until end of element bool inSingleQuote = false; bool inDoubleQuote = false; bool endStartTagSeen = false; bool endElementSeen = false; for (; i != data.end(); ++i) { char c = static_cast<char>(*i); if (inSingleQuote) { if (c == '\'') { inSingleQuote = false; } } else if (inDoubleQuote) { if (c == '"') { inDoubleQuote = false; } } else if (c == '\'') { inSingleQuote = true; } else if (c == '"') { inDoubleQuote = true; } else if (c == '/') { if (i + 1 == data.end() || *(i+1) != '>') { return; } else { endElementSeen = true; endStartTagSeen = true; i += 2; break; } } else if (c == '>') { endStartTagSeen = true; i += 1; break; } } if (!endStartTagSeen) { return; } // Look for the end of the element ByteArray::const_reverse_iterator j = data.rbegin(); if (!endElementSeen) { while (isWhitespace(*j) && j < data.rend()) { ++j; } if (j == data.rend() || *j != '>') { return; } ++j; while (j < data.rend() && isWhitespace(*j)) { ++j; } if (std::distance(j, data.rend()) < 6 || *(j+5) != '<' || *(j+4) != '/' || *(j+3) != 'b' || *(j+2) != 'o' || *(j+1) != 'd' || *j != 'y') { return; } j += 6; } body = BOSHBody(); if (!endElementSeen) { body->content = std::string( reinterpret_cast<const char*>(vecptr(data) + std::distance(data.begin(), i)), boost::numeric_cast<size_t>(std::distance(i, j.base()))); } // Parse the body element BOSHBodyParserClient parserClient(this); std::shared_ptr<XMLParser> parser(parserFactory->createXMLParser(&parserClient)); if (!parser->parse(std::string( reinterpret_cast<const char*>(vecptr(data)), boost::numeric_cast<size_t>(std::distance(data.begin(), i))))) { /* TODO: This needs to be only validating the BOSH <body> element, so that XMPP parsing errors are caught at the correct higher layer */ body = boost::optional<BOSHBody>(); return; } }