23#include <QSslCertificate>
40 case QSsl::SecureProtocols:
41 return QObject::tr(
"SecureProtocols" );
42#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
43 case QSsl::TlsV1SslV3:
44 return QObject::tr(
"TlsV1SslV3" );
47 return QObject::tr(
"TlsV1" );
48#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
51 return QObject::tr(
"SslV3" );
53 return QObject::tr(
"SslV2" );
62 QMap<QString, QSslCertificate> digestmap;
63 for (
const auto &cert : certs )
72 QMap< QString, QList<QSslCertificate> > orgcerts;
73 for (
const auto &cert : certs )
77 org = QStringLiteral(
"(Organization not defined)" );
78 QList<QSslCertificate> valist = orgcerts.contains( org ) ? orgcerts.value( org ) : QList<QSslCertificate>();
79 orgcerts.insert( org, valist << cert );
86 QMap<QString, QgsAuthConfigSslServer> digestmap;
87 for (
const auto &config : configs )
89 digestmap.insert(
shaHexForCert( config.sslCertificate() ), config );
96 QMap< QString, QList<QgsAuthConfigSslServer> > orgconfigs;
97 for (
const auto &config : configs )
99 QString org(
SSL_SUBJECT_INFO( config.sslCertificate(), QSslCertificate::Organization ) );
102 org = QObject::tr(
"(Organization not defined)" );
103 QList<QgsAuthConfigSslServer> valist = orgconfigs.contains( org ) ? orgconfigs.value( org ) : QList<QgsAuthConfigSslServer>();
104 orgconfigs.insert( org, valist << config );
113 if ( !file.exists() )
115 QgsDebugMsg( QStringLiteral(
"Read file error, file not found: %1" ).arg( path ) );
119 const QFile::OpenMode openflags( QIODevice::ReadOnly );
120 const bool ret = file.open( openflags );
123 data = file.readAll();
132 QList<QSslCertificate> certs;
134 certs = QSslCertificate::fromData( payload, sniffEncoding( payload ) );
135 if ( certs.isEmpty() )
137 QgsDebugMsg( QStringLiteral(
"Parsed cert(s) EMPTY for path: %1" ).arg( certspath ) );
144 QList<QSslCertificate> cas;
145 const QList<QSslCertificate> certs(
certsFromFile( certspath ) );
146 for (
const auto &cert : certs )
159 QList<QSslCertificate> result( bundle1 );
160 const QList<QSslCertificate> c_bundle1( bundle1 );
161 for (
const auto &cert : c_bundle1 )
165 const QList<QSslCertificate> c_bundle2( bundle2 );
166 for (
const auto &cert : c_bundle2 )
170 result.append( cert );
180 QSslCertificate cert;
182 if ( !certs.isEmpty() )
184 cert = certs.first();
188 QgsDebugMsg( QStringLiteral(
"Parsed cert is NULL for path: %1" ).arg( certpath ) );
194 const QString &keypass,
201 const QSsl::EncodingFormat keyEncoding( sniffEncoding( keydata ) );
203 const std::vector<QSsl::KeyAlgorithm> algs
205 QSsl::KeyAlgorithm::Rsa,
206 QSsl::KeyAlgorithm::Dsa,
207 QSsl::KeyAlgorithm::Ec,
208 QSsl::KeyAlgorithm::Opaque
211 for (
const auto &alg : algs )
213 clientkey = QSslKey( keydata,
217 !keypass.isEmpty() ? keypass.toUtf8() : QByteArray() );
218 if ( ! clientkey.isNull() )
224 case QSsl::KeyAlgorithm::Rsa:
225 *algtype = QStringLiteral(
"rsa" );
227 case QSsl::KeyAlgorithm::Dsa:
228 *algtype = QStringLiteral(
"dsa" );
230 case QSsl::KeyAlgorithm::Ec:
231 *algtype = QStringLiteral(
"ec" );
233 case QSsl::KeyAlgorithm::Opaque:
234 *algtype = QStringLiteral(
"opaque" );
236 case QSsl::KeyAlgorithm::Dh:
237 *algtype = QStringLiteral(
"dh" );
249 QList<QSslCertificate> certs;
250 certs = QSslCertificate::fromData( pemtext.toLatin1(), QSsl::Pem );
251 if ( certs.isEmpty() )
253 QgsDebugMsg( QStringLiteral(
"Parsed cert(s) EMPTY" ) );
260 QList<QSslCertificate> certs;
261 for (
const auto &cert : caList )
263 if ( ! cert.isSelfSigned( ) )
265 certs.append( cert );
272 const QString &keypath,
273 const QString &keypass,
278 if ( !clientcert.isNull() )
280 certpem = QString( clientcert.toPem() );
288 if ( !clientkey.isNull() )
290 keypem = QString( clientkey.toPem( ( reencrypt && !keypass.isEmpty() ) ? keypass.toUtf8() : QByteArray() ) );
293 return QStringList() << certpem << keypem << algtype;
298 const QString pkcs8Header = QStringLiteral(
"-----BEGIN PRIVATE KEY-----" );
299 const QString pkcs8Footer = QStringLiteral(
"-----END PRIVATE KEY-----" );
300 return keyPemTxt.contains( pkcs8Header ) && keyPemTxt.contains( pkcs8Footer );
304QByteArray QgsAuthCertUtils::pkcs8PrivateKey( QByteArray &pkcs8Der )
308 if ( pkcs8Der.isEmpty() )
310 QgsDebugMsg( QStringLiteral(
"ERROR, passed DER is empty" ) );
317 if ( ! asnDefsRsrc.exists() )
319 QgsDebugMsg( QStringLiteral(
"ERROR, pkcs.asn resource file not found: %1" ).arg( asnDefsRsrc.filePath() ) );
322 const char *asnDefsFile = asnDefsRsrc.absoluteFilePath().toLocal8Bit().constData();
324 int asn1_result = ASN1_SUCCESS, der_len = 0, oct_len = 0;
325 asn1_node definitions = NULL, structure = NULL;
326 char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE], oct_data[1024];
327 unsigned char *der = NULL;
328 unsigned int flags = 0;
332 QString
typeName( QStringLiteral(
"PKCS-8.PrivateKeyInfo" ) );
334 asn1_result = asn1_parser2tree( asnDefsFile, &definitions, errorDescription );
336 switch ( asn1_result )
341 case ASN1_FILE_NOT_FOUND:
342 QgsDebugMsg( QStringLiteral(
"ERROR, file not found: %1" ).arg( asnDefsFile ) );
344 case ASN1_SYNTAX_ERROR:
345 case ASN1_IDENTIFIER_NOT_FOUND:
346 case ASN1_NAME_TOO_LONG:
347 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 parsing: %1" ).arg( errorDescription ) );
350 QgsDebugMsg( QStringLiteral(
"ERROR, libtasn1: %1" ).arg( asn1_strerror( asn1_result ) ) );
355 asn1_result = asn1_create_element( definitions,
typeName.toLatin1().constData(), &structure );
359 if ( asn1_result != ASN1_SUCCESS )
361 QgsDebugMsg( QStringLiteral(
"ERROR, structure creation: %1" ).arg( asn1_strerror( asn1_result ) ) );
366 der =
reinterpret_cast<unsigned char *
>( pkcs8Der.data() );
367 der_len = pkcs8Der.size();
371 asn1_result = asn1_der_decoding2( &structure, der, &der_len, flags, errorDescription );
375 asn1_result = asn1_der_decoding( &structure, der, der_len, errorDescription );
378 if ( asn1_result != ASN1_SUCCESS )
380 QgsDebugMsg( QStringLiteral(
"ERROR, decoding: %1" ).arg( errorDescription ) );
385 QgsDebugMsgLevel( QStringLiteral(
"Decoding: %1" ).arg( asn1_strerror( asn1_result ) ), 4 );
390 QgsDebugMsg( QStringLiteral(
"DECODING RESULT:" ) );
391 asn1_print_structure( stdout, structure,
"", ASN1_PRINT_NAME_TYPE_VALUE );
396 typeName.append( QStringLiteral(
".privateKey" ) );
399 asn1_result = asn1_read_value_type( structure,
"privateKey", NULL, &oct_len, &oct_etype );
401 if ( asn1_result != ASN1_MEM_ERROR )
403 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 read privateKey value type: %1" ).arg( asn1_strerror( asn1_result ) ) );
407 if ( oct_etype != ASN1_ETYPE_OCTET_STRING )
409 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 privateKey value not octet string, but type: %1" ).arg(
static_cast<int>( oct_etype ) ) );
415 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 privateKey octet string empty" ) );
420 asn1_result = asn1_read_value( structure,
"privateKey", oct_data, &oct_len );
422 if ( asn1_result != ASN1_SUCCESS )
424 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 read privateKey value: %1" ).arg( asn1_strerror( asn1_result ) ) );
430 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 privateKey value octet string empty" ) );
434 pkcs1 = QByteArray( oct_data, oct_len );
441 asn1_delete_structure( &structure );
447 const QString &bundlepass,
451 if ( !QCA::isSupported(
"pkcs12" ) )
453 QgsDebugMsg( QStringLiteral(
"QCA does not support PKCS#12" ) );
458 if ( bundle.isNull() )
460 QgsDebugMsg( QStringLiteral(
"FAILED to convert PKCS#12 file to QCA key bundle: %1" ).arg( bundlepath ) );
464 QCA::SecureArray passarray;
465 if ( reencrypt && !bundlepass.isEmpty() )
467 passarray = QCA::SecureArray( bundlepass.toUtf8() );
471 QSsl::KeyAlgorithm keyalg = QSsl::Opaque;
472 if ( bundle.privateKey().isRSA() )
474 algtype = QStringLiteral(
"rsa" );
477 else if ( bundle.privateKey().isDSA() )
479 algtype = QStringLiteral(
"dsa" );
482 else if ( bundle.privateKey().isDH() )
484 algtype = QStringLiteral(
"dh" );
489 if ( keyalg == QSsl::Opaque )
491 QgsDebugMsg( QStringLiteral(
"FAILED to read PKCS#12 key (only RSA and DSA algorithms supported): %1" ).arg( bundlepath ) );
499 QgsDebugMsgLevel( QStringLiteral(
"Private key is PKCS#8: attempting conversion to PKCS#1..." ), 4 );
504 QByteArray pkcs8Der = bundle.privateKey().toDER().toByteArray();
505 if ( pkcs8Der.isEmpty() )
507 QgsDebugMsg( QStringLiteral(
"FAILED to convert PKCS#12 key to DER-encoded format: %1" ).arg( bundlepath ) );
511 QByteArray pkcs1Der = QgsAuthCertUtils::pkcs8PrivateKey( pkcs8Der );
512 if ( pkcs1Der.isEmpty() )
514 QgsDebugMsg( QStringLiteral(
"FAILED to convert PKCS#12 key from PKCS#8 to PKCS#1: %1" ).arg( bundlepath ) );
518 QSslKey pkcs1Key( pkcs1Der, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey );
519 if ( pkcs1Key.isNull() )
521 QgsDebugMsg( QStringLiteral(
"FAILED to convert PKCS#12 key from PKCS#8 to PKCS#1 QSslKey: %1" ).arg( bundlepath ) );
524 keyPem = QString( pkcs1Key.toPem( passarray.toByteArray() ) );
528 keyPem = bundle.privateKey().toPEM( passarray );
531 keyPem = bundle.privateKey().toPEM( passarray );
534 QgsDebugMsgLevel( QStringLiteral(
"PKCS#12 cert as PEM:\n%1" ).arg( QString( bundle.certificateChain().primary().toPEM() ) ), 4 );
538 return QStringList() << bundle.certificateChain().primary().toPEM() << keyPem << algtype;
543 QList<QSslCertificate> result;
544 if ( !QCA::isSupported(
"pkcs12" ) )
548 if ( bundle.isNull() )
551 const QCA::CertificateChain chain( bundle.certificateChain() );
552 for (
const auto &cert : chain )
556 result.append( QSslCertificate::fromData( cert.toPEM().toLatin1() ) );
565 if ( !certs.isEmpty() )
567 QStringList certslist;
568 for (
const auto &cert : certs )
570 certslist << cert.toPem();
572 capem = certslist.join( QLatin1Char(
'\n' ) ).toLatin1();
579 QFile pemFile( QDir::tempPath() + QDir::separator() + name );
580 QString pemFilePath( pemFile.fileName() );
582 if ( pemFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
584 const qint64 bytesWritten = pemFile.write( pemtext );
585 if ( bytesWritten == -1 )
587 QgsDebugMsg( QStringLiteral(
"FAILED to write to temp PEM file: %1" ).arg( pemFilePath ) );
593 QgsDebugMsg( QStringLiteral(
"FAILED to open writing for temp PEM file: %1" ).arg( pemFilePath ) );
597 if ( !pemFile.setPermissions( QFile::ReadUser ) )
599 QgsDebugMsg( QStringLiteral(
"FAILED to set permissions on temp PEM file: %1" ).arg( pemFilePath ) );
611 return single ? QObject::tr(
"System Root CA" ) : QObject::tr(
"System Root Authorities" );
613 return single ? QObject::tr(
"File CA" ) : QObject::tr(
"Authorities from File" );
615 return single ? QObject::tr(
"Database CA" ) : QObject::tr(
"Authorities in Database" );
617 return single ? QObject::tr(
"Connection CA" ) : QObject::tr(
"Authorities from connection" );
625 QString name( issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::CommonName )
628 if ( name.isEmpty() )
629 name = issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::OrganizationalUnitName )
632 if ( name.isEmpty() )
636 if ( name.isEmpty() )
640 if ( name.isEmpty() )
641 name = issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::StateOrProvinceName )
644 if ( name.isEmpty() )
652void QgsAuthCertUtils::appendDirSegment_( QStringList &dirname,
653 const QString &
segment, QString value )
655 if ( !value.isEmpty() )
657 dirname.append(
segment +
'=' + value.replace(
',', QLatin1String(
"\\," ) ) );
661QSsl::EncodingFormat QgsAuthCertUtils::sniffEncoding(
const QByteArray &payload )
663 return payload.contains( QByteArrayLiteral(
"-----BEGIN " ) ) ?
669 const QCA::Certificate &acert,
675 if ( acert.isNull() )
677 QCA::ConvertResult res;
678 const QCA::Certificate acert( QCA::Certificate::fromPEM( qcert.toPem(), &res, QStringLiteral(
"qca-ossl" ) ) );
679 if ( res != QCA::ConvertGood || acert.isNull() )
681 QgsDebugMsg( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
693 QgsAuthCertUtils::appendDirSegment_(
694 dirname, QStringLiteral(
"E" ), issuer ? acert.issuerInfo().value( QCA::Email )
695 : acert.subjectInfo().value( QCA::Email ) );
696 QgsAuthCertUtils::appendDirSegment_(
697 dirname, QStringLiteral(
"CN" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::CommonName )
699 QgsAuthCertUtils::appendDirSegment_(
700 dirname, QStringLiteral(
"OU" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::OrganizationalUnitName )
702 QgsAuthCertUtils::appendDirSegment_(
703 dirname, QStringLiteral(
"O" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::Organization )
705 QgsAuthCertUtils::appendDirSegment_(
706 dirname, QStringLiteral(
"L" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::LocalityName )
708 QgsAuthCertUtils::appendDirSegment_(
709 dirname, QStringLiteral(
"ST" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::StateOrProvinceName )
711 QgsAuthCertUtils::appendDirSegment_(
712 dirname, QStringLiteral(
"C" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::CountryName )
715 return dirname.join( QLatin1Char(
',' ) );
723 return QObject::tr(
"Default" );
725 return QObject::tr(
"Trusted" );
727 return QObject::tr(
"Untrusted" );
738 sl.reserve( txt.size() );
739 for (
int i = 0; i < txt.size(); i += 2 )
741 sl << txt.mid( i, ( i + 2 > txt.size() ) ? -1 : 2 );
743 return sl.join( QLatin1Char(
':' ) );
748 QString sha( cert.digest( QCryptographicHash::Sha1 ).toHex() );
759 return QCA::Certificate();
761 QCA::ConvertResult res;
762 QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.toPem(), &res, QStringLiteral(
"qca-ossl" ) ) );
763 if ( res != QCA::ConvertGood || qcacert.isNull() )
765 QgsDebugMsg( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
766 qcacert = QCA::Certificate();
773 QCA::CertificateCollection qcacoll;
777 for (
const auto &cert : certs )
780 if ( !qcacert.isNull() )
782 qcacoll.addCertificate( qcacert );
790 QCA::SecureArray passarray;
791 if ( !pass.isEmpty() )
792 passarray = QCA::SecureArray( pass.toUtf8() );
794 QCA::ConvertResult res;
795 const QCA::KeyBundle bundle( QCA::KeyBundle::fromFile( path, passarray, &res, QStringLiteral(
"qca-ossl" ) ) );
797 return ( res == QCA::ConvertGood ? bundle : QCA::KeyBundle() );
804 case QCA::ValidityGood:
805 return QObject::tr(
"Certificate is valid." );
806 case QCA::ErrorRejected:
807 return QObject::tr(
"Root CA rejected the certificate purpose." );
808 case QCA::ErrorUntrusted:
809 return QObject::tr(
"Certificate is not trusted." );
810 case QCA::ErrorSignatureFailed:
811 return QObject::tr(
"Signature does not match." );
812 case QCA::ErrorInvalidCA:
813 return QObject::tr(
"Certificate Authority is invalid or not found." );
814 case QCA::ErrorInvalidPurpose:
815 return QObject::tr(
"Purpose does not match the intended usage." );
816 case QCA::ErrorSelfSigned:
817 return QObject::tr(
"Certificate is self-signed, and is not found in the list of trusted certificates." );
818 case QCA::ErrorRevoked:
819 return QObject::tr(
"Certificate has been revoked." );
820 case QCA::ErrorPathLengthExceeded:
821 return QObject::tr(
"Path length from the root CA to this certificate is too long." );
822 case QCA::ErrorExpired:
823 return QObject::tr(
"Certificate has expired or is not yet valid." );
824 case QCA::ErrorExpiredCA:
825 return QObject::tr(
"Certificate Authority has expired." );
826 case QCA::ErrorValidityUnknown:
827 return QObject::tr(
"Validity is unknown." );
837 case QCA::EMSA1_SHA1:
838 return QObject::tr(
"SHA1, with EMSA1" );
839 case QCA::EMSA3_SHA1:
840 return QObject::tr(
"SHA1, with EMSA3" );
842 return QObject::tr(
"MD5, with EMSA3" );
844 return QObject::tr(
"MD2, with EMSA3" );
845 case QCA::EMSA3_RIPEMD160:
846 return QObject::tr(
"RIPEMD160, with EMSA3" );
848 return QObject::tr(
"EMSA3, without digest" );
849#if QCA_VERSION >= 0x020100
850 case QCA::EMSA3_SHA224:
851 return QObject::tr(
"SHA224, with EMSA3" );
852 case QCA::EMSA3_SHA256:
853 return QObject::tr(
"SHA256, with EMSA3" );
854 case QCA::EMSA3_SHA384:
855 return QObject::tr(
"SHA384, with EMSA3" );
856 case QCA::EMSA3_SHA512:
857 return QObject::tr(
"SHA512, with EMSA3" );
860 return QObject::tr(
"Unknown (possibly Elliptic Curve)" );
866 switch ( constraint )
868 case QCA::DigitalSignature:
869 return QObject::tr(
"Digital Signature" );
870 case QCA::NonRepudiation:
871 return QObject::tr(
"Non-repudiation" );
872 case QCA::KeyEncipherment:
873 return QObject::tr(
"Key Encipherment" );
874 case QCA::DataEncipherment:
875 return QObject::tr(
"Data Encipherment" );
876 case QCA::KeyAgreement:
877 return QObject::tr(
"Key Agreement" );
878 case QCA::KeyCertificateSign:
879 return QObject::tr(
"Key Certificate Sign" );
881 return QObject::tr(
"CRL Sign" );
882 case QCA::EncipherOnly:
883 return QObject::tr(
"Encipher Only" );
884 case QCA::DecipherOnly:
885 return QObject::tr(
"Decipher Only" );
886 case QCA::ServerAuth:
887 return QObject::tr(
"Server Authentication" );
888 case QCA::ClientAuth:
889 return QObject::tr(
"Client Authentication" );
890 case QCA::CodeSigning:
891 return QObject::tr(
"Code Signing" );
892 case QCA::EmailProtection:
893 return QObject::tr(
"Email Protection" );
894 case QCA::IPSecEndSystem:
895 return QObject::tr(
"IPSec Endpoint" );
896 case QCA::IPSecTunnel:
897 return QObject::tr(
"IPSec Tunnel" );
899 return QObject::tr(
"IPSec User" );
900 case QCA::TimeStamping:
901 return QObject::tr(
"Time Stamping" );
902 case QCA::OCSPSigning:
903 return QObject::tr(
"OCSP Signing" );
914 return QObject::tr(
"Any or unspecified" );
916 return QObject::tr(
"Certificate Authority" );
918 return QObject::tr(
"Certificate Issuer" );
920 return QObject::tr(
"TLS/SSL Server" );
922 return QObject::tr(
"TLS/SSL Server EV" );
924 return QObject::tr(
"TLS/SSL Client" );
926 return QObject::tr(
"Code Signing" );
928 return QObject::tr(
"Email Protection" );
930 return QObject::tr(
"Time Stamping" );
932 return QObject::tr(
"CRL Signing" );
935 return QObject::tr(
"Undetermined usage" );
941 QList<QgsAuthCertUtils::CertUsageType> usages;
946 QCA::ConvertResult res;
947 const QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.toPem(), &res, QStringLiteral(
"qca-ossl" ) ) );
948 if ( res != QCA::ConvertGood || qcacert.isNull() )
950 QgsDebugMsg( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
954 if ( qcacert.isCA() )
956 QgsDebugMsg( QStringLiteral(
"Certificate has 'CA:TRUE' basic constraint" ) );
960 const QList<QCA::ConstraintType> certconsts = qcacert.constraints();
961 for (
const auto &certconst : certconsts )
963 if ( certconst.known() == QCA::KeyCertificateSign )
965 QgsDebugMsg( QStringLiteral(
"Certificate has 'Certificate Sign' key usage" ) );
968 else if ( certconst.known() == QCA::ServerAuth )
970 QgsDebugMsg( QStringLiteral(
"Certificate has 'server authentication' extended key usage" ) );
976 const QCA::CertificateCollection trustedCAs(
978 const QCA::CertificateCollection untrustedCAs(
982 v_any = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageAny, QCA::ValidateAll );
983 if ( v_any == QCA::ValidityGood )
988 QCA::Validity v_tlsserver;
989 v_tlsserver = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageTLSServer, QCA::ValidateAll );
990 if ( v_tlsserver == QCA::ValidityGood )
1000 QCA::Validity v_tlsclient;
1001 v_tlsclient = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageTLSClient, QCA::ValidateAll );
1003 if ( v_tlsclient == QCA::ValidityGood )
1046 QCA::ConvertResult res;
1047 QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.toPem(), &res, QString(
"qca-ossl" ) ) );
1048 if ( res != QCA::ConvertGood || qcacert.isNull() )
1050 QgsDebugMsg( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
1054 if ( qcacert.isCA() )
1056 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'CA:TRUE' basic constraint (and should not)" ) );
1060 const QList<QCA::ConstraintType> certconsts = qcacert.constraints();
1061 for (
const auto & certconst, certconsts )
1063 if ( certconst.known() == QCA::KeyCertificateSign )
1065 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'Certificate Sign' key usage (and should not)" ) );
1072 bool serverauth =
false;
1073 bool dsignature =
false;
1074 bool keyencrypt =
false;
1075 for (
const auto &certconst : certconsts )
1077 if ( certconst.known() == QCA::DigitalSignature )
1079 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'digital signature' key usage" ) );
1082 else if ( certconst.known() == QCA::KeyEncipherment )
1084 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'key encipherment' key usage" ) );
1087 else if ( certconst.known() == QCA::KeyAgreement )
1089 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'key agreement' key usage" ) );
1092 else if ( certconst.known() == QCA::ServerAuth )
1094 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'server authentication' extended key usage" ) );
1106 if ( serverauth && dsignature && keyencrypt )
1110 if ( dsignature && keyencrypt )
1116 bool keyagree =
false;
1117 bool encipheronly =
false;
1118 bool decipheronly =
false;
1120 QCA::PublicKey pubkey( qcacert.subjectPublicKey() );
1122 if ( pubkey.bitSize() > 0 && pubkey.isDH() )
1124 keyagree = pubkey.canKeyAgree();
1129 for (
const auto &certconst : certconsts )
1131 if ( certconst.known() == QCA::EncipherOnly )
1133 QgsDebugMsg( QStringLiteral(
"SSL server public key has 'encipher only' key usage" ) );
1134 encipheronly =
true;
1136 else if ( certconst.known() == QCA::DecipherOnly )
1138 QgsDebugMsg( QStringLiteral(
"SSL server public key has 'decipher only' key usage" ) );
1139 decipheronly =
true;
1142 if ( !encipheronly && !decipheronly )
1160 case QSslError::UnableToGetIssuerCertificate:
1161 return QObject::tr(
"Unable to Get Issuer Certificate" );
1162 case QSslError::UnableToDecryptCertificateSignature:
1163 return QObject::tr(
"Unable to Decrypt Certificate Signature" );
1164 case QSslError::UnableToDecodeIssuerPublicKey:
1165 return QObject::tr(
"Unable to Decode Issuer Public Key" );
1166 case QSslError::CertificateSignatureFailed:
1167 return QObject::tr(
"Certificate Signature Failed" );
1168 case QSslError::CertificateNotYetValid:
1169 return QObject::tr(
"Certificate Not Yet Valid" );
1170 case QSslError::CertificateExpired:
1171 return QObject::tr(
"Certificate Expired" );
1172 case QSslError::InvalidNotBeforeField:
1173 return QObject::tr(
"Invalid Not Before Field" );
1174 case QSslError::InvalidNotAfterField:
1175 return QObject::tr(
"Invalid Not After Field" );
1176 case QSslError::SelfSignedCertificate:
1177 return QObject::tr(
"Self-signed Certificate" );
1178 case QSslError::SelfSignedCertificateInChain:
1179 return QObject::tr(
"Self-signed Certificate In Chain" );
1180 case QSslError::UnableToGetLocalIssuerCertificate:
1181 return QObject::tr(
"Unable to Get Local Issuer Certificate" );
1182 case QSslError::UnableToVerifyFirstCertificate:
1183 return QObject::tr(
"Unable to Verify First Certificate" );
1184 case QSslError::CertificateRevoked:
1185 return QObject::tr(
"Certificate Revoked" );
1186 case QSslError::InvalidCaCertificate:
1187 return QObject::tr(
"Invalid CA Certificate" );
1188 case QSslError::PathLengthExceeded:
1189 return QObject::tr(
"Path Length Exceeded" );
1190 case QSslError::InvalidPurpose:
1191 return QObject::tr(
"Invalid Purpose" );
1192 case QSslError::CertificateUntrusted:
1193 return QObject::tr(
"Certificate Untrusted" );
1194 case QSslError::CertificateRejected:
1195 return QObject::tr(
"Certificate Rejected" );
1196 case QSslError::SubjectIssuerMismatch:
1197 return QObject::tr(
"Subject Issuer Mismatch" );
1198 case QSslError::AuthorityIssuerSerialNumberMismatch:
1199 return QObject::tr(
"Authority Issuer Serial Number Mismatch" );
1200 case QSslError::NoPeerCertificate:
1201 return QObject::tr(
"No Peer Certificate" );
1202 case QSslError::HostNameMismatch:
1203 return QObject::tr(
"Host Name Mismatch" );
1204 case QSslError::UnspecifiedError:
1205 return QObject::tr(
"Unspecified Error" );
1206 case QSslError::CertificateBlacklisted:
1207 return QObject::tr(
"Certificate Blacklisted" );
1208 case QSslError::NoError:
1209 return QObject::tr(
"No Error" );
1210 case QSslError::NoSslSupport:
1211 return QObject::tr(
"No SSL Support" );
1219 QList<QPair<QSslError::SslError, QString> > errenums;
1220 errenums << qMakePair( QSslError::UnableToGetIssuerCertificate,
1222 errenums << qMakePair( QSslError::UnableToDecryptCertificateSignature,
1224 errenums << qMakePair( QSslError::UnableToDecodeIssuerPublicKey,
1226 errenums << qMakePair( QSslError::CertificateSignatureFailed,
1228 errenums << qMakePair( QSslError::CertificateNotYetValid,
1230 errenums << qMakePair( QSslError::CertificateExpired,
1232 errenums << qMakePair( QSslError::InvalidNotBeforeField,
1234 errenums << qMakePair( QSslError::InvalidNotAfterField,
1236 errenums << qMakePair( QSslError::SelfSignedCertificate,
1238 errenums << qMakePair( QSslError::SelfSignedCertificateInChain,
1240 errenums << qMakePair( QSslError::UnableToGetLocalIssuerCertificate,
1242 errenums << qMakePair( QSslError::UnableToVerifyFirstCertificate,
1244 errenums << qMakePair( QSslError::CertificateRevoked,
1246 errenums << qMakePair( QSslError::InvalidCaCertificate,
1248 errenums << qMakePair( QSslError::PathLengthExceeded,
1250 errenums << qMakePair( QSslError::InvalidPurpose,
1252 errenums << qMakePair( QSslError::CertificateUntrusted,
1254 errenums << qMakePair( QSslError::CertificateRejected,
1256 errenums << qMakePair( QSslError::SubjectIssuerMismatch,
1258 errenums << qMakePair( QSslError::AuthorityIssuerSerialNumberMismatch,
1260 errenums << qMakePair( QSslError::NoPeerCertificate,
1262 errenums << qMakePair( QSslError::HostNameMismatch,
1264 errenums << qMakePair( QSslError::UnspecifiedError,
1266 errenums << qMakePair( QSslError::CertificateBlacklisted,
1273 if ( cert.isNull() )
1275 const QDateTime currentTime = QDateTime::currentDateTime();
1276 return cert.effectiveDate() <= currentTime && cert.expiryDate() >= currentTime;
1281 QList<QSslError> sslErrors;
1283 if ( cert.isNull() )
1286 const QDateTime currentTime = QDateTime::currentDateTime();
1287 if ( cert.expiryDate() <= currentTime )
1289 sslErrors << QSslError( QSslError::SslError::CertificateExpired, cert );
1291 if ( cert.effectiveDate() >= QDateTime::currentDateTime() )
1293 sslErrors << QSslError( QSslError::SslError::CertificateNotYetValid, cert );
1295 if ( cert.isBlacklisted() )
1297 sslErrors << QSslError( QSslError::SslError::CertificateBlacklisted, cert );
1309 const QString &hostName,
1312 QList<QSslError> sslErrors;
1313 QList<QSslCertificate> trustedChain;
1315 for (
const auto &cert : certificateChain )
1317 bool untrusted =
false;
1320 if ( cert.digest( ) == untrustedCert.digest( ) )
1328 trustedChain << cert;
1333 const QList<QSslCertificate> constTrustedChain( trustedChain );
1334 for (
const auto &cert : constTrustedChain )
1340 if ( trustRootCa && trustedChain.count() > 1 && trustedChain.last().isSelfSigned() )
1342 static QMutex sMutex;
1343 const QMutexLocker lock( &sMutex );
1344 const QSslConfiguration oldSslConfig( QSslConfiguration::defaultConfiguration() );
1345 QSslConfiguration sslConfig( oldSslConfig );
1346 sslConfig.setCaCertificates(
casMerge( sslConfig.caCertificates(), QList<QSslCertificate>() << trustedChain.last() ) );
1347 QSslConfiguration::setDefaultConfiguration( sslConfig );
1348 sslErrors = QSslCertificate::verify( trustedChain, hostName );
1349 QSslConfiguration::setDefaultConfiguration( oldSslConfig );
1353 sslErrors = QSslCertificate::verify( trustedChain, hostName );
1362 errors << QObject::tr(
"Client certificate is NULL." );
1365 errors << QObject::tr(
"Client certificate key is NULL." );
1368 if ( !errors.isEmpty() )
1371 QList<QSslError> sslErrors;
1372 if ( useIntermediates )
1374 QList<QSslCertificate> certsList( bundle.
caChain() );
1380 sslErrors = QSslCertificate::verify( QList<QSslCertificate>() << bundle.
clientCert() );
1382 const QList<QSslError> constSslErrors( sslErrors );
1383 for (
const auto &sslError : constSslErrors )
1385 if ( sslError.error() != QSslError::NoError )
1387 errors << sslError.errorString();
1391 const QCA::PrivateKey pvtKey( QCA::PrivateKey::fromPEM( bundle.
clientKey().toPem() ) );
1392 const QCA::PublicKey pubKey( QCA::PublicKey::fromPEM( bundle.
clientCert().publicKey().toPem( ) ) );
1393 bool keyValid( ! pvtKey.isNull() );
1394 if ( keyValid && !( pubKey.toRSA().isNull( ) || pvtKey.toRSA().isNull( ) ) )
1396 keyValid = pubKey.toRSA().n() == pvtKey.toRSA().n();
1398 else if ( keyValid && !( pubKey.toDSA().isNull( ) || pvtKey.toDSA().isNull( ) ) )
1400 keyValid = pubKey == QCA::DSAPublicKey( pvtKey.toDSA() );
1404 QgsDebugMsg( QStringLiteral(
"Key is not DSA, RSA: validation is not supported by QCA" ) );
1408 errors << QObject::tr(
"Private key does not match client certificate public key." );
static QString pkgDataPath()
Returns the common root path of all application data directories.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static QString sslErrorEnumString(QSslError::SslError errenum)
Gets short strings describing an SSL error.
static QString qcaValidityMessage(QCA::Validity validity)
Certificate validity check messages per enum.
static QByteArray fileData(const QString &path)
Returns data from a local file via a read-only operation.
static QList< QgsAuthCertUtils::CertUsageType > certificateUsageTypes(const QSslCertificate &cert)
Try to determine the certificates usage types.
static QString qcaSignatureAlgorithm(QCA::SignatureAlgorithm algorithm)
Certificate signature algorithm strings per enum.
static QString resolvedCertName(const QSslCertificate &cert, bool issuer=false)
Gets the general name via RFC 5280 resolution.
static QCA::Certificate qtCertToQcaCert(const QSslCertificate &cert)
Convert a QSslCertificate to a QCA::Certificate.
static QMap< QString, QList< QSslCertificate > > certsGroupedByOrg(const QList< QSslCertificate > &certs)
Map certificates to their oraganization.
static QString certificateUsageTypeString(QgsAuthCertUtils::CertUsageType usagetype)
Certificate usage type strings per enum.
static QString getCertTrustName(QgsAuthCertUtils::CertTrustPolicy trust)
Gets the general name for certificate trust.
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Gets the sha1 hash for certificate.
static QCA::CertificateCollection qtCertsToQcaCollection(const QList< QSslCertificate > &certs)
Convert a QList of QSslCertificate to a QCA::CertificateCollection.
CertTrustPolicy
Type of certificate trust policy.
static QSslCertificate certFromFile(const QString &certpath)
Returns the first cert from a PEM or DER formatted file.
static QString qcaKnownConstraint(QCA::ConstraintTypeKnown constraint)
Certificate well-known constraint strings per enum.
static QMap< QString, QSslCertificate > mapDigestToCerts(const QList< QSslCertificate > &certs)
Map certificate sha1 to certificate as simple cache.
static QList< QSslCertificate > casMerge(const QList< QSslCertificate > &bundle1, const QList< QSslCertificate > &bundle2)
casMerge merges two certificate bundles in a single one removing duplicates, the certificates from th...
static QByteArray certsToPemText(const QList< QSslCertificate > &certs)
certsToPemText dump a list of QSslCertificates to PEM text
static QString getSslProtocolName(QSsl::SslProtocol protocol)
SSL Protocol name strings per enum.
static bool certIsViable(const QSslCertificate &cert)
certIsViable checks for viability errors of cert and whether it is NULL
static QStringList certKeyBundleToPem(const QString &certpath, const QString &keypath, const QString &keypass=QString(), bool reencrypt=true)
Returns list of certificate, private key and algorithm (as PEM text) from file path components.
static QString getColonDelimited(const QString &txt)
Gets string with colon delimiters every 2 characters.
static bool certificateIsAuthority(const QSslCertificate &cert)
Gets whether a certificate is an Authority.
static QStringList pkcs12BundleToPem(const QString &bundlepath, const QString &bundlepass=QString(), bool reencrypt=true)
Returns list of certificate, private key and algorithm (as PEM text) for a PKCS#12 bundle.
static QMap< QString, QList< QgsAuthConfigSslServer > > sslConfigsGroupedByOrg(const QList< QgsAuthConfigSslServer > &configs)
Map SSL custom configs' certificates to their oraganization.
static QList< QSslCertificate > certsFromFile(const QString &certspath)
Returns a list of concatenated certs from a PEM or DER formatted file.
static bool certificateIsAuthorityOrIssuer(const QSslCertificate &cert)
Gets whether a certificate is an Authority or can at least sign other certificates.
static QList< QSslCertificate > casRemoveSelfSigned(const QList< QSslCertificate > &caList)
casRemoveSelfSigned remove self-signed CA certificates from caList
static bool certificateIsIssuer(const QSslCertificate &cert)
Gets whether a certificate can sign other certificates.
static bool certificateIsSslClient(const QSslCertificate &cert)
Gets whether a certificate is probably used for a client identity.
static QSslKey keyFromFile(const QString &keypath, const QString &keypass=QString(), QString *algtype=nullptr)
Returns non-encrypted key from a PEM or DER formatted file.
static bool certificateIsSslServer(const QSslCertificate &cert)
Gets whether a certificate is probably used for a SSL server.
static QList< QSslCertificate > casFromFile(const QString &certspath)
Returns a list of concatenated CAs from a PEM or DER formatted file.
static QList< QSslCertificate > certsFromString(const QString &pemtext)
Returns a list of concatenated certs from a PEM Base64 text block.
static bool certIsCurrent(const QSslCertificate &cert)
certIsCurrent checks if cert is viable for its not before and not after dates
CertUsageType
Type of certificate usage.
CaCertSource
Type of CA certificate source.
static QList< QSslCertificate > pkcs12BundleCas(const QString &bundlepath, const QString &bundlepass=QString())
Returns list of CA certificates (as QSslCertificate) for a PKCS#12 bundle.
static QCA::KeyBundle qcaKeyBundle(const QString &path, const QString &pass)
PKI key/cert bundle from file path, e.g.
static QString getCaSourceName(QgsAuthCertUtils::CaCertSource source, bool single=false)
Gets the general name for CA source enum type.
static QString pemTextToTempFile(const QString &name, const QByteArray &pemtext)
Write a temporary file for a PEM text of cert/key/CAs bundle component.
static bool pemIsPkcs8(const QString &keyPemTxt)
Determine if the PEM-encoded text of a key is PKCS#8 format.
static QMap< QString, QgsAuthConfigSslServer > mapDigestToSslConfigs(const QList< QgsAuthConfigSslServer > &configs)
Map SSL custom configs' certificate sha1 to custom config as simple cache.
static QList< QSslError > validateCertChain(const QList< QSslCertificate > &certificateChain, const QString &hostName=QString(), bool trustRootCa=false)
validateCertChain validates the given certificateChain
static QList< QPair< QSslError::SslError, QString > > sslErrorEnumStrings()
Gets short strings describing SSL errors.
static QString getCertDistinguishedName(const QSslCertificate &qcert, const QCA::Certificate &acert=QCA::Certificate(), bool issuer=false)
Gets combined distinguished name for certificate.
static QStringList validatePKIBundle(QgsPkiBundle &bundle, bool useIntermediates=true, bool trustRootCa=false)
validatePKIBundle validate the PKI bundle by checking the certificate chain, the expiration and effec...
static QList< QSslError > certViabilityErrors(const QSslCertificate &cert)
certViabilityErrors checks basic characteristics (validity dates, blocklisting, etc....
static int debugLevel()
Reads the environment variable QGIS_DEBUG and converts it to int.
Storage set for PKI bundle: SSL certificate, key, optional CA cert chain.
const QSslKey clientKey() const
Private key object.
const QList< QSslCertificate > caChain() const
Chain of Certificate Authorities for client certificate.
const QSslCertificate clientCert() const
Client certificate object.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
#define SSL_SUBJECT_INFO(var, prop)
#define SSL_ISSUER_INFO(var, prop)
#define QgsDebugMsgLevel(str, level)
QLineF segment(int index, QRectF rect, double radius)