23#include <QSslCertificate>
40 case QSsl::SecureProtocols:
41 return QObject::tr(
"SecureProtocols" );
43 return QObject::tr(
"TlsV1" );
51 QMap<QString, QSslCertificate> digestmap;
52 for (
const auto &cert : certs )
61 QMap< QString, QList<QSslCertificate> > orgcerts;
62 for (
const auto &cert : certs )
66 org = QStringLiteral(
"(Organization not defined)" );
67 QList<QSslCertificate> valist = orgcerts.contains( org ) ? orgcerts.value( org ) : QList<QSslCertificate>();
68 orgcerts.insert( org, valist << cert );
75 QMap<QString, QgsAuthConfigSslServer> digestmap;
76 for (
const auto &config : configs )
78 digestmap.insert(
shaHexForCert( config.sslCertificate() ), config );
85 QMap< QString, QList<QgsAuthConfigSslServer> > orgconfigs;
86 for (
const auto &config : configs )
88 QString org(
SSL_SUBJECT_INFO( config.sslCertificate(), QSslCertificate::Organization ) );
91 org = QObject::tr(
"(Organization not defined)" );
92 QList<QgsAuthConfigSslServer> valist = orgconfigs.contains( org ) ? orgconfigs.value( org ) : QList<QgsAuthConfigSslServer>();
93 orgconfigs.insert( org, valist << config );
102 if ( !file.exists() )
104 QgsDebugError( QStringLiteral(
"Read file error, file not found: %1" ).arg( path ) );
108 const QFile::OpenMode openflags( QIODevice::ReadOnly );
109 const bool ret = file.open( openflags );
112 data = file.readAll();
121 QList<QSslCertificate> certs;
123 certs = QSslCertificate::fromData( payload, sniffEncoding( payload ) );
124 if ( certs.isEmpty() )
126 QgsDebugError( QStringLiteral(
"Parsed cert(s) EMPTY for path: %1" ).arg( certspath ) );
133 QList<QSslCertificate> cas;
134 const QList<QSslCertificate> certs(
certsFromFile( certspath ) );
135 for (
const auto &cert : certs )
148 QList<QSslCertificate> result( bundle1 );
149 const QList<QSslCertificate> c_bundle1( bundle1 );
150 for (
const auto &cert : c_bundle1 )
154 const QList<QSslCertificate> c_bundle2( bundle2 );
155 for (
const auto &cert : c_bundle2 )
159 result.append( cert );
169 QSslCertificate cert;
171 if ( !certs.isEmpty() )
173 cert = certs.first();
177 QgsDebugError( QStringLiteral(
"Parsed cert is NULL for path: %1" ).arg( certpath ) );
183 const QString &keypass,
190 const QSsl::EncodingFormat keyEncoding( sniffEncoding( keydata ) );
192 const std::vector<QSsl::KeyAlgorithm> algs
194 QSsl::KeyAlgorithm::Rsa,
195 QSsl::KeyAlgorithm::Dsa,
196 QSsl::KeyAlgorithm::Ec,
197 QSsl::KeyAlgorithm::Opaque
200 for (
const auto &alg : algs )
202 clientkey = QSslKey( keydata,
206 !keypass.isEmpty() ? keypass.toUtf8() : QByteArray() );
207 if ( ! clientkey.isNull() )
213 case QSsl::KeyAlgorithm::Rsa:
214 *algtype = QStringLiteral(
"rsa" );
216 case QSsl::KeyAlgorithm::Dsa:
217 *algtype = QStringLiteral(
"dsa" );
219 case QSsl::KeyAlgorithm::Ec:
220 *algtype = QStringLiteral(
"ec" );
222 case QSsl::KeyAlgorithm::Opaque:
223 *algtype = QStringLiteral(
"opaque" );
225 case QSsl::KeyAlgorithm::Dh:
226 *algtype = QStringLiteral(
"dh" );
238 QList<QSslCertificate> certs;
239 certs = QSslCertificate::fromData( pemtext.toLatin1(), QSsl::Pem );
240 if ( certs.isEmpty() )
249 QList<QSslCertificate> certs;
250 for (
const auto &cert : caList )
252 if ( ! cert.isSelfSigned( ) )
254 certs.append( cert );
261 const QString &keypath,
262 const QString &keypass,
267 if ( !clientcert.isNull() )
269 certpem = QString( clientcert.toPem() );
277 if ( !clientkey.isNull() )
279 keypem = QString( clientkey.toPem( ( reencrypt && !keypass.isEmpty() ) ? keypass.toUtf8() : QByteArray() ) );
282 return QStringList() << certpem << keypem << algtype;
287 const QString pkcs8Header = QStringLiteral(
"-----BEGIN PRIVATE KEY-----" );
288 const QString pkcs8Footer = QStringLiteral(
"-----END PRIVATE KEY-----" );
289 return keyPemTxt.contains( pkcs8Header ) && keyPemTxt.contains( pkcs8Footer );
293QByteArray QgsAuthCertUtils::pkcs8PrivateKey( QByteArray &pkcs8Der )
297 if ( pkcs8Der.isEmpty() )
299 QgsDebugError( QStringLiteral(
"ERROR, passed DER is empty" ) );
306 if ( ! asnDefsRsrc.exists() )
308 QgsDebugError( QStringLiteral(
"ERROR, pkcs.asn resource file not found: %1" ).arg( asnDefsRsrc.filePath() ) );
311 const char *asnDefsFile = asnDefsRsrc.absoluteFilePath().toLocal8Bit().constData();
313 int asn1_result = ASN1_SUCCESS, der_len = 0, oct_len = 0;
314 asn1_node definitions = NULL, structure = NULL;
315 char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE], oct_data[1024];
316 unsigned char *der = NULL;
317 unsigned int flags = 0;
321 QString
typeName( QStringLiteral(
"PKCS-8.PrivateKeyInfo" ) );
323 asn1_result = asn1_parser2tree( asnDefsFile, &definitions, errorDescription );
325 switch ( asn1_result )
330 case ASN1_FILE_NOT_FOUND:
331 QgsDebugError( QStringLiteral(
"ERROR, file not found: %1" ).arg( asnDefsFile ) );
333 case ASN1_SYNTAX_ERROR:
334 case ASN1_IDENTIFIER_NOT_FOUND:
335 case ASN1_NAME_TOO_LONG:
336 QgsDebugError( QStringLiteral(
"ERROR, asn1 parsing: %1" ).arg( errorDescription ) );
339 QgsDebugError( QStringLiteral(
"ERROR, libtasn1: %1" ).arg( asn1_strerror( asn1_result ) ) );
344 asn1_result = asn1_create_element( definitions,
typeName.toLatin1().constData(), &structure );
348 if ( asn1_result != ASN1_SUCCESS )
350 QgsDebugError( QStringLiteral(
"ERROR, structure creation: %1" ).arg( asn1_strerror( asn1_result ) ) );
355 der =
reinterpret_cast<unsigned char *
>( pkcs8Der.data() );
356 der_len = pkcs8Der.size();
360 asn1_result = asn1_der_decoding2( &structure, der, &der_len, flags, errorDescription );
364 asn1_result = asn1_der_decoding( &structure, der, der_len, errorDescription );
367 if ( asn1_result != ASN1_SUCCESS )
369 QgsDebugError( QStringLiteral(
"ERROR, decoding: %1" ).arg( errorDescription ) );
374 QgsDebugMsgLevel( QStringLiteral(
"Decoding: %1" ).arg( asn1_strerror( asn1_result ) ), 4 );
380 asn1_print_structure( stdout, structure,
"", ASN1_PRINT_NAME_TYPE_VALUE );
385 typeName.append( QStringLiteral(
".privateKey" ) );
388 asn1_result = asn1_read_value_type( structure,
"privateKey", NULL, &oct_len, &oct_etype );
390 if ( asn1_result != ASN1_MEM_ERROR )
392 QgsDebugError( QStringLiteral(
"ERROR, asn1 read privateKey value type: %1" ).arg( asn1_strerror( asn1_result ) ) );
396 if ( oct_etype != ASN1_ETYPE_OCTET_STRING )
398 QgsDebugError( QStringLiteral(
"ERROR, asn1 privateKey value not octet string, but type: %1" ).arg(
static_cast<int>( oct_etype ) ) );
404 QgsDebugError( QStringLiteral(
"ERROR, asn1 privateKey octet string empty" ) );
409 asn1_result = asn1_read_value( structure,
"privateKey", oct_data, &oct_len );
411 if ( asn1_result != ASN1_SUCCESS )
413 QgsDebugError( QStringLiteral(
"ERROR, asn1 read privateKey value: %1" ).arg( asn1_strerror( asn1_result ) ) );
419 QgsDebugError( QStringLiteral(
"ERROR, asn1 privateKey value octet string empty" ) );
423 pkcs1 = QByteArray( oct_data, oct_len );
430 asn1_delete_structure( &structure );
436 const QString &bundlepass,
440 if ( !QCA::isSupported(
"pkcs12" ) )
442 QgsDebugError( QStringLiteral(
"QCA does not support PKCS#12" ) );
447 if ( bundle.isNull() )
449 QgsDebugError( QStringLiteral(
"FAILED to convert PKCS#12 file to QCA key bundle: %1" ).arg( bundlepath ) );
453 QCA::SecureArray passarray;
454 if ( reencrypt && !bundlepass.isEmpty() )
456 passarray = QCA::SecureArray( bundlepass.toUtf8() );
460 QSsl::KeyAlgorithm keyalg = QSsl::Opaque;
461 if ( bundle.privateKey().isRSA() )
463 algtype = QStringLiteral(
"rsa" );
466 else if ( bundle.privateKey().isDSA() )
468 algtype = QStringLiteral(
"dsa" );
471 else if ( bundle.privateKey().isDH() )
473 algtype = QStringLiteral(
"dh" );
478 if ( keyalg == QSsl::Opaque )
480 QgsDebugError( QStringLiteral(
"FAILED to read PKCS#12 key (only RSA and DSA algorithms supported): %1" ).arg( bundlepath ) );
488 QgsDebugMsgLevel( QStringLiteral(
"Private key is PKCS#8: attempting conversion to PKCS#1..." ), 4 );
493 QByteArray pkcs8Der = bundle.privateKey().toDER().toByteArray();
494 if ( pkcs8Der.isEmpty() )
496 QgsDebugError( QStringLiteral(
"FAILED to convert PKCS#12 key to DER-encoded format: %1" ).arg( bundlepath ) );
500 QByteArray pkcs1Der = QgsAuthCertUtils::pkcs8PrivateKey( pkcs8Der );
501 if ( pkcs1Der.isEmpty() )
503 QgsDebugError( QStringLiteral(
"FAILED to convert PKCS#12 key from PKCS#8 to PKCS#1: %1" ).arg( bundlepath ) );
507 QSslKey pkcs1Key( pkcs1Der, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey );
508 if ( pkcs1Key.isNull() )
510 QgsDebugError( QStringLiteral(
"FAILED to convert PKCS#12 key from PKCS#8 to PKCS#1 QSslKey: %1" ).arg( bundlepath ) );
513 keyPem = QString( pkcs1Key.toPem( passarray.toByteArray() ) );
517 keyPem = bundle.privateKey().toPEM( passarray );
520 keyPem = bundle.privateKey().toPEM( passarray );
523 QgsDebugMsgLevel( QStringLiteral(
"PKCS#12 cert as PEM:\n%1" ).arg( QString( bundle.certificateChain().primary().toPEM() ) ), 4 );
527 return QStringList() << bundle.certificateChain().primary().toPEM() << keyPem << algtype;
532 QList<QSslCertificate> result;
533 if ( !QCA::isSupported(
"pkcs12" ) )
537 if ( bundle.isNull() )
540 const QCA::CertificateChain chain( bundle.certificateChain() );
541 for (
const auto &cert : chain )
545 result.append( QSslCertificate::fromData( cert.toPEM().toLatin1() ) );
554 if ( !certs.isEmpty() )
556 QStringList certslist;
557 for (
const auto &cert : certs )
559 certslist << cert.toPem();
561 capem = certslist.join( QLatin1Char(
'\n' ) ).toLatin1();
568 QFile pemFile( QDir::tempPath() + QDir::separator() + name );
569 QString pemFilePath( pemFile.fileName() );
571 if ( pemFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
573 const qint64 bytesWritten = pemFile.write( pemtext );
574 if ( bytesWritten == -1 )
576 QgsDebugError( QStringLiteral(
"FAILED to write to temp PEM file: %1" ).arg( pemFilePath ) );
582 QgsDebugError( QStringLiteral(
"FAILED to open writing for temp PEM file: %1" ).arg( pemFilePath ) );
586 if ( !pemFile.setPermissions( QFile::ReadUser ) )
588 QgsDebugError( QStringLiteral(
"FAILED to set permissions on temp PEM file: %1" ).arg( pemFilePath ) );
600 return single ? QObject::tr(
"System Root CA" ) : QObject::tr(
"System Root Authorities" );
602 return single ? QObject::tr(
"File CA" ) : QObject::tr(
"Authorities from File" );
604 return single ? QObject::tr(
"Database CA" ) : QObject::tr(
"Authorities in Database" );
606 return single ? QObject::tr(
"Connection CA" ) : QObject::tr(
"Authorities from connection" );
614 QString name( issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::CommonName )
617 if ( name.isEmpty() )
618 name = issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::OrganizationalUnitName )
621 if ( name.isEmpty() )
625 if ( name.isEmpty() )
629 if ( name.isEmpty() )
630 name = issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::StateOrProvinceName )
633 if ( name.isEmpty() )
641void QgsAuthCertUtils::appendDirSegment_( QStringList &dirname,
642 const QString &
segment, QString value )
644 if ( !value.isEmpty() )
646 dirname.append(
segment +
'=' + value.replace(
',', QLatin1String(
"\\," ) ) );
650QSsl::EncodingFormat QgsAuthCertUtils::sniffEncoding(
const QByteArray &payload )
652 return payload.contains( QByteArrayLiteral(
"-----BEGIN " ) ) ?
658 const QCA::Certificate &acert,
664 if ( acert.isNull() )
666 QCA::ConvertResult res;
667 const QCA::Certificate acert( QCA::Certificate::fromPEM( qcert.toPem(), &res, QStringLiteral(
"qca-ossl" ) ) );
668 if ( res != QCA::ConvertGood || acert.isNull() )
670 QgsDebugError( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
682 QgsAuthCertUtils::appendDirSegment_(
683 dirname, QStringLiteral(
"E" ), issuer ? acert.issuerInfo().value( QCA::Email )
684 : acert.subjectInfo().value( QCA::Email ) );
685 QgsAuthCertUtils::appendDirSegment_(
686 dirname, QStringLiteral(
"CN" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::CommonName )
688 QgsAuthCertUtils::appendDirSegment_(
689 dirname, QStringLiteral(
"OU" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::OrganizationalUnitName )
691 QgsAuthCertUtils::appendDirSegment_(
692 dirname, QStringLiteral(
"O" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::Organization )
694 QgsAuthCertUtils::appendDirSegment_(
695 dirname, QStringLiteral(
"L" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::LocalityName )
697 QgsAuthCertUtils::appendDirSegment_(
698 dirname, QStringLiteral(
"ST" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::StateOrProvinceName )
700 QgsAuthCertUtils::appendDirSegment_(
701 dirname, QStringLiteral(
"C" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::CountryName )
704 return dirname.join( QLatin1Char(
',' ) );
712 return QObject::tr(
"Default" );
714 return QObject::tr(
"Trusted" );
716 return QObject::tr(
"Untrusted" );
727 sl.reserve( txt.size() );
728 for (
int i = 0; i < txt.size(); i += 2 )
730 sl << txt.mid( i, ( i + 2 > txt.size() ) ? -1 : 2 );
732 return sl.join( QLatin1Char(
':' ) );
737 QString sha( cert.digest( QCryptographicHash::Sha1 ).toHex() );
748 return QCA::Certificate();
750 QCA::ConvertResult res;
751 QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.toPem(), &res, QStringLiteral(
"qca-ossl" ) ) );
752 if ( res != QCA::ConvertGood || qcacert.isNull() )
754 QgsDebugError( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
755 qcacert = QCA::Certificate();
762 QCA::CertificateCollection qcacoll;
766 for (
const auto &cert : certs )
769 if ( !qcacert.isNull() )
771 qcacoll.addCertificate( qcacert );
779 QCA::SecureArray passarray;
780 if ( !pass.isEmpty() )
781 passarray = QCA::SecureArray( pass.toUtf8() );
783 QCA::ConvertResult res;
784 const QCA::KeyBundle bundle( QCA::KeyBundle::fromFile( path, passarray, &res, QStringLiteral(
"qca-ossl" ) ) );
786 return ( res == QCA::ConvertGood ? bundle : QCA::KeyBundle() );
793 case QCA::ValidityGood:
794 return QObject::tr(
"Certificate is valid." );
795 case QCA::ErrorRejected:
796 return QObject::tr(
"Root CA rejected the certificate purpose." );
797 case QCA::ErrorUntrusted:
798 return QObject::tr(
"Certificate is not trusted." );
799 case QCA::ErrorSignatureFailed:
800 return QObject::tr(
"Signature does not match." );
801 case QCA::ErrorInvalidCA:
802 return QObject::tr(
"Certificate Authority is invalid or not found." );
803 case QCA::ErrorInvalidPurpose:
804 return QObject::tr(
"Purpose does not match the intended usage." );
805 case QCA::ErrorSelfSigned:
806 return QObject::tr(
"Certificate is self-signed, and is not found in the list of trusted certificates." );
807 case QCA::ErrorRevoked:
808 return QObject::tr(
"Certificate has been revoked." );
809 case QCA::ErrorPathLengthExceeded:
810 return QObject::tr(
"Path length from the root CA to this certificate is too long." );
811 case QCA::ErrorExpired:
812 return QObject::tr(
"Certificate has expired or is not yet valid." );
813 case QCA::ErrorExpiredCA:
814 return QObject::tr(
"Certificate Authority has expired." );
815 case QCA::ErrorValidityUnknown:
816 return QObject::tr(
"Validity is unknown." );
826 case QCA::EMSA1_SHA1:
827 return QObject::tr(
"SHA1, with EMSA1" );
828 case QCA::EMSA3_SHA1:
829 return QObject::tr(
"SHA1, with EMSA3" );
831 return QObject::tr(
"MD5, with EMSA3" );
833 return QObject::tr(
"MD2, with EMSA3" );
834 case QCA::EMSA3_RIPEMD160:
835 return QObject::tr(
"RIPEMD160, with EMSA3" );
837 return QObject::tr(
"EMSA3, without digest" );
838#if QCA_VERSION >= 0x020100
839 case QCA::EMSA3_SHA224:
840 return QObject::tr(
"SHA224, with EMSA3" );
841 case QCA::EMSA3_SHA256:
842 return QObject::tr(
"SHA256, with EMSA3" );
843 case QCA::EMSA3_SHA384:
844 return QObject::tr(
"SHA384, with EMSA3" );
845 case QCA::EMSA3_SHA512:
846 return QObject::tr(
"SHA512, with EMSA3" );
849 return QObject::tr(
"Unknown (possibly Elliptic Curve)" );
855 switch ( constraint )
857 case QCA::DigitalSignature:
858 return QObject::tr(
"Digital Signature" );
859 case QCA::NonRepudiation:
860 return QObject::tr(
"Non-repudiation" );
861 case QCA::KeyEncipherment:
862 return QObject::tr(
"Key Encipherment" );
863 case QCA::DataEncipherment:
864 return QObject::tr(
"Data Encipherment" );
865 case QCA::KeyAgreement:
866 return QObject::tr(
"Key Agreement" );
867 case QCA::KeyCertificateSign:
868 return QObject::tr(
"Key Certificate Sign" );
870 return QObject::tr(
"CRL Sign" );
871 case QCA::EncipherOnly:
872 return QObject::tr(
"Encipher Only" );
873 case QCA::DecipherOnly:
874 return QObject::tr(
"Decipher Only" );
875 case QCA::ServerAuth:
876 return QObject::tr(
"Server Authentication" );
877 case QCA::ClientAuth:
878 return QObject::tr(
"Client Authentication" );
879 case QCA::CodeSigning:
880 return QObject::tr(
"Code Signing" );
881 case QCA::EmailProtection:
882 return QObject::tr(
"Email Protection" );
883 case QCA::IPSecEndSystem:
884 return QObject::tr(
"IPSec Endpoint" );
885 case QCA::IPSecTunnel:
886 return QObject::tr(
"IPSec Tunnel" );
888 return QObject::tr(
"IPSec User" );
889 case QCA::TimeStamping:
890 return QObject::tr(
"Time Stamping" );
891 case QCA::OCSPSigning:
892 return QObject::tr(
"OCSP Signing" );
903 return QObject::tr(
"Any or unspecified" );
905 return QObject::tr(
"Certificate Authority" );
907 return QObject::tr(
"Certificate Issuer" );
909 return QObject::tr(
"TLS/SSL Server" );
911 return QObject::tr(
"TLS/SSL Server EV" );
913 return QObject::tr(
"TLS/SSL Client" );
915 return QObject::tr(
"Code Signing" );
917 return QObject::tr(
"Email Protection" );
919 return QObject::tr(
"Time Stamping" );
921 return QObject::tr(
"CRL Signing" );
924 return QObject::tr(
"Undetermined usage" );
930 QList<QgsAuthCertUtils::CertUsageType> usages;
935 QCA::ConvertResult res;
936 const QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.toPem(), &res, QStringLiteral(
"qca-ossl" ) ) );
937 if ( res != QCA::ConvertGood || qcacert.isNull() )
939 QgsDebugError( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
943 if ( qcacert.isCA() )
945 QgsDebugMsgLevel( QStringLiteral(
"Certificate has 'CA:TRUE' basic constraint" ), 2 );
949 const QList<QCA::ConstraintType> certconsts = qcacert.constraints();
950 for (
const auto &certconst : certconsts )
952 if ( certconst.known() == QCA::KeyCertificateSign )
954 QgsDebugMsgLevel( QStringLiteral(
"Certificate has 'Certificate Sign' key usage" ), 2 );
957 else if ( certconst.known() == QCA::ServerAuth )
959 QgsDebugMsgLevel( QStringLiteral(
"Certificate has 'server authentication' extended key usage" ), 2 );
965 const QCA::CertificateCollection trustedCAs(
967 const QCA::CertificateCollection untrustedCAs(
971 v_any = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageAny, QCA::ValidateAll );
972 if ( v_any == QCA::ValidityGood )
977 QCA::Validity v_tlsserver;
978 v_tlsserver = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageTLSServer, QCA::ValidateAll );
979 if ( v_tlsserver == QCA::ValidityGood )
989 QCA::Validity v_tlsclient;
990 v_tlsclient = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageTLSClient, QCA::ValidateAll );
992 if ( v_tlsclient == QCA::ValidityGood )
1035 QCA::ConvertResult res;
1036 QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.toPem(), &res, QString(
"qca-ossl" ) ) );
1037 if ( res != QCA::ConvertGood || qcacert.isNull() )
1039 QgsDebugError( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
1043 if ( qcacert.isCA() )
1045 QgsDebugMsgLevel( QStringLiteral(
"SSL server certificate has 'CA:TRUE' basic constraint (and should not)" ), 2 );
1049 const QList<QCA::ConstraintType> certconsts = qcacert.constraints();
1050 for (
const auto & certconst, certconsts )
1052 if ( certconst.known() == QCA::KeyCertificateSign )
1054 QgsDebugError( QStringLiteral(
"SSL server certificate has 'Certificate Sign' key usage (and should not)" ) );
1061 bool serverauth =
false;
1062 bool dsignature =
false;
1063 bool keyencrypt =
false;
1064 for (
const auto &certconst : certconsts )
1066 if ( certconst.known() == QCA::DigitalSignature )
1068 QgsDebugMsgLevel( QStringLiteral(
"SSL server certificate has 'digital signature' key usage" ), 2 );
1071 else if ( certconst.known() == QCA::KeyEncipherment )
1073 QgsDebugMsgLevel( QStringLiteral(
"SSL server certificate has 'key encipherment' key usage" ), 2 );
1076 else if ( certconst.known() == QCA::KeyAgreement )
1078 QgsDebugMsgLevel( QStringLiteral(
"SSL server certificate has 'key agreement' key usage" ), 2 );
1081 else if ( certconst.known() == QCA::ServerAuth )
1083 QgsDebugMsgLevel( QStringLiteral(
"SSL server certificate has 'server authentication' extended key usage" ), 2 );
1095 if ( serverauth && dsignature && keyencrypt )
1099 if ( dsignature && keyencrypt )
1105 bool keyagree =
false;
1106 bool encipheronly =
false;
1107 bool decipheronly =
false;
1109 QCA::PublicKey pubkey( qcacert.subjectPublicKey() );
1111 if ( pubkey.bitSize() > 0 && pubkey.isDH() )
1113 keyagree = pubkey.canKeyAgree();
1118 for (
const auto &certconst : certconsts )
1120 if ( certconst.known() == QCA::EncipherOnly )
1122 QgsDebugMsgLevel( QStringLiteral(
"SSL server public key has 'encipher only' key usage" ), 2 );
1123 encipheronly =
true;
1125 else if ( certconst.known() == QCA::DecipherOnly )
1127 QgsDebugMsgLevel( QStringLiteral(
"SSL server public key has 'decipher only' key usage" ), 2 );
1128 decipheronly =
true;
1131 if ( !encipheronly && !decipheronly )
1149 case QSslError::UnableToGetIssuerCertificate:
1150 return QObject::tr(
"Unable to Get Issuer Certificate" );
1151 case QSslError::UnableToDecryptCertificateSignature:
1152 return QObject::tr(
"Unable to Decrypt Certificate Signature" );
1153 case QSslError::UnableToDecodeIssuerPublicKey:
1154 return QObject::tr(
"Unable to Decode Issuer Public Key" );
1155 case QSslError::CertificateSignatureFailed:
1156 return QObject::tr(
"Certificate Signature Failed" );
1157 case QSslError::CertificateNotYetValid:
1158 return QObject::tr(
"Certificate Not Yet Valid" );
1159 case QSslError::CertificateExpired:
1160 return QObject::tr(
"Certificate Expired" );
1161 case QSslError::InvalidNotBeforeField:
1162 return QObject::tr(
"Invalid Not Before Field" );
1163 case QSslError::InvalidNotAfterField:
1164 return QObject::tr(
"Invalid Not After Field" );
1165 case QSslError::SelfSignedCertificate:
1166 return QObject::tr(
"Self-signed Certificate" );
1167 case QSslError::SelfSignedCertificateInChain:
1168 return QObject::tr(
"Self-signed Certificate In Chain" );
1169 case QSslError::UnableToGetLocalIssuerCertificate:
1170 return QObject::tr(
"Unable to Get Local Issuer Certificate" );
1171 case QSslError::UnableToVerifyFirstCertificate:
1172 return QObject::tr(
"Unable to Verify First Certificate" );
1173 case QSslError::CertificateRevoked:
1174 return QObject::tr(
"Certificate Revoked" );
1175 case QSslError::InvalidCaCertificate:
1176 return QObject::tr(
"Invalid CA Certificate" );
1177 case QSslError::PathLengthExceeded:
1178 return QObject::tr(
"Path Length Exceeded" );
1179 case QSslError::InvalidPurpose:
1180 return QObject::tr(
"Invalid Purpose" );
1181 case QSslError::CertificateUntrusted:
1182 return QObject::tr(
"Certificate Untrusted" );
1183 case QSslError::CertificateRejected:
1184 return QObject::tr(
"Certificate Rejected" );
1185 case QSslError::SubjectIssuerMismatch:
1186 return QObject::tr(
"Subject Issuer Mismatch" );
1187 case QSslError::AuthorityIssuerSerialNumberMismatch:
1188 return QObject::tr(
"Authority Issuer Serial Number Mismatch" );
1189 case QSslError::NoPeerCertificate:
1190 return QObject::tr(
"No Peer Certificate" );
1191 case QSslError::HostNameMismatch:
1192 return QObject::tr(
"Host Name Mismatch" );
1193 case QSslError::UnspecifiedError:
1194 return QObject::tr(
"Unspecified Error" );
1195 case QSslError::CertificateBlacklisted:
1196 return QObject::tr(
"Certificate Blacklisted" );
1197 case QSslError::NoError:
1198 return QObject::tr(
"No Error" );
1199 case QSslError::NoSslSupport:
1200 return QObject::tr(
"No SSL Support" );
1208 QList<QPair<QSslError::SslError, QString> > errenums;
1209 errenums << qMakePair( QSslError::UnableToGetIssuerCertificate,
1211 errenums << qMakePair( QSslError::UnableToDecryptCertificateSignature,
1213 errenums << qMakePair( QSslError::UnableToDecodeIssuerPublicKey,
1215 errenums << qMakePair( QSslError::CertificateSignatureFailed,
1217 errenums << qMakePair( QSslError::CertificateNotYetValid,
1219 errenums << qMakePair( QSslError::CertificateExpired,
1221 errenums << qMakePair( QSslError::InvalidNotBeforeField,
1223 errenums << qMakePair( QSslError::InvalidNotAfterField,
1225 errenums << qMakePair( QSslError::SelfSignedCertificate,
1227 errenums << qMakePair( QSslError::SelfSignedCertificateInChain,
1229 errenums << qMakePair( QSslError::UnableToGetLocalIssuerCertificate,
1231 errenums << qMakePair( QSslError::UnableToVerifyFirstCertificate,
1233 errenums << qMakePair( QSslError::CertificateRevoked,
1235 errenums << qMakePair( QSslError::InvalidCaCertificate,
1237 errenums << qMakePair( QSslError::PathLengthExceeded,
1239 errenums << qMakePair( QSslError::InvalidPurpose,
1241 errenums << qMakePair( QSslError::CertificateUntrusted,
1243 errenums << qMakePair( QSslError::CertificateRejected,
1245 errenums << qMakePair( QSslError::SubjectIssuerMismatch,
1247 errenums << qMakePair( QSslError::AuthorityIssuerSerialNumberMismatch,
1249 errenums << qMakePair( QSslError::NoPeerCertificate,
1251 errenums << qMakePair( QSslError::HostNameMismatch,
1253 errenums << qMakePair( QSslError::UnspecifiedError,
1255 errenums << qMakePair( QSslError::CertificateBlacklisted,
1262 if ( cert.isNull() )
1264 const QDateTime currentTime = QDateTime::currentDateTime();
1265 return cert.effectiveDate() <= currentTime && cert.expiryDate() >= currentTime;
1270 QList<QSslError> sslErrors;
1272 if ( cert.isNull() )
1275 const QDateTime currentTime = QDateTime::currentDateTime();
1276 if ( cert.expiryDate() <= currentTime )
1278 sslErrors << QSslError( QSslError::SslError::CertificateExpired, cert );
1280 if ( cert.effectiveDate() >= QDateTime::currentDateTime() )
1282 sslErrors << QSslError( QSslError::SslError::CertificateNotYetValid, cert );
1284 if ( cert.isBlacklisted() )
1286 sslErrors << QSslError( QSslError::SslError::CertificateBlacklisted, cert );
1298 const QString &hostName,
1301 QList<QSslError> sslErrors;
1302 QList<QSslCertificate> trustedChain;
1304 for (
const auto &cert : certificateChain )
1306 bool untrusted =
false;
1309 if ( cert.digest( ) == untrustedCert.digest( ) )
1317 trustedChain << cert;
1322 const QList<QSslCertificate> constTrustedChain( trustedChain );
1323 for (
const auto &cert : constTrustedChain )
1329 if ( trustRootCa && trustedChain.count() > 1 && trustedChain.last().isSelfSigned() )
1331 static QMutex sMutex;
1332 const QMutexLocker lock( &sMutex );
1333 const QSslConfiguration oldSslConfig( QSslConfiguration::defaultConfiguration() );
1334 QSslConfiguration sslConfig( oldSslConfig );
1335 sslConfig.setCaCertificates(
casMerge( sslConfig.caCertificates(), QList<QSslCertificate>() << trustedChain.last() ) );
1336 QSslConfiguration::setDefaultConfiguration( sslConfig );
1337 sslErrors = QSslCertificate::verify( trustedChain, hostName );
1338 QSslConfiguration::setDefaultConfiguration( oldSslConfig );
1342 sslErrors = QSslCertificate::verify( trustedChain, hostName );
1351 errors << QObject::tr(
"Client certificate is NULL." );
1354 errors << QObject::tr(
"Client certificate key is NULL." );
1357 if ( !errors.isEmpty() )
1360 QList<QSslError> sslErrors;
1361 if ( useIntermediates )
1363 QList<QSslCertificate> certsList( bundle.
caChain() );
1369 sslErrors = QSslCertificate::verify( QList<QSslCertificate>() << bundle.
clientCert() );
1371 const QList<QSslError> constSslErrors( sslErrors );
1372 for (
const auto &sslError : constSslErrors )
1374 if ( sslError.error() != QSslError::NoError )
1376 errors << sslError.errorString();
1380 const QCA::PrivateKey pvtKey( QCA::PrivateKey::fromPEM( bundle.
clientKey().toPem() ) );
1381 const QCA::PublicKey pubKey( QCA::PublicKey::fromPEM( bundle.
clientCert().publicKey().toPem( ) ) );
1382 bool keyValid( ! pvtKey.isNull() );
1383 if ( keyValid && !( pubKey.toRSA().isNull( ) || pvtKey.toRSA().isNull( ) ) )
1385 keyValid = pubKey.toRSA().n() == pvtKey.toRSA().n();
1387 else if ( keyValid && !( pubKey.toDSA().isNull( ) || pvtKey.toDSA().isNull( ) ) )
1389 keyValid = pubKey == QCA::DSAPublicKey( pvtKey.toDSA() );
1393 QgsDebugError( QStringLiteral(
"Key is not DSA, RSA: validation is not supported by QCA" ) );
1397 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....
const QList< QSslCertificate > untrustedCaCerts(QList< QSslCertificate > trustedCAs=QList< QSslCertificate >())
untrustedCaCerts get list of untrusted certificate authorities
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)
#define QgsDebugError(str)
QLineF segment(int index, QRectF rect, double radius)