void Client::on(Connected) noexcept { updateActivity(); { #ifdef FLYLINKDC_USE_CS_CLIENT_SOCKET FastLock lock(csSock); // [+] brain-ripper #endif boost::system::error_code ec; m_ip = boost::asio::ip::address_v4::from_string(m_client_sock->getIp(), ec); dcassert(!ec); } if (m_client_sock->isSecure() && m_keyprint.compare(0, 7, "SHA256/", 7) == 0) { const auto kp = m_client_sock->getKeyprint(); if (!kp.empty()) { vector<uint8_t> kp2v(kp.size()); Encoder::fromBase32(m_keyprint.c_str() + 7, &kp2v[0], kp2v.size()); if (!std::equal(kp.begin(), kp.end(), kp2v.begin())) { state = STATE_DISCONNECTED; m_client_sock->removeListener(this); fire(ClientListener::Failed(), this, "Keyprint mismatch"); return; } } } #ifdef IRAINMAN_ENABLE_CON_STATUS_ON_FAV_HUBS FavoriteManager::getInstance()->changeConnectionStatus(getHubUrl(), ConnectionStatus::SUCCES); #endif fire(ClientListener::Connected(), this); state = STATE_PROTOCOL; }
void Client::on(Connected) throw() { updateActivity(); ip = sock->getIp(); localIp = sock->getLocalIp(); if(sock->isSecure() && keyprint.compare(0, 7, "SHA256/") == 0) { vector<uint8_t> kp = sock->getKeyprint(); if(!kp.empty()) { vector<uint8_t> kp2v(kp.size()); Encoder::fromBase32(keyprint.c_str() + 7, &kp2v[0], kp2v.size()); if(!std::equal(kp.begin(), kp.end(), kp2v.begin())) { state = STATE_DISCONNECTED; sock->removeListener(this); fire(ClientListener::Failed(), this, "Keyprint mismatch"); return; } } } fire(ClientListener::Connected(), this); state = STATE_PROTOCOL; }
int CryptoManager::verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { int err = X509_STORE_CTX_get_error(ctx); SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); SSLVerifyData* verifyData = (SSLVerifyData*)SSL_get_ex_data(ssl, CryptoManager::idxVerifyData); // TODO: we should make sure that the trusted certificate store never overules KeyPrint, if present, because certificate pinning on an individual certificate is a stronger method of verification. // verifyData is unset only when KeyPrint has been pinned and we are not skipping errors due to incomplete chains // we can fail here f.ex. if the certificate has expired but is still pinned with KeyPrint if (!verifyData) return preverify_ok; bool allowUntrusted = verifyData->first; string keyp = verifyData->second; if (!keyp.empty()) { X509* cert = X509_STORE_CTX_get_current_cert(ctx); if (!cert) return 0; string kp2(keyp); if (kp2.compare(0, 12, "trusted_keyp") == 0) { // Possible follow up errors, after verification of a partial chain if (err == X509_V_ERR_CERT_UNTRUSTED || err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) { X509_STORE_CTX_set_error(ctx, X509_V_OK); return 1; } } else if (kp2.compare(0, 7, "SHA256/") != 0) return allowUntrusted ? 1 : 0; ByteVector kp = ssl::X509_digest(cert, EVP_sha256()); ByteVector kp2v(kp.size()); Encoder::fromBase32(&kp2[7], &kp2v[0], kp2v.size()); if (std::equal(kp.begin(), kp.end(), kp2v.begin())) { // KeyPrint validated, we can get rid of it (to avoid unnecessary passes) SSL_set_ex_data(ssl, CryptoManager::idxVerifyData, NULL); if (err != X509_V_OK) { // This is the right way to get the certificate store, although it is rather roundabout X509_STORE* store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(ssl)); dcassert(store == ctx->ctx); // Hide the potential library error about trying to add a dupe ERR_set_mark(); if (X509_STORE_add_cert(store, cert)) { X509_STORE_CTX_set_error(ctx, X509_V_OK); X509_verify_cert(ctx); err = X509_STORE_CTX_get_error(ctx); } else ERR_pop_to_mark(); // KeyPrint was not root certificate or we don't have the issuer certificate, the best we can do is trust the pinned KeyPrint if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN || err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY || err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) { X509_STORE_CTX_set_error(ctx, X509_V_OK); // Set this to allow ignoring any follow up errors caused by the incomplete chain SSL_set_ex_data(ssl, CryptoManager::idxVerifyData, &CryptoManager::trustedKeyprint); return 1; } } return (err == X509_V_OK) ? 1 : 0; } else { if (X509_STORE_CTX_get_error_depth(ctx) > 0) return 1; } } if (allowUntrusted) { /* // We let untrusted certificates through unconditionally, when allowed, but we like to complain if (!preverify_ok && err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) { X509* cert = NULL; if ((cert = X509_STORE_CTX_get_current_cert(ctx)) != NULL) { X509_NAME* subject = X509_get_subject_name(cert); string tmp, line; tmp = getNameEntryByNID(subject, NID_commonName); if (!tmp.empty()) { CID certCID(tmp); if (certCID) tmp = Util::listToString(ClientManager::getInstance()->getNicks(certCID)); line += (!line.empty() ? ", " : "") + tmp; } tmp = getNameEntryByNID(subject, NID_organizationName); if (!tmp.empty()) line += (!line.empty() ? ", " : "") + tmp; ByteVector kp = ssl::X509_digest(cert, EVP_sha256()); string keyp = "SHA256/" + Encoder::toBase32(&kp[0], kp.size()); LogManager::getInstance()->message(STRING_F(VERIFY_CERT_FAILED, line % X509_verify_cert_error_string(err) % keyp), LogManager::LOG_INFO); } }*/ return 1; } return preverify_ok; }