QSsl::KeyType QSslKeyProto::type() const { QSslKey *item = qscriptvalue_cast<QSslKey*>(thisObject()); if (item) return item->type(); return QSsl::KeyType(); }
bool Server::isKeyForCert(const QSslKey &key, const QSslCertificate &cert) { if (key.isNull() || cert.isNull() || (key.type() != QSsl::PrivateKey)) return false; QByteArray qbaKey = key.toDer(); QByteArray qbaCert = cert.toDer(); X509 *x509 = NULL; EVP_PKEY *pkey = NULL; BIO *mem = NULL; mem = BIO_new_mem_buf(qbaKey.data(), qbaKey.size()); Q_UNUSED(BIO_set_close(mem, BIO_NOCLOSE)); pkey = d2i_PrivateKey_bio(mem, NULL); BIO_free(mem); mem = BIO_new_mem_buf(qbaCert.data(), qbaCert.size()); Q_UNUSED(BIO_set_close(mem, BIO_NOCLOSE)); x509 = d2i_X509_bio(mem, NULL); BIO_free(mem); mem = NULL; if (x509 && pkey && X509_check_private_key(x509, pkey)) { EVP_PKEY_free(pkey); X509_free(x509); return true; } if (pkey) EVP_PKEY_free(pkey); if (x509) X509_free(x509); return false; }
int QSslKeyProto::length() const { QSslKey *item = qscriptvalue_cast<QSslKey*>(thisObject()); if (item) return item->length(); return 0; }
QByteArray QSslKeyProto::toPem(const QByteArray & passPhrase) const { QSslKey *item = qscriptvalue_cast<QSslKey*>(thisObject()); if (item) return item->toPem(passPhrase); return QByteArray(); }
bool QSslKeyProto::isNull() const { QSslKey *item = qscriptvalue_cast<QSslKey*>(thisObject()); if (item) return item->isNull(); return false; }
QSsl::KeyAlgorithm QSslKeyProto::algorithm() const { QSslKey *item = qscriptvalue_cast<QSslKey*>(thisObject()); if (item) return item->algorithm(); return QSsl::KeyAlgorithm(); }
Settings::KeyPair CertWizard::importCert(QByteArray data, const QString &pw) { X509 *x509 = NULL; EVP_PKEY *pkey = NULL; PKCS12 *pkcs = NULL; BIO *mem = NULL; STACK_OF(X509) *certs = NULL; Settings::KeyPair kp; int ret = 0; mem = BIO_new_mem_buf(data.data(), data.size()); Q_UNUSED(BIO_set_close(mem, BIO_NOCLOSE)); pkcs = d2i_PKCS12_bio(mem, NULL); if (pkcs) { ret = PKCS12_parse(pkcs, NULL, &pkey, &x509, &certs); if (pkcs && !pkey && !x509 && ! pw.isEmpty()) { if (certs) { if (ret) sk_X509_free(certs); certs = NULL; } ret = PKCS12_parse(pkcs, pw.toUtf8().constData(), &pkey, &x509, &certs); } if (pkey && x509 && X509_check_private_key(x509, pkey)) { unsigned char *dptr; QByteArray key, crt; key.resize(i2d_PrivateKey(pkey, NULL)); dptr=reinterpret_cast<unsigned char *>(key.data()); i2d_PrivateKey(pkey, &dptr); crt.resize(i2d_X509(x509, NULL)); dptr=reinterpret_cast<unsigned char *>(crt.data()); i2d_X509(x509, &dptr); QSslCertificate qscCert = QSslCertificate(crt, QSsl::Der); QSslKey qskKey = QSslKey(key, QSsl::Rsa, QSsl::Der); QList<QSslCertificate> qlCerts; qlCerts << qscCert; if (certs) { for (int i=0;i<sk_X509_num(certs);++i) { X509 *c = sk_X509_value(certs, i); crt.resize(i2d_X509(c, NULL)); dptr=reinterpret_cast<unsigned char *>(crt.data()); i2d_X509(c, &dptr); QSslCertificate cert = QSslCertificate(crt, QSsl::Der); qlCerts << cert; } } bool valid = ! qskKey.isNull(); foreach(const QSslCertificate &cert, qlCerts) valid = valid && ! cert.isNull(); if (valid) kp = Settings::KeyPair(qlCerts, qskKey); } }
void QgsPkiBundle::setClientKey( const QSslKey &certkey ) { mCertKey.clear(); if ( !certkey.isNull() && certkey.type() == QSsl::PrivateKey ) { mCertKey = certkey; } }
QDebug operator<<(QDebug debug, const QSslKey &key) { debug << "QSslKey(" << (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey") << ", " << (key.algorithm() == QSsl::Rsa ? "RSA" : "DSA") << ", " << key.length() << ")"; return debug; }
int CertificateDialogPrivate::keyLenght( const QSslKey &key ) const { switch( key.algorithm() ) { case QSsl::Dsa: return DSA_size( (DSA*)key.handle() ) * 8; case QSsl::Rsa: return RSA_size( (RSA*)key.handle() ) * 8; } return key.length(); }
QSslKey Server::privateKeyFromPEM(const QByteArray &buf, const QByteArray &pass) { QSslKey key; key = QSslKey(buf, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, pass); if (key.isNull()) key = QSslKey(buf, QSsl::Dsa, QSsl::Pem, QSsl::PrivateKey, pass); #if QT_VERSION >= 0x050500 if (key.isNull()) key = QSslKey(buf, QSsl::Ec, QSsl::Pem, QSsl::PrivateKey, pass); #endif return key; }
QDebug operator<<(QDebug debug, const QSslKey &key) { QDebugStateSaver saver(debug); debug.resetFormat().nospace(); debug << "QSslKey(" << (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey") << ", " << (key.algorithm() == QSsl::Opaque ? "OPAQUE" : (key.algorithm() == QSsl::Rsa ? "RSA" : ((key.algorithm() == QSsl::Dsa) ? "DSA" : "EC"))) << ", " << key.length() << ')'; return debug; }
void CertIdentity::setSslKey(const QSslKey &key) { if (key.toPem() == _sslKey.toPem()) return; _sslKey = key; _isDirty = true; }
const QgsPkiBundle QgsPkiBundle::fromPemPaths( const QString &certPath, const QString &keyPath, const QString &keyPass, const QList<QSslCertificate> &caChain ) { QgsPkiBundle pkibundle; if ( !certPath.isEmpty() && !keyPath.isEmpty() && ( certPath.endsWith( QLatin1String( ".pem" ), Qt::CaseInsensitive ) || certPath.endsWith( QLatin1String( ".der" ), Qt::CaseInsensitive ) ) && ( keyPath.endsWith( QLatin1String( ".pem" ), Qt::CaseInsensitive ) || keyPath.endsWith( QLatin1String( ".der" ), Qt::CaseInsensitive ) ) && QFile::exists( certPath ) && QFile::exists( keyPath ) ) { // client cert bool pem = certPath.endsWith( QLatin1String( ".pem" ), Qt::CaseInsensitive ); QSslCertificate clientcert( fileData_( certPath, pem ), pem ? QSsl::Pem : QSsl::Der ); pkibundle.setClientCert( clientcert ); // client key bool pem_key = keyPath.endsWith( QLatin1String( ".pem" ), Qt::CaseInsensitive ); QByteArray keydata( fileData_( keyPath, pem_key ) ); QSslKey clientkey; clientkey = QSslKey( keydata, QSsl::Rsa, pem_key ? QSsl::Pem : QSsl::Der, QSsl::PrivateKey, !keyPass.isNull() ? keyPass.toUtf8() : QByteArray() ); if ( clientkey.isNull() ) { // try DSA algorithm, since Qt can't seem to determine it otherwise clientkey = QSslKey( keydata, QSsl::Dsa, pem_key ? QSsl::Pem : QSsl::Der, QSsl::PrivateKey, !keyPass.isNull() ? keyPass.toUtf8() : QByteArray() ); } pkibundle.setClientKey( clientkey ); if ( !caChain.isEmpty() ) { pkibundle.setCaChain( caChain ); } } return pkibundle; }
void KeyShare::CheckPath() { QDir key_path(_path, "*.pub"); foreach(const QString &key_name, key_path.entryList()) { QString path = _path + "/" + key_name; QFile key_file(path); key_file.open(QIODevice::ReadOnly); QSharedPointer<QSslCertificate> cert(new QSslCertificate(&key_file, QSsl::Der)); QSslKey pubkey = cert->publicKey(); QSharedPointer<AsymmetricKey> key(new DsaPublicKey(pubkey.toDer())); if(!key->IsValid()) { qDebug() << "Invalid key:" << path; continue; } QString name = key_name.left(key_name.length() - 4); AddCertificate(name, cert); } }
QSslKey IdentityEditWidget::keyByFilename(const QString &filename) { QSslKey key; QFile keyFile(filename); keyFile.open(QIODevice::ReadOnly); QByteArray keyRaw = keyFile.read(2 << 20); keyFile.close(); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { key = QSslKey(keyRaw, (QSsl::KeyAlgorithm)j, (QSsl::EncodingFormat)i); if (!key.isNull()) goto returnKey; } } QMessageBox::information(this, tr("Failed to read key"), tr("Failed to read the key file. It is either incompatible or invalid. Note that the key file must not have a passphrase.")); returnKey: return key; }
void IdentityEditWidget::showKeyState(const QSslKey &key) { if (key.isNull()) { ui.keyTypeLabel->setText(tr("No Key loaded")); ui.clearOrLoadKeyButton->setText(tr("Load")); } else { switch (key.algorithm()) { case QSsl::Rsa: ui.keyTypeLabel->setText(tr("RSA")); break; case QSsl::Dsa: ui.keyTypeLabel->setText(tr("DSA")); break; default: ui.keyTypeLabel->setText(tr("No Key loaded")); } ui.clearOrLoadKeyButton->setText(tr("Clear")); } ui.keyTypeLabel->setProperty("sslKey", key.toPem()); ui.keyTypeLabel->setProperty("sslKeyType", (int)key.algorithm()); }
// static const QByteArray QgsAuthProviderPkiPaths::keyAsPem( const QString &keypath, const QString &keypass, QString *algtype, bool reencrypt ) { bool pem = keypath.endsWith( ".pem", Qt::CaseInsensitive ); QByteArray keydata( fileData_( keypath, pem ) ); QSslKey clientkey; clientkey = QSslKey( keydata, QSsl::Rsa, pem ? QSsl::Pem : QSsl::Der, QSsl::PrivateKey, !keypass.isEmpty() ? keypass.toUtf8() : QByteArray() ); if ( clientkey.isNull() ) { // try DSA algorithm, since Qt can't seem to determine it otherwise clientkey = QSslKey( keydata, QSsl::Dsa, pem ? QSsl::Pem : QSsl::Der, QSsl::PrivateKey, !keypass.isEmpty() ? keypass.toUtf8() : QByteArray() ); if ( clientkey.isNull() ) { return QByteArray(); } if ( algtype ) *algtype = "dsa"; } else { if ( algtype ) *algtype = "rsa"; } // reapply passphrase if protection is requested and passphrase exists return ( clientkey.toPem( reencrypt && !keypass.isEmpty() ? keypass.toUtf8() : QByteArray() ) ); }
void IdentityEditWidget::sslDropEvent(QDropEvent *event, bool isCert) { QByteArray rawUris; if (event->mimeData()->hasFormat("text/uri-list")) rawUris = event->mimeData()->data("text/uri-list"); else rawUris = event->mimeData()->data("text/uri"); QTextStream uriStream(rawUris); QString filename = QUrl(uriStream.readLine()).toLocalFile(); if (isCert) { QSslCertificate cert = certByFilename(filename); if (!cert.isNull()) showCertState(cert); } else { QSslKey key = keyByFilename(filename); if (!key.isNull()) showKeyState(key); } event->accept(); emit widgetHasChanged(); }
/*! Returns \c true if this key is equal to \a other; otherwise returns \c false. */ bool QSslKey::operator==(const QSslKey &other) const { if (isNull()) return other.isNull(); if (other.isNull()) return isNull(); if (algorithm() != other.algorithm()) return false; if (type() != other.type()) return false; if (length() != other.length()) return false; if (algorithm() == QSsl::Opaque) return handle() == other.handle(); return toDer() == other.toDer(); }
void PlaydarApi::start() { Q_D( PlaydarApi ); if ( !d->session.isNull() ) { tLog() << "HTTPd session already exists, returning"; return; } d->session.reset( new QxtHttpSessionManager() ); d->connector.reset( new QxtHttpServerConnector() ); d->tlsSession.reset( new QxtHttpSessionManager() ); d->tlsConnector.reset( new QxtHttpsServerConnector() ); if ( d->session.isNull() || d->connector.isNull() || d->tlsSession.isNull() || d->tlsConnector.isNull() ) { if ( !d->session.isNull() ) d->session.reset(); if ( !d->connector.isNull() ) d->connector.reset(); if ( !d->tlsSession.isNull() ) d->tlsSession.reset(); if ( !d->tlsConnector.isNull() ) d->tlsConnector.reset(); tLog() << "Failed to start HTTPd, could not create object"; return; } d->session->setListenInterface( d->ha ); d->session->setPort( d->port ); d->session->setConnector( d->connector.data() ); d->instance.reset( new Api_v1( d->session.data() ) ); d->session->setStaticContentService( d->instance.data() ); tLog() << "Starting HTTPd on" << d->session->listenInterface().toString() << d->session->port(); d->session->start(); d->tlsSession->setListenInterface( d->ha ); d->tlsSession->setPort( d->sport ); d->tlsSession->setConnector( d->tlsConnector.data() ); d->tlsInstance.reset( new Api_v1( d->tlsSession.data() ) ); d->tlsSession->setStaticContentService( d->tlsInstance.data() ); QByteArray settingsKey = TomahawkSettings::instance()->playdarKey(); QSslKey key; if ( settingsKey.isNull() || settingsKey.isEmpty() ) { // Generate a SSL key key = KeyBuilder::generate( QSsl::Rsa, KeyBuilder::StrengthNormal ); TomahawkSettings::instance()->setPlaydarKey( key.toPem() ); } else { // Restore key key = QSslKey( settingsKey, QSsl::Rsa ); } QByteArray settingsCert = TomahawkSettings::instance()->playdarCertificate(); QSslCertificate cert; if ( settingsCert.isNull() || settingsCert.isEmpty() ) { // Generate a SSL certificate CertificateRequestBuilder reqbuilder; reqbuilder.setVersion( 1 ); reqbuilder.setKey( key ); reqbuilder.addNameEntry( Certificate::EntryCountryName, "GB" ); reqbuilder.addNameEntry( Certificate::EntryOrganizationName, "Tomahawk Player (Desktop)" ); reqbuilder.addNameEntry( Certificate::EntryCommonName, "localhost" ); // Sign the request CertificateRequest req = reqbuilder.signedRequest(key); // Now make a certificate CertificateBuilder builder; builder.setRequest( req ); builder.setVersion( 3 ); builder.setSerial( uuid().toLatin1() ); builder.setActivationTime( QDateTime::currentDateTimeUtc()); builder.setExpirationTime( QDateTime::currentDateTimeUtc().addYears( 10 ) ); builder.setBasicConstraints( false ); builder.addKeyPurpose( CertificateBuilder::PurposeWebServer ); builder.setKeyUsage( CertificateBuilder::UsageKeyAgreement|CertificateBuilder::UsageKeyEncipherment ); builder.addSubjectKeyIdentifier(); cert = builder.signedCertificate( key ); TomahawkSettings::instance()->setPlaydarCertificate( cert.toPem() ); } else { cert = QSslCertificate( settingsCert ); } QxtSslServer* sslServer = d->tlsConnector->tcpServer(); sslServer->setPrivateKey( key ); sslServer->setLocalCertificate( cert ); tLog() << "Starting HTTPSd on" << d->tlsSession->listenInterface().toString() << d->tlsSession->port(); tLog() << Q_FUNC_INFO << d->tlsSession->start(); }
void QSslKeyProto::clear() { QSslKey *item = qscriptvalue_cast<QSslKey*>(thisObject()); if (item) item->clear(); }
void QSslKeyProto::swap(QSslKey & other) { QSslKey *item = qscriptvalue_cast<QSslKey*>(thisObject()); if (item) item->swap(other); }
void WebUI::init() { Preferences* const pref = Preferences::instance(); Logger* const logger = Logger::instance(); if (pref->isWebUiEnabled()) { const quint16 port = pref->getWebUiPort(); if (m_port != port) { Net::PortForwarder::instance()->deletePort(port); m_port = port; } if (httpServer_) { if (httpServer_->serverPort() != m_port) httpServer_->close(); } else { webapp_ = new WebApplication(this); httpServer_ = new Http::Server(webapp_, this); } #ifndef QT_NO_OPENSSL if (pref->isWebUiHttpsEnabled()) { QList<QSslCertificate> certs = QSslCertificate::fromData(pref->getWebUiHttpsCertificate()); QSslKey key; key = QSslKey(pref->getWebUiHttpsKey(), QSsl::Rsa); bool certsIsNull = std::any_of(certs.begin(), certs.end(), [](QSslCertificate c) { return c.isNull(); }); if (!certsIsNull && !certs.empty() && !key.isNull()) httpServer_->enableHttps(certs, key); else httpServer_->disableHttps(); } else { httpServer_->disableHttps(); } #endif if (!httpServer_->isListening()) { bool success = httpServer_->listen(QHostAddress::Any, m_port); if (success) logger->addMessage(tr("The Web UI is listening on port %1").arg(m_port)); else logger->addMessage(tr("Web UI Error - Unable to bind Web UI to port %1").arg(m_port), Log::CRITICAL); } // DynDNS if (pref->isDynDNSEnabled()) { if (!dynDNSUpdater_) dynDNSUpdater_ = new Net::DNSUpdater(this); else dynDNSUpdater_->updateCredentials(); } else { if (dynDNSUpdater_) delete dynDNSUpdater_; } // Use UPnP/NAT-PMP for Web UI if (pref->useUPnPForWebUIPort()) Net::PortForwarder::instance()->addPort(m_port); else Net::PortForwarder::instance()->deletePort(m_port); } else { if (httpServer_) delete httpServer_; if (webapp_) delete webapp_; if (dynDNSUpdater_) delete dynDNSUpdater_; Net::PortForwarder::instance()->deletePort(m_port); } }
void DataPlaneServer::start() { server_addr.s6.sin6_family = AF_INET6; // we listen on public IP, which is the one stored in the DB. struct in6_addr servIp; inet_pton(AF_INET6, qSql->getLocalIP().toUtf8().data(), &servIp); server_addr.s6.sin6_addr = servIp; //in6addr_any; server_addr.s6.sin6_port = htons(DATAPLANEPORT); const int on = 1, off = 0; OpenSSL_add_ssl_algorithms(); SSL_load_error_strings(); ctx = SSL_CTX_new(DTLSv1_server_method()); SSL_CTX_set_cipher_list(ctx, DTLS_ENCRYPT); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); // get certificate and key from SQL & use them ConnectionInitiator* i = ConnectionInitiator::getInstance(); QSslCertificate cert = i->getLocalCertificate(); QByteArray certBytesPEM = cert.toPem(); char* x509buffer = certBytesPEM.data(); BIO *bi; bi = BIO_new_mem_buf(x509buffer, certBytesPEM.length()); X509 *x; x = PEM_read_bio_X509(bi, NULL, NULL, NULL); if (!SSL_CTX_use_certificate(ctx,x)) { qWarning() << "ERROR: no certificate found!"; UnixSignalHandler::termSignalHandler(0); } if (x != NULL) X509_free(x); if (bi != NULL) BIO_free(bi); QSslKey key = i->getPrivateKey(); QByteArray keyBytesPEM = key.toPem(); char* keyBuffer = keyBytesPEM.data(); bi = BIO_new_mem_buf(keyBuffer, keyBytesPEM.length()); EVP_PKEY *pkey; pkey = PEM_read_bio_PrivateKey(bi, NULL, NULL, NULL); if (!SSL_CTX_use_PrivateKey(ctx, pkey)) { qWarning() << "ERROR: no private key found!"; UnixSignalHandler::termSignalHandler(0); } if (pkey != NULL) EVP_PKEY_free(pkey); if (bi != NULL) BIO_free(bi); if (!SSL_CTX_check_private_key (ctx)) { qWarning() << "ERROR: invalid private key!"; UnixSignalHandler::termSignalHandler(0); } /* Client has to authenticate */ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, dtls_verify_callback); SSL_CTX_set_read_ahead(ctx, 1); SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie); SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie); fd = socket(server_addr.ss.ss_family, SOCK_DGRAM, 0); if (fd < 0) { qWarning() << "Could not open SOCK_DGRAM"; UnixSignalHandler::termSignalHandler(0); } #ifdef WIN32 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, (socklen_t) sizeof(on)); #else setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &on, (socklen_t) sizeof(on)); #ifdef SO_REUSEPORT setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &on, (socklen_t) sizeof(on)); #endif #endif setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off)); bind(fd, (const struct sockaddr *) &server_addr, sizeof(struct sockaddr_in6)); notif = new QSocketNotifier(fd, QSocketNotifier::Read); connect(notif, SIGNAL(activated(int)), this, SLOT(readyRead(int))); }
bool SslServer::setCertificate(const QString &path, const QString &keyPath) { // Don't reset _isCertValid here, in case an older but valid certificate is still loaded. // Use temporary variables in order to avoid overwriting the existing certificates until // everything is confirmed good. QSslCertificate untestedCert; QList<QSslCertificate> untestedCA; QSslKey untestedKey; if (path.isEmpty()) return false; QFile certFile(path); if (!certFile.exists()) { quWarning() << "SslServer: Certificate file" << qPrintable(path) << "does not exist"; return false; } if (!certFile.open(QIODevice::ReadOnly)) { quWarning() << "SslServer: Failed to open certificate file" << qPrintable(path) << "error:" << certFile.error(); return false; } QList<QSslCertificate> certList = QSslCertificate::fromDevice(&certFile); if (certList.isEmpty()) { quWarning() << "SslServer: Certificate file doesn't contain a certificate"; return false; } untestedCert = certList[0]; certList.removeFirst(); // remove server cert // store CA and intermediates certs untestedCA = certList; if (!certFile.reset()) { quWarning() << "SslServer: IO error reading certificate file"; return false; } // load key from keyPath if it differs from path, otherwise load key from path if(path != keyPath) { QFile keyFile(keyPath); if(!keyFile.exists()) { quWarning() << "SslServer: Key file" << qPrintable(keyPath) << "does not exist"; return false; } if (!keyFile.open(QIODevice::ReadOnly)) { quWarning() << "SslServer: Failed to open key file" << qPrintable(keyPath) << "error:" << keyFile.error(); return false; } untestedKey = QSslKey(&keyFile, QSsl::Rsa); keyFile.close(); } else { untestedKey = QSslKey(&certFile, QSsl::Rsa); } certFile.close(); if (untestedCert.isNull()) { quWarning() << "SslServer:" << qPrintable(path) << "contains no certificate data"; return false; } // We allow the core to offer SSL anyway, so no "return false" here. Client will warn about the cert being invalid. const QDateTime now = QDateTime::currentDateTime(); if (now < untestedCert.effectiveDate()) quWarning() << "SslServer: Certificate won't be valid before" << untestedCert.effectiveDate().toString(); else if (now > untestedCert.expiryDate()) quWarning() << "SslServer: Certificate expired on" << untestedCert.expiryDate().toString(); else { // Qt4's isValid() checks for time range and blacklist; avoid a double warning, hence the else block #if QT_VERSION < 0x050000 if (!untestedCert.isValid()) #else if (untestedCert.isBlacklisted()) #endif quWarning() << "SslServer: Certificate blacklisted"; } if (untestedKey.isNull()) { quWarning() << "SslServer:" << qPrintable(keyPath) << "contains no key data"; return false; } _isCertValid = true; // All keys are valid, update the externally visible copy used for new connections. _cert = untestedCert; _ca = untestedCA; _key = untestedKey; return _isCertValid; }