23 #include <QSslCertificate> 33 #if QT_VERSION >= 0x040800 34 case QSsl::SecureProtocols:
36 case QSsl::TlsV1SslV3:
67 org =
"(Organization not defined)";
69 orgcerts.
insert( org, valist << cert );
94 orgconfigs.
insert( org, valist << config );
107 openflags |= QIODevice::Text;
108 bool ret = file.
open( openflags );
121 bool pem = certspath.
endsWith(
".pem", Qt::CaseInsensitive );
136 cert = certs.
first();
149 bool pem = keypath.
endsWith(
".pem", Qt::CaseInsensitive );
155 pem ? QSsl::Pem : QSsl::Der,
163 pem ? QSsl::Pem : QSsl::Der,
200 if ( !clientcert.
isNull() )
210 if ( !clientkey.
isNull() )
215 return QStringList() << certpem << keypem << algtype;
223 if ( !QCA::isSupported(
"pkcs12" ) )
227 if ( bundle.isNull() )
230 QCA::SecureArray passarray;
231 if ( reencrypt && !bundlepass.
isEmpty() )
232 passarray = QCA::SecureArray( bundlepass.
toUtf8() );
235 if ( bundle.privateKey().isRSA() )
239 else if ( bundle.privateKey().isDSA() )
243 else if ( bundle.privateKey().isDH() )
248 return QStringList() << bundle.certificateChain().primary().toPEM() << bundle.privateKey().toPEM( passarray ) << algtype;
256 if ( pemFile.
open( QIODevice::WriteOnly ) )
258 qint64 bytesWritten = pemFile.
write( pemtext );
259 if ( bytesWritten == -1 )
267 QgsDebugMsg(
QString(
"FAILED to open writing for temp PEM file: %1" ).arg( pemFilePath ) );
273 QgsDebugMsg(
QString(
"FAILED to set permissions on temp PEM file: %1" ).arg( pemFilePath ) );
303 name = issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::OrganizationalUnitName )
315 name = issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::StateOrProvinceName )
326 void QgsAuthCertUtils::appendDirSegment_(
QStringList &dirname,
331 dirname.
append( segment +
'=' + value.
replace(
',',
"\\," ) );
336 const QCA::Certificate &acert ,
342 if ( acert.isNull() )
344 QCA::ConvertResult res;
345 QCA::Certificate acert( QCA::Certificate::fromPEM( qcert.
toPem(), &res,
QString(
"qca-ossl" ) ) );
346 if ( res != QCA::ConvertGood || acert.isNull() )
348 QgsDebugMsg(
"Certificate could not be converted to QCA cert" );
360 QgsAuthCertUtils::appendDirSegment_(
361 dirname,
"E", issuer ? acert.issuerInfo().
value( QCA::Email )
362 : acert.subjectInfo().value( QCA::Email ) );
363 QgsAuthCertUtils::appendDirSegment_(
364 dirname,
"CN", issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::CommonName )
366 QgsAuthCertUtils::appendDirSegment_(
367 dirname,
"OU", issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::OrganizationalUnitName )
369 QgsAuthCertUtils::appendDirSegment_(
370 dirname,
"O", issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::Organization )
372 QgsAuthCertUtils::appendDirSegment_(
373 dirname,
"L", issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::LocalityName )
375 QgsAuthCertUtils::appendDirSegment_(
376 dirname,
"ST", issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::StateOrProvinceName )
378 QgsAuthCertUtils::appendDirSegment_(
379 dirname,
"C", issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::CountryName )
382 return dirname.
join(
"," );
406 for (
int i = 0; i < txt.
size(); i += 2 )
408 sl << txt.
mid( i, ( i + 2 > txt.
size() ) ? -1 : 2 );
410 return sl.
join(
":" );
426 return QCA::Certificate();
428 QCA::ConvertResult res;
429 QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.
toPem(), &res,
QString(
"qca-ossl" ) ) );
430 if ( res != QCA::ConvertGood || qcacert.isNull() )
432 QgsDebugMsg(
"Certificate could not be converted to QCA cert" );
433 qcacert = QCA::Certificate();
440 QCA::CertificateCollection qcacoll;
447 if ( !qcacert.isNull() )
449 qcacoll.addCertificate( qcacert );
457 QCA::SecureArray passarray;
459 passarray = QCA::SecureArray( pass.
toUtf8() );
461 QCA::ConvertResult res;
462 QCA::KeyBundle bundle( QCA::KeyBundle::fromFile( path, passarray, &res,
QString(
"qca-ossl" ) ) );
464 return ( res == QCA::ConvertGood ? bundle : QCA::KeyBundle() );
471 case QCA::ValidityGood:
473 case QCA::ErrorRejected:
474 return QObject::tr(
"Root CA rejected the certificate purpose." );
475 case QCA::ErrorUntrusted:
476 return QObject::tr(
"Certificate is not trusted." );
477 case QCA::ErrorSignatureFailed:
479 case QCA::ErrorInvalidCA:
480 return QObject::tr(
"Certificate Authority is invalid or not found." );
481 case QCA::ErrorInvalidPurpose:
482 return QObject::tr(
"Purpose does not match the intended usage." );
483 case QCA::ErrorSelfSigned:
484 return QObject::tr(
"Certificate is self-signed, and is not found in the list of trusted certificates." );
485 case QCA::ErrorRevoked:
486 return QObject::tr(
"Certificate has been revoked." );
487 case QCA::ErrorPathLengthExceeded:
488 return QObject::tr(
"Path length from the root CA to this certificate is too long." );
489 case QCA::ErrorExpired:
490 return QObject::tr(
"Certificate has expired or is not yet valid." );
491 case QCA::ErrorExpiredCA:
492 return QObject::tr(
"Certificate Authority has expired." );
493 case QCA::ErrorValidityUnknown:
504 case QCA::EMSA1_SHA1:
506 case QCA::EMSA3_SHA1:
512 case QCA::EMSA3_RIPEMD160:
516 #if QCA_VERSION >= 0x020100 517 case QCA::EMSA3_SHA224:
519 case QCA::EMSA3_SHA256:
521 case QCA::EMSA3_SHA384:
523 case QCA::EMSA3_SHA512:
527 return QObject::tr(
"Unknown (possibly Elliptic Curve)" );
533 switch ( constraint )
535 case QCA::DigitalSignature:
537 case QCA::NonRepudiation:
539 case QCA::KeyEncipherment:
541 case QCA::DataEncipherment:
543 case QCA::KeyAgreement:
545 case QCA::KeyCertificateSign:
549 case QCA::EncipherOnly:
551 case QCA::DecipherOnly:
553 case QCA::ServerAuth:
555 case QCA::ClientAuth:
557 case QCA::CodeSigning:
559 case QCA::EmailProtection:
561 case QCA::IPSecEndSystem:
563 case QCA::IPSecTunnel:
567 case QCA::TimeStamping:
569 case QCA::OCSPSigning:
613 QCA::ConvertResult res;
614 QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.
toPem(), &res,
QString(
"qca-ossl" ) ) );
615 if ( res != QCA::ConvertGood || qcacert.isNull() )
617 QgsDebugMsg(
"Certificate could not be converted to QCA cert" );
621 if ( qcacert.isCA() )
623 QgsDebugMsg(
"Certificate has 'CA:TRUE' basic constraint" );
628 Q_FOREACH (
const QCA::ConstraintType& certconst, certconsts )
630 if ( certconst.known() == QCA::KeyCertificateSign )
632 QgsDebugMsg(
"Certificate has 'Certificate Sign' key usage" );
635 else if ( certconst.known() == QCA::ServerAuth )
637 QgsDebugMsg(
"Certificate has 'server authentication' extended key usage" );
643 QCA::CertificateCollection trustedCAs(
645 QCA::CertificateCollection untrustedCAs(
649 v_any = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageAny, QCA::ValidateAll );
650 if ( v_any == QCA::ValidityGood )
655 QCA::Validity v_tlsserver;
656 v_tlsserver = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageTLSServer, QCA::ValidateAll );
657 if ( v_tlsserver == QCA::ValidityGood )
667 QCA::Validity v_tlsclient;
668 v_tlsclient = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageTLSClient, QCA::ValidateAll );
670 if ( v_tlsclient == QCA::ValidityGood )
713 QCA::ConvertResult res;
714 QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.
toPem(), &res,
QString(
"qca-ossl" ) ) );
715 if ( res != QCA::ConvertGood || qcacert.isNull() )
717 QgsDebugMsg(
"Certificate could not be converted to QCA cert" );
721 if ( qcacert.isCA() )
723 QgsDebugMsg(
"SSL server certificate has 'CA:TRUE' basic constraint (and should not)" );
728 Q_FOREACH ( QCA::ConstraintType certconst, certconsts )
730 if ( certconst.known() == QCA::KeyCertificateSign )
732 QgsDebugMsg(
"SSL server certificate has 'Certificate Sign' key usage (and should not)" );
739 bool serverauth =
false;
740 bool dsignature =
false;
741 bool keyencrypt =
false;
742 Q_FOREACH ( QCA::ConstraintType certconst, certconsts )
744 if ( certconst.known() == QCA::DigitalSignature )
746 QgsDebugMsg(
"SSL server certificate has 'digital signature' key usage" );
749 else if ( certconst.known() == QCA::KeyEncipherment )
751 QgsDebugMsg(
"SSL server certificate has 'key encipherment' key usage" );
754 else if ( certconst.known() == QCA::KeyAgreement )
756 QgsDebugMsg(
"SSL server certificate has 'key agreement' key usage" );
759 else if ( certconst.known() == QCA::ServerAuth )
761 QgsDebugMsg(
"SSL server certificate has 'server authentication' extended key usage" );
773 if ( serverauth && dsignature && keyencrypt )
777 if ( dsignature && keyencrypt )
783 bool keyagree =
false;
784 bool encipheronly =
false;
785 bool decipheronly =
false;
787 QCA::PublicKey pubkey( qcacert.subjectPublicKey() );
789 if ( pubkey.bitSize() > 0 && pubkey.isDH() )
791 keyagree = pubkey.canKeyAgree();
796 Q_FOREACH ( QCA::ConstraintType certconst, certconsts )
798 if ( certconst.known() == QCA::EncipherOnly )
800 QgsDebugMsg(
"SSL server public key has 'encipher only' key usage" );
803 else if ( certconst.known() == QCA::DecipherOnly )
805 QgsDebugMsg(
"SSL server public key has 'decipher only' key usage" );
809 if ( !encipheronly && !decipheronly )
827 case QSslError::UnableToGetIssuerCertificate:
828 return QObject::tr(
"Unable To Get Issuer Certificate" );
829 case QSslError::UnableToDecryptCertificateSignature:
830 return QObject::tr(
"Unable To Decrypt Certificate Signature" );
831 case QSslError::UnableToDecodeIssuerPublicKey:
832 return QObject::tr(
"Unable To Decode Issuer Public Key" );
833 case QSslError::CertificateSignatureFailed:
834 return QObject::tr(
"Certificate Signature Failed" );
835 case QSslError::CertificateNotYetValid:
837 case QSslError::CertificateExpired:
839 case QSslError::InvalidNotBeforeField:
841 case QSslError::InvalidNotAfterField:
843 case QSslError::SelfSignedCertificate:
845 case QSslError::SelfSignedCertificateInChain:
846 return QObject::tr(
"Self-signed Certificate In Chain" );
847 case QSslError::UnableToGetLocalIssuerCertificate:
848 return QObject::tr(
"Unable To Get Local Issuer Certificate" );
849 case QSslError::UnableToVerifyFirstCertificate:
850 return QObject::tr(
"Unable To Verify First Certificate" );
851 case QSslError::CertificateRevoked:
853 case QSslError::InvalidCaCertificate:
855 case QSslError::PathLengthExceeded:
857 case QSslError::InvalidPurpose:
859 case QSslError::CertificateUntrusted:
861 case QSslError::CertificateRejected:
863 case QSslError::SubjectIssuerMismatch:
865 case QSslError::AuthorityIssuerSerialNumberMismatch:
866 return QObject::tr(
"Authority Issuer Serial Number Mismatch" );
867 case QSslError::NoPeerCertificate:
869 case QSslError::HostNameMismatch:
871 case QSslError::UnspecifiedError:
873 case QSslError::CertificateBlacklisted:
875 case QSslError::NoError:
877 case QSslError::NoSslSupport:
887 errenums << qMakePair( QSslError::UnableToGetIssuerCertificate,
889 errenums << qMakePair( QSslError::UnableToDecryptCertificateSignature,
891 errenums << qMakePair( QSslError::UnableToDecodeIssuerPublicKey,
893 errenums << qMakePair( QSslError::CertificateSignatureFailed,
895 errenums << qMakePair( QSslError::CertificateNotYetValid,
897 errenums << qMakePair( QSslError::CertificateExpired,
899 errenums << qMakePair( QSslError::InvalidNotBeforeField,
901 errenums << qMakePair( QSslError::InvalidNotAfterField,
903 errenums << qMakePair( QSslError::SelfSignedCertificate,
905 errenums << qMakePair( QSslError::SelfSignedCertificateInChain,
907 errenums << qMakePair( QSslError::UnableToGetLocalIssuerCertificate,
909 errenums << qMakePair( QSslError::UnableToVerifyFirstCertificate,
911 errenums << qMakePair( QSslError::CertificateRevoked,
913 errenums << qMakePair( QSslError::InvalidCaCertificate,
915 errenums << qMakePair( QSslError::PathLengthExceeded,
917 errenums << qMakePair( QSslError::InvalidPurpose,
919 errenums << qMakePair( QSslError::CertificateUntrusted,
921 errenums << qMakePair( QSslError::CertificateRejected,
923 errenums << qMakePair( QSslError::SubjectIssuerMismatch,
925 errenums << qMakePair( QSslError::AuthorityIssuerSerialNumberMismatch,
927 errenums << qMakePair( QSslError::NoPeerCertificate,
929 errenums << qMakePair( QSslError::HostNameMismatch,
931 errenums << qMakePair( QSslError::UnspecifiedError,
933 errenums << qMakePair( QSslError::CertificateBlacklisted,
static QString certificateUsageTypeString(QgsAuthCertUtils::CertUsageType usagetype)
Certificate usage type strings per enum.
static QString pemTextToTempFile(const QString &name, const QByteArray &pemtext)
Write a temporary file for a PEM text of cert/key/CAs bundle component.
bool contains(const Key &key) const
static QMap< QString, QgsAuthConfigSslServer > mapDigestToSslConfigs(const QList< QgsAuthConfigSslServer > &configs)
Map SSL custom configs' certificate sha1 to custom config as simple cache.
static QgsAuthManager * instance()
Enforce singleton pattern.
static bool certificateIsIssuer(const QSslCertificate &cert)
Get whether a certificate can sign other certificates.
static QString qcaKnownConstraint(QCA::ConstraintTypeKnown constraint)
Certificate well-known constraint strings per enum.
static QSslKey keyFromFile(const QString &keypath, const QString &keypass=QString(), QString *algtype=nullptr)
Return non-encrypted key from a PEM or DER formatted file.
static QString sslErrorEnumString(QSslError::SslError errenum)
Get short strings describing an SSL error.
static QList< QSslCertificate > certsFromFile(const QString &certspath)
Return list of concatenated certs from a PEM or DER formatted file.
static QMap< QString, QSslCertificate > mapDigestToCerts(const QList< QSslCertificate > &certs)
Map certificate sha1 to certificate as simple cache.
Configuration container for SSL server connection exceptions or overrides.
static bool certificateIsAuthorityOrIssuer(const QSslCertificate &cert)
Get whether a certificate is an Authority or can at least sign other certificates.
static QCA::CertificateCollection qtCertsToQcaCollection(const QList< QSslCertificate > &certs)
Convert a QList of QSslCertificate to a QCA::CertificateCollection.
bool setPermissions(QFlags< QFile::Permission > permissions)
QString join(const QString &separator) const
CertUsageType
Type of certificate usage.
static QCA::Certificate qtCertToQcaCert(const QSslCertificate &cert)
Convert a QSslCertificate to a QCA::Certificate.
static QList< QgsAuthCertUtils::CertUsageType > certificateUsageTypes(const QSslCertificate &cert)
Try to determine the certificates usage types.
QString tr(const char *sourceText, const char *disambiguation, int n)
static QByteArray fileData_(const QString &path, bool astext=false)
static QStringList pkcs12BundleToPem(const QString &bundlepath, const QString &bundlepass=QString(), bool reencrypt=true)
Return list of certificate, private key and algorithm (as PEM text) for a PKCS#12 bundle...
static bool certificateIsAuthority(const QSslCertificate &cert)
Get whether a certificate is an Authority.
void append(const T &value)
static QStringList certKeyBundleToPem(const QString &certpath, const QString &keypath, const QString &keypass=QString(), bool reencrypt=true)
Return list of certificate, private key and algorithm (as PEM text) from file path components...
static QString getCertDistinguishedName(const QSslCertificate &qcert, const QCA::Certificate &acert=QCA::Certificate(), bool issuer=false)
Get combined distinguished name for certificate.
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
static QMap< QString, QList< QgsAuthConfigSslServer > > sslConfigsGroupedByOrg(const QList< QgsAuthConfigSslServer > &configs)
Map SSL custom configs' certificates to their oraganization.
QList< QSslCertificate > fromData(const QByteArray &data, QSsl::EncodingFormat format)
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
static bool certificateIsSslServer(const QSslCertificate &cert)
Get whether a certificate is probably used for a SSL server.
static QList< QSslCertificate > certsFromString(const QString &pemtext)
Return list of concatenated certs from a PEM Base64 text block.
static QString getSslProtocolName(QSsl::SslProtocol protocol)
SSL Protocol name strings per enum.
bool contains(const T &value) const
QByteArray digest(QCryptographicHash::Algorithm algorithm) const
static bool certificateIsSslClient(const QSslCertificate &cert)
Get whether a certificate is probably used for a client identity.
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Get the sha1 hash for certificate.
QString & replace(int position, int n, QChar after)
const QSslCertificate sslCertificate() const
Server certificate object.
QString mid(int position, int n) const
CaCertSource
Type of CA certificate source.
#define SSL_SUBJECT_INFO(var, prop)
static QString qcaSignatureAlgorithm(QCA::SignatureAlgorithm algorithm)
Certificate signature algorithm strings per enum.
qint64 write(const char *data, qint64 maxSize)
QByteArray toPem(const QByteArray &passPhrase) const
static QMap< QString, QList< QSslCertificate > > certsGroupedByOrg(const QList< QSslCertificate > &certs)
Map certificates to their oraganization.
iterator insert(const Key &key, const T &value)
CertTrustPolicy
Type of certificate trust policy.
static QString getColonDelimited(const QString &txt)
Get string with colon delimeters every 2 characters.
static QCA::KeyBundle qcaKeyBundle(const QString &path, const QString &pass)
PKI key/cert bundle from file path, e.g.
static QList< QPair< QSslError::SslError, QString > > sslErrorEnumStrings()
Get short strings describing SSL errors.
static QString getCertTrustName(QgsAuthCertUtils::CertTrustPolicy trust)
Get the general name for certificate trust.
static QSslCertificate certFromFile(const QString &certpath)
Return first cert from a PEM or DER formatted file.
#define SSL_ISSUER_INFO(var, prop)
static QString getCaSourceName(QgsAuthCertUtils::CaCertSource source, bool single=false)
Get the general name for CA source enum type.
static QString resolvedCertName(const QSslCertificate &cert, bool issuer=false)
Get the general name via RFC 5280 resolution.
QByteArray toAscii() const
static QString qcaValidityMessage(QCA::Validity validity)
Certificate validity check messages per enum.
const T value(const Key &key) const
QByteArray toUtf8() const