//! Save the fact that the user has manually accepted a certificate. void PersistAcceptanceForCertificate(ConfirmationDialogData *confinfo) { unsigned char tmphash[SHA_DIGEST_LENGTH]; if (X509_pubkey_digest(confinfo->err_cert, EVP_sha1(), tmphash, NULL) != 0) { std::string hexhash = bin2hex(tmphash, SHA_DIGEST_LENGTH); std::string regpath = std::string(REGKEYBASE "\\AllowedCerts\\").append(hexhash); HKEY hkeyAllowed; if (RegCreateKeyEx(HKEY_CURRENT_USER, regpath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ, NULL, &hkeyAllowed, NULL) == ERROR_SUCCESS) { DOUT(("stundlg: Saving acceptance for persisted certificate.\n")); char buf[256]; X509_NAME_oneline(X509_get_subject_name(confinfo->err_cert), buf, sizeof(buf)); RegSetValueEx(hkeyAllowed, "SubjectName", 0, REG_SZ, reinterpret_cast<const BYTE*>(buf), static_cast<DWORD>(strlen(buf) + 1)); RegCloseKey(hkeyAllowed); } } }
static int tls_keypair_pubkey_hash(struct tls_keypair *keypair, char **hash) { BIO *membio = NULL; X509 *cert = NULL; char d[EVP_MAX_MD_SIZE], *dhex = NULL; int dlen, rv = -1; *hash = NULL; if ((membio = BIO_new_mem_buf(keypair->cert_mem, keypair->cert_len)) == NULL) goto err; if ((cert = PEM_read_bio_X509_AUX(membio, NULL, tls_password_cb, NULL)) == NULL) goto err; if (X509_pubkey_digest(cert, EVP_sha256(), d, &dlen) != 1) goto err; if (tls_hex_string(d, dlen, &dhex, NULL) != 0) goto err; if (asprintf(hash, "SHA256:%s", dhex) == -1) { *hash = NULL; goto err; } rv = 0; err: free(dhex); X509_free(cert); BIO_free(membio); return (rv); }
/*! * \param confinfo Pointer to structure containing identity of certificate. * \return Returns true if the connection should be allowed without prompting. * Otherwise the user should be asked whether to allow it. * * \sa ConfirmCertificateDialog */ bool CheckAllowCertificate(ConfirmationDialogData *confinfo) { DOUT(("stundlg: CheckAllowCertificate called\n")); // OpenSSL will sometimes call the certificate verification routine // multiple times when establishing a connection, but we should not // prompt the user to confirm the same connection multiple times. if (confinfo->stunnel->bCertificateAccepted) { DOUT(("stundlg: Returning acceptance since this stunnel object has already been authorized.\n")); return true; } #if 0 // If you trust OpenSSL's pre-verification step, then accept it. if (confinfo->preverify_ok) { DOUT(("stundlg: Returning acceptance since certificate preverification was ok.\n")); return true; } #endif #if 1 // Check the registry setting that forces us to accept all certificates. // This is a pretty insecure mode since it allows anything. do { HKEY hkeySettings; if (RegCreateKeyEx(HKEY_CURRENT_USER, REGKEYBASE, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ, NULL, &hkeySettings, NULL) != ERROR_SUCCESS) { break; } DWORD dwType; char buffer[512]; DWORD dwBufferSize = sizeof(buffer); bool AlwaysAllowAnyCert = false; if (RegQueryValueEx(hkeySettings, "AlwaysAllowAnyCert", NULL, &dwType, (LPBYTE) buffer, &dwBufferSize) == ERROR_SUCCESS && (dwType == REG_DWORD)) { AlwaysAllowAnyCert = (*reinterpret_cast<DWORD*>(buffer) != 0); } else { *reinterpret_cast<DWORD*>(buffer) = (AlwaysAllowAnyCert ? 1 : 0); RegSetValueEx(hkeySettings, "AlwaysAllowAnyCert", 0, REG_DWORD, reinterpret_cast<const BYTE *>(buffer), sizeof(DWORD) ); } RegCloseKey(hkeySettings); if (AlwaysAllowAnyCert) { DOUT(("stundlg: Returning acceptance since the AlwaysAllowAnyCert mode is enabled.\n")); return true; } } while (0); #endif // Check the registry to see if the user has explicitly accepted this // certificate in the past. unsigned char tmphash[SHA_DIGEST_LENGTH]; if (X509_pubkey_digest(confinfo->err_cert, EVP_sha1(), tmphash, NULL) != 0) { std::string hexhash = bin2hex(tmphash, SHA_DIGEST_LENGTH); std::string regpath = std::string(REGKEYBASE "\\AllowedCerts\\").append(hexhash); HKEY hkeyAllowed; if (RegOpenKeyEx(HKEY_CURRENT_USER, regpath.c_str(), 0, KEY_READ, &hkeyAllowed) == ERROR_SUCCESS) { DOUT(("stundlg: Returning acceptance for persisted certificate.\n")); RegCloseKey(hkeyAllowed); return true; } } return false; // don't know, so prompt the user about what to do. }