23 #include <QSslCertificate>
40 case QSsl::SecureProtocols:
41 return QObject::tr(
"SecureProtocols" );
42 case QSsl::TlsV1SslV3:
43 return QObject::tr(
"TlsV1SslV3" );
45 return QObject::tr(
"TlsV1" );
47 return QObject::tr(
"SslV3" );
49 return QObject::tr(
"SslV2" );
57 QMap<QString, QSslCertificate> digestmap;
58 for (
const auto &cert : certs )
67 QMap< QString, QList<QSslCertificate> > orgcerts;
68 for (
const auto &cert : certs )
72 org = QStringLiteral(
"(Organization not defined)" );
73 QList<QSslCertificate> valist = orgcerts.contains( org ) ? orgcerts.value( org ) : QList<QSslCertificate>();
74 orgcerts.insert( org, valist << cert );
81 QMap<QString, QgsAuthConfigSslServer> digestmap;
82 for (
const auto &config : configs )
84 digestmap.insert(
shaHexForCert( config.sslCertificate() ), config );
91 QMap< QString, QList<QgsAuthConfigSslServer> > orgconfigs;
92 for (
const auto &config : configs )
94 QString org(
SSL_SUBJECT_INFO( config.sslCertificate(), QSslCertificate::Organization ) );
97 org = QObject::tr(
"(Organization not defined)" );
98 QList<QgsAuthConfigSslServer> valist = orgconfigs.contains( org ) ? orgconfigs.value( org ) : QList<QgsAuthConfigSslServer>();
99 orgconfigs.insert( org, valist << config );
108 if ( !file.exists() )
110 QgsDebugMsg( QStringLiteral(
"Read file error, file not found: %1" ).arg( path ) );
114 QFile::OpenMode openflags( QIODevice::ReadOnly );
115 bool ret = file.open( openflags );
118 data = file.readAll();
127 QList<QSslCertificate> certs;
129 certs = QSslCertificate::fromData( payload, sniffEncoding( payload ) );
130 if ( certs.isEmpty() )
132 QgsDebugMsg( QStringLiteral(
"Parsed cert(s) EMPTY for path: %1" ).arg( certspath ) );
139 QList<QSslCertificate> cas;
140 const QList<QSslCertificate> certs(
certsFromFile( certspath ) );
141 for (
const auto &cert : certs )
154 QList<QSslCertificate> result( bundle1 );
155 const QList<QSslCertificate> c_bundle1( bundle1 );
156 for (
const auto &cert : c_bundle1 )
160 const QList<QSslCertificate> c_bundle2( bundle2 );
161 for (
const auto &cert : c_bundle2 )
165 result.append( cert );
175 QSslCertificate cert;
177 if ( !certs.isEmpty() )
179 cert = certs.first();
183 QgsDebugMsg( QStringLiteral(
"Parsed cert is NULL for path: %1" ).arg( certpath ) );
189 const QString &keypass,
196 QSsl::EncodingFormat keyEncoding( sniffEncoding( keydata ) );
198 const std::vector<QSsl::KeyAlgorithm> algs
200 QSsl::KeyAlgorithm::Rsa,
201 QSsl::KeyAlgorithm::Dsa,
202 QSsl::KeyAlgorithm::Ec,
203 QSsl::KeyAlgorithm::Opaque
206 for (
const auto &alg : algs )
208 clientkey = QSslKey( keydata,
212 !keypass.isEmpty() ? keypass.toUtf8() : QByteArray() );
213 if ( ! clientkey.isNull() )
219 case QSsl::KeyAlgorithm::Rsa:
220 *algtype = QStringLiteral(
"rsa" );
222 case QSsl::KeyAlgorithm::Dsa:
223 *algtype = QStringLiteral(
"dsa" );
225 case QSsl::KeyAlgorithm::Ec:
226 *algtype = QStringLiteral(
"ec" );
228 case QSsl::KeyAlgorithm::Opaque:
229 *algtype = QStringLiteral(
"opaque" );
231 #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
232 case QSsl::KeyAlgorithm::Dh:
233 *algtype = QStringLiteral(
"dh" );
246 QList<QSslCertificate> certs;
247 certs = QSslCertificate::fromData( pemtext.toLatin1(), QSsl::Pem );
248 if ( certs.isEmpty() )
250 QgsDebugMsg( QStringLiteral(
"Parsed cert(s) EMPTY" ) );
257 QList<QSslCertificate> certs;
258 for (
const auto &cert : caList )
260 if ( ! cert.isSelfSigned( ) )
262 certs.append( cert );
269 const QString &keypath,
270 const QString &keypass,
275 if ( !clientcert.isNull() )
277 certpem = QString( clientcert.toPem() );
285 if ( !clientkey.isNull() )
287 keypem = QString( clientkey.toPem( ( reencrypt && !keypass.isEmpty() ) ? keypass.toUtf8() : QByteArray() ) );
290 return QStringList() << certpem << keypem << algtype;
295 QString pkcs8Header = QStringLiteral(
"-----BEGIN PRIVATE KEY-----" );
296 QString pkcs8Footer = QStringLiteral(
"-----END PRIVATE KEY-----" );
297 return keyPemTxt.contains( pkcs8Header ) && keyPemTxt.contains( pkcs8Footer );
301 QByteArray QgsAuthCertUtils::pkcs8PrivateKey( QByteArray &pkcs8Der )
305 if ( pkcs8Der.isEmpty() )
307 QgsDebugMsg( QStringLiteral(
"ERROR, passed DER is empty" ) );
314 if ( ! asnDefsRsrc.exists() )
316 QgsDebugMsg( QStringLiteral(
"ERROR, pkcs.asn resource file not found: %1" ).arg( asnDefsRsrc.filePath() ) );
319 const char *asnDefsFile = asnDefsRsrc.absoluteFilePath().toLocal8Bit().constData();
321 int asn1_result = ASN1_SUCCESS, der_len = 0, oct_len = 0;
322 asn1_node definitions = NULL, structure = NULL;
323 char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE], oct_data[1024];
324 unsigned char *der = NULL;
325 unsigned int flags = 0;
329 QString
typeName( QStringLiteral(
"PKCS-8.PrivateKeyInfo" ) );
331 asn1_result = asn1_parser2tree( asnDefsFile, &definitions, errorDescription );
333 switch ( asn1_result )
338 case ASN1_FILE_NOT_FOUND:
339 QgsDebugMsg( QStringLiteral(
"ERROR, file not found: %1" ).arg( asnDefsFile ) );
341 case ASN1_SYNTAX_ERROR:
342 case ASN1_IDENTIFIER_NOT_FOUND:
343 case ASN1_NAME_TOO_LONG:
344 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 parsing: %1" ).arg( errorDescription ) );
347 QgsDebugMsg( QStringLiteral(
"ERROR, libtasn1: %1" ).arg( asn1_strerror( asn1_result ) ) );
352 asn1_result = asn1_create_element( definitions,
typeName.toLatin1().constData(), &structure );
356 if ( asn1_result != ASN1_SUCCESS )
358 QgsDebugMsg( QStringLiteral(
"ERROR, structure creation: %1" ).arg( asn1_strerror( asn1_result ) ) );
363 der =
reinterpret_cast<unsigned char *
>( pkcs8Der.data() );
364 der_len = pkcs8Der.size();
368 asn1_result = asn1_der_decoding2( &structure, der, &der_len, flags, errorDescription );
372 asn1_result = asn1_der_decoding( &structure, der, der_len, errorDescription );
375 if ( asn1_result != ASN1_SUCCESS )
377 QgsDebugMsg( QStringLiteral(
"ERROR, decoding: %1" ).arg( errorDescription ) );
382 QgsDebugMsgLevel( QStringLiteral(
"Decoding: %1" ).arg( asn1_strerror( asn1_result ) ), 4 );
387 QgsDebugMsg( QStringLiteral(
"DECODING RESULT:" ) );
388 asn1_print_structure( stdout, structure,
"", ASN1_PRINT_NAME_TYPE_VALUE );
393 typeName.append( QStringLiteral(
".privateKey" ) );
396 asn1_result = asn1_read_value_type( structure,
"privateKey", NULL, &oct_len, &oct_etype );
398 if ( asn1_result != ASN1_MEM_ERROR )
400 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 read privateKey value type: %1" ).arg( asn1_strerror( asn1_result ) ) );
404 if ( oct_etype != ASN1_ETYPE_OCTET_STRING )
406 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 privateKey value not octet string, but type: %1" ).arg(
static_cast<int>( oct_etype ) ) );
412 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 privateKey octet string empty" ) );
417 asn1_result = asn1_read_value( structure,
"privateKey", oct_data, &oct_len );
419 if ( asn1_result != ASN1_SUCCESS )
421 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 read privateKey value: %1" ).arg( asn1_strerror( asn1_result ) ) );
427 QgsDebugMsg( QStringLiteral(
"ERROR, asn1 privateKey value octet string empty" ) );
431 pkcs1 = QByteArray( oct_data, oct_len );
438 asn1_delete_structure( &structure );
444 const QString &bundlepass,
448 if ( !QCA::isSupported(
"pkcs12" ) )
450 QgsDebugMsg( QStringLiteral(
"QCA does not support PKCS#12" ) );
455 if ( bundle.isNull() )
457 QgsDebugMsg( QStringLiteral(
"FAILED to convert PKCS#12 file to QCA key bundle: %1" ).arg( bundlepath ) );
461 QCA::SecureArray passarray;
462 if ( reencrypt && !bundlepass.isEmpty() )
464 passarray = QCA::SecureArray( bundlepass.toUtf8() );
468 QSsl::KeyAlgorithm keyalg = QSsl::Opaque;
469 if ( bundle.privateKey().isRSA() )
471 algtype = QStringLiteral(
"rsa" );
474 else if ( bundle.privateKey().isDSA() )
476 algtype = QStringLiteral(
"dsa" );
479 else if ( bundle.privateKey().isDH() )
481 algtype = QStringLiteral(
"dh" );
486 if ( keyalg == QSsl::Opaque )
488 QgsDebugMsg( QStringLiteral(
"FAILED to read PKCS#12 key (only RSA and DSA algorithms supported): %1" ).arg( bundlepath ) );
496 QgsDebugMsgLevel( QStringLiteral(
"Private key is PKCS#8: attempting conversion to PKCS#1..." ), 4 );
501 QByteArray pkcs8Der = bundle.privateKey().toDER().toByteArray();
502 if ( pkcs8Der.isEmpty() )
504 QgsDebugMsg( QStringLiteral(
"FAILED to convert PKCS#12 key to DER-encoded format: %1" ).arg( bundlepath ) );
508 QByteArray pkcs1Der = QgsAuthCertUtils::pkcs8PrivateKey( pkcs8Der );
509 if ( pkcs1Der.isEmpty() )
511 QgsDebugMsg( QStringLiteral(
"FAILED to convert PKCS#12 key from PKCS#8 to PKCS#1: %1" ).arg( bundlepath ) );
515 QSslKey pkcs1Key( pkcs1Der, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey );
516 if ( pkcs1Key.isNull() )
518 QgsDebugMsg( QStringLiteral(
"FAILED to convert PKCS#12 key from PKCS#8 to PKCS#1 QSslKey: %1" ).arg( bundlepath ) );
521 keyPem = QString( pkcs1Key.toPem( passarray.toByteArray() ) );
525 keyPem = bundle.privateKey().toPEM( passarray );
528 keyPem = bundle.privateKey().toPEM( passarray );
531 QgsDebugMsgLevel( QStringLiteral(
"PKCS#12 cert as PEM:\n%1" ).arg( QString( bundle.certificateChain().primary().toPEM() ) ), 4 );
535 return QStringList() << bundle.certificateChain().primary().toPEM() << keyPem << algtype;
540 QList<QSslCertificate> result;
541 if ( !QCA::isSupported(
"pkcs12" ) )
545 if ( bundle.isNull() )
548 const QCA::CertificateChain chain( bundle.certificateChain() );
549 for (
const auto &cert : chain )
553 result.append( QSslCertificate::fromData( cert.toPEM().toLatin1() ) );
562 if ( !certs.isEmpty() )
564 QStringList certslist;
565 for (
const auto &cert : certs )
567 certslist << cert.toPem();
569 capem = certslist.join( QStringLiteral(
"\n" ) ).toLatin1();
576 QFile pemFile( QDir::tempPath() + QDir::separator() + name );
577 QString pemFilePath( pemFile.fileName() );
579 if ( pemFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
581 qint64 bytesWritten = pemFile.write( pemtext );
582 if ( bytesWritten == -1 )
584 QgsDebugMsg( QStringLiteral(
"FAILED to write to temp PEM file: %1" ).arg( pemFilePath ) );
590 QgsDebugMsg( QStringLiteral(
"FAILED to open writing for temp PEM file: %1" ).arg( pemFilePath ) );
594 if ( !pemFile.setPermissions( QFile::ReadUser ) )
596 QgsDebugMsg( QStringLiteral(
"FAILED to set permissions on temp PEM file: %1" ).arg( pemFilePath ) );
608 return single ? QObject::tr(
"System Root CA" ) : QObject::tr(
"System Root Authorities" );
610 return single ? QObject::tr(
"File CA" ) : QObject::tr(
"Authorities from File" );
612 return single ? QObject::tr(
"Database CA" ) : QObject::tr(
"Authorities in Database" );
614 return single ? QObject::tr(
"Connection CA" ) : QObject::tr(
"Authorities from connection" );
622 QString name( issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::CommonName )
625 if ( name.isEmpty() )
626 name = issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::OrganizationalUnitName )
629 if ( name.isEmpty() )
633 if ( name.isEmpty() )
637 if ( name.isEmpty() )
638 name = issuer ?
SSL_ISSUER_INFO( cert, QSslCertificate::StateOrProvinceName )
641 if ( name.isEmpty() )
649 void QgsAuthCertUtils::appendDirSegment_( QStringList &dirname,
650 const QString &segment, QString value )
652 if ( !value.isEmpty() )
654 dirname.append( segment +
'=' + value.replace(
',', QLatin1String(
"\\," ) ) );
658 QSsl::EncodingFormat QgsAuthCertUtils::sniffEncoding(
const QByteArray &payload )
660 return payload.contains( QByteArrayLiteral(
"-----BEGIN " ) ) ?
666 const QCA::Certificate &acert,
672 if ( acert.isNull() )
674 QCA::ConvertResult res;
675 QCA::Certificate acert( QCA::Certificate::fromPEM( qcert.toPem(), &res, QStringLiteral(
"qca-ossl" ) ) );
676 if ( res != QCA::ConvertGood || acert.isNull() )
678 QgsDebugMsg( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
690 QgsAuthCertUtils::appendDirSegment_(
691 dirname, QStringLiteral(
"E" ), issuer ? acert.issuerInfo().value( QCA::Email )
692 : acert.subjectInfo().value( QCA::Email ) );
693 QgsAuthCertUtils::appendDirSegment_(
694 dirname, QStringLiteral(
"CN" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::CommonName )
696 QgsAuthCertUtils::appendDirSegment_(
697 dirname, QStringLiteral(
"OU" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::OrganizationalUnitName )
699 QgsAuthCertUtils::appendDirSegment_(
700 dirname, QStringLiteral(
"O" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::Organization )
702 QgsAuthCertUtils::appendDirSegment_(
703 dirname, QStringLiteral(
"L" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::LocalityName )
705 QgsAuthCertUtils::appendDirSegment_(
706 dirname, QStringLiteral(
"ST" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::StateOrProvinceName )
708 QgsAuthCertUtils::appendDirSegment_(
709 dirname, QStringLiteral(
"C" ), issuer ?
SSL_ISSUER_INFO( qcert, QSslCertificate::CountryName )
712 return dirname.join( QStringLiteral(
"," ) );
720 return QObject::tr(
"Default" );
722 return QObject::tr(
"Trusted" );
724 return QObject::tr(
"Untrusted" );
735 sl.reserve( txt.size() );
736 for (
int i = 0; i < txt.size(); i += 2 )
738 sl << txt.mid( i, ( i + 2 > txt.size() ) ? -1 : 2 );
740 return sl.join( QStringLiteral(
":" ) );
745 QString sha( cert.digest( QCryptographicHash::Sha1 ).toHex() );
756 return QCA::Certificate();
758 QCA::ConvertResult res;
759 QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.toPem(), &res, QStringLiteral(
"qca-ossl" ) ) );
760 if ( res != QCA::ConvertGood || qcacert.isNull() )
762 QgsDebugMsg( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
763 qcacert = QCA::Certificate();
770 QCA::CertificateCollection qcacoll;
774 for (
const auto &cert : certs )
777 if ( !qcacert.isNull() )
779 qcacoll.addCertificate( qcacert );
787 QCA::SecureArray passarray;
788 if ( !pass.isEmpty() )
789 passarray = QCA::SecureArray( pass.toUtf8() );
791 QCA::ConvertResult res;
792 QCA::KeyBundle bundle( QCA::KeyBundle::fromFile( path, passarray, &res, QStringLiteral(
"qca-ossl" ) ) );
794 return ( res == QCA::ConvertGood ? bundle : QCA::KeyBundle() );
801 case QCA::ValidityGood:
802 return QObject::tr(
"Certificate is valid." );
803 case QCA::ErrorRejected:
804 return QObject::tr(
"Root CA rejected the certificate purpose." );
805 case QCA::ErrorUntrusted:
806 return QObject::tr(
"Certificate is not trusted." );
807 case QCA::ErrorSignatureFailed:
808 return QObject::tr(
"Signature does not match." );
809 case QCA::ErrorInvalidCA:
810 return QObject::tr(
"Certificate Authority is invalid or not found." );
811 case QCA::ErrorInvalidPurpose:
812 return QObject::tr(
"Purpose does not match the intended usage." );
813 case QCA::ErrorSelfSigned:
814 return QObject::tr(
"Certificate is self-signed, and is not found in the list of trusted certificates." );
815 case QCA::ErrorRevoked:
816 return QObject::tr(
"Certificate has been revoked." );
817 case QCA::ErrorPathLengthExceeded:
818 return QObject::tr(
"Path length from the root CA to this certificate is too long." );
819 case QCA::ErrorExpired:
820 return QObject::tr(
"Certificate has expired or is not yet valid." );
821 case QCA::ErrorExpiredCA:
822 return QObject::tr(
"Certificate Authority has expired." );
823 case QCA::ErrorValidityUnknown:
824 return QObject::tr(
"Validity is unknown." );
834 case QCA::EMSA1_SHA1:
835 return QObject::tr(
"SHA1, with EMSA1" );
836 case QCA::EMSA3_SHA1:
837 return QObject::tr(
"SHA1, with EMSA3" );
839 return QObject::tr(
"MD5, with EMSA3" );
841 return QObject::tr(
"MD2, with EMSA3" );
842 case QCA::EMSA3_RIPEMD160:
843 return QObject::tr(
"RIPEMD160, with EMSA3" );
845 return QObject::tr(
"EMSA3, without digest" );
846 #if QCA_VERSION >= 0x020100
847 case QCA::EMSA3_SHA224:
848 return QObject::tr(
"SHA224, with EMSA3" );
849 case QCA::EMSA3_SHA256:
850 return QObject::tr(
"SHA256, with EMSA3" );
851 case QCA::EMSA3_SHA384:
852 return QObject::tr(
"SHA384, with EMSA3" );
853 case QCA::EMSA3_SHA512:
854 return QObject::tr(
"SHA512, with EMSA3" );
857 return QObject::tr(
"Unknown (possibly Elliptic Curve)" );
863 switch ( constraint )
865 case QCA::DigitalSignature:
866 return QObject::tr(
"Digital Signature" );
867 case QCA::NonRepudiation:
868 return QObject::tr(
"Non-repudiation" );
869 case QCA::KeyEncipherment:
870 return QObject::tr(
"Key Encipherment" );
871 case QCA::DataEncipherment:
872 return QObject::tr(
"Data Encipherment" );
873 case QCA::KeyAgreement:
874 return QObject::tr(
"Key Agreement" );
875 case QCA::KeyCertificateSign:
876 return QObject::tr(
"Key Certificate Sign" );
878 return QObject::tr(
"CRL Sign" );
879 case QCA::EncipherOnly:
880 return QObject::tr(
"Encipher Only" );
881 case QCA::DecipherOnly:
882 return QObject::tr(
"Decipher Only" );
883 case QCA::ServerAuth:
884 return QObject::tr(
"Server Authentication" );
885 case QCA::ClientAuth:
886 return QObject::tr(
"Client Authentication" );
887 case QCA::CodeSigning:
888 return QObject::tr(
"Code Signing" );
889 case QCA::EmailProtection:
890 return QObject::tr(
"Email Protection" );
891 case QCA::IPSecEndSystem:
892 return QObject::tr(
"IPSec Endpoint" );
893 case QCA::IPSecTunnel:
894 return QObject::tr(
"IPSec Tunnel" );
896 return QObject::tr(
"IPSec User" );
897 case QCA::TimeStamping:
898 return QObject::tr(
"Time Stamping" );
899 case QCA::OCSPSigning:
900 return QObject::tr(
"OCSP Signing" );
911 return QObject::tr(
"Any or unspecified" );
913 return QObject::tr(
"Certificate Authority" );
915 return QObject::tr(
"Certificate Issuer" );
917 return QObject::tr(
"TLS/SSL Server" );
919 return QObject::tr(
"TLS/SSL Server EV" );
921 return QObject::tr(
"TLS/SSL Client" );
923 return QObject::tr(
"Code Signing" );
925 return QObject::tr(
"Email Protection" );
927 return QObject::tr(
"Time Stamping" );
929 return QObject::tr(
"CRL Signing" );
932 return QObject::tr(
"Undetermined usage" );
938 QList<QgsAuthCertUtils::CertUsageType> usages;
943 QCA::ConvertResult res;
944 QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.toPem(), &res, QStringLiteral(
"qca-ossl" ) ) );
945 if ( res != QCA::ConvertGood || qcacert.isNull() )
947 QgsDebugMsg( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
951 if ( qcacert.isCA() )
953 QgsDebugMsg( QStringLiteral(
"Certificate has 'CA:TRUE' basic constraint" ) );
957 const QList<QCA::ConstraintType> certconsts = qcacert.constraints();
958 for (
const auto &certconst : certconsts )
960 if ( certconst.known() == QCA::KeyCertificateSign )
962 QgsDebugMsg( QStringLiteral(
"Certificate has 'Certificate Sign' key usage" ) );
965 else if ( certconst.known() == QCA::ServerAuth )
967 QgsDebugMsg( QStringLiteral(
"Certificate has 'server authentication' extended key usage" ) );
973 QCA::CertificateCollection trustedCAs(
975 QCA::CertificateCollection untrustedCAs(
979 v_any = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageAny, QCA::ValidateAll );
980 if ( v_any == QCA::ValidityGood )
985 QCA::Validity v_tlsserver;
986 v_tlsserver = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageTLSServer, QCA::ValidateAll );
987 if ( v_tlsserver == QCA::ValidityGood )
997 QCA::Validity v_tlsclient;
998 v_tlsclient = qcacert.validate( trustedCAs, untrustedCAs, QCA::UsageTLSClient, QCA::ValidateAll );
1000 if ( v_tlsclient == QCA::ValidityGood )
1043 QCA::ConvertResult res;
1044 QCA::Certificate qcacert( QCA::Certificate::fromPEM( cert.toPem(), &res, QString(
"qca-ossl" ) ) );
1045 if ( res != QCA::ConvertGood || qcacert.isNull() )
1047 QgsDebugMsg( QStringLiteral(
"Certificate could not be converted to QCA cert" ) );
1051 if ( qcacert.isCA() )
1053 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'CA:TRUE' basic constraint (and should not)" ) );
1057 const QList<QCA::ConstraintType> certconsts = qcacert.constraints();
1058 for (
const auto & certconst, certconsts )
1060 if ( certconst.known() == QCA::KeyCertificateSign )
1062 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'Certificate Sign' key usage (and should not)" ) );
1069 bool serverauth =
false;
1070 bool dsignature =
false;
1071 bool keyencrypt =
false;
1072 for (
const auto &certconst : certconsts )
1074 if ( certconst.known() == QCA::DigitalSignature )
1076 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'digital signature' key usage" ) );
1079 else if ( certconst.known() == QCA::KeyEncipherment )
1081 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'key encipherment' key usage" ) );
1084 else if ( certconst.known() == QCA::KeyAgreement )
1086 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'key agreement' key usage" ) );
1089 else if ( certconst.known() == QCA::ServerAuth )
1091 QgsDebugMsg( QStringLiteral(
"SSL server certificate has 'server authentication' extended key usage" ) );
1103 if ( serverauth && dsignature && keyencrypt )
1107 if ( dsignature && keyencrypt )
1113 bool keyagree =
false;
1114 bool encipheronly =
false;
1115 bool decipheronly =
false;
1117 QCA::PublicKey pubkey( qcacert.subjectPublicKey() );
1119 if ( pubkey.bitSize() > 0 && pubkey.isDH() )
1121 keyagree = pubkey.canKeyAgree();
1126 for (
const auto &certconst : certconsts )
1128 if ( certconst.known() == QCA::EncipherOnly )
1130 QgsDebugMsg( QStringLiteral(
"SSL server public key has 'encipher only' key usage" ) );
1131 encipheronly =
true;
1133 else if ( certconst.known() == QCA::DecipherOnly )
1135 QgsDebugMsg( QStringLiteral(
"SSL server public key has 'decipher only' key usage" ) );
1136 decipheronly =
true;
1139 if ( !encipheronly && !decipheronly )
1157 case QSslError::UnableToGetIssuerCertificate:
1158 return QObject::tr(
"Unable to Get Issuer Certificate" );
1159 case QSslError::UnableToDecryptCertificateSignature:
1160 return QObject::tr(
"Unable to Decrypt Certificate Signature" );
1161 case QSslError::UnableToDecodeIssuerPublicKey:
1162 return QObject::tr(
"Unable to Decode Issuer Public Key" );
1163 case QSslError::CertificateSignatureFailed:
1164 return QObject::tr(
"Certificate Signature Failed" );
1165 case QSslError::CertificateNotYetValid:
1166 return QObject::tr(
"Certificate Not Yet Valid" );
1167 case QSslError::CertificateExpired:
1168 return QObject::tr(
"Certificate Expired" );
1169 case QSslError::InvalidNotBeforeField:
1170 return QObject::tr(
"Invalid Not Before Field" );
1171 case QSslError::InvalidNotAfterField:
1172 return QObject::tr(
"Invalid Not After Field" );
1173 case QSslError::SelfSignedCertificate:
1174 return QObject::tr(
"Self-signed Certificate" );
1175 case QSslError::SelfSignedCertificateInChain:
1176 return QObject::tr(
"Self-signed Certificate In Chain" );
1177 case QSslError::UnableToGetLocalIssuerCertificate:
1178 return QObject::tr(
"Unable to Get Local Issuer Certificate" );
1179 case QSslError::UnableToVerifyFirstCertificate:
1180 return QObject::tr(
"Unable to Verify First Certificate" );
1181 case QSslError::CertificateRevoked:
1182 return QObject::tr(
"Certificate Revoked" );
1183 case QSslError::InvalidCaCertificate:
1184 return QObject::tr(
"Invalid CA Certificate" );
1185 case QSslError::PathLengthExceeded:
1186 return QObject::tr(
"Path Length Exceeded" );
1187 case QSslError::InvalidPurpose:
1188 return QObject::tr(
"Invalid Purpose" );
1189 case QSslError::CertificateUntrusted:
1190 return QObject::tr(
"Certificate Untrusted" );
1191 case QSslError::CertificateRejected:
1192 return QObject::tr(
"Certificate Rejected" );
1193 case QSslError::SubjectIssuerMismatch:
1194 return QObject::tr(
"Subject Issuer Mismatch" );
1195 case QSslError::AuthorityIssuerSerialNumberMismatch:
1196 return QObject::tr(
"Authority Issuer Serial Number Mismatch" );
1197 case QSslError::NoPeerCertificate:
1198 return QObject::tr(
"No Peer Certificate" );
1199 case QSslError::HostNameMismatch:
1200 return QObject::tr(
"Host Name Mismatch" );
1201 case QSslError::UnspecifiedError:
1202 return QObject::tr(
"Unspecified Error" );
1203 case QSslError::CertificateBlacklisted:
1204 return QObject::tr(
"Certificate Blocklisted" );
1205 case QSslError::NoError:
1206 return QObject::tr(
"No Error" );
1207 case QSslError::NoSslSupport:
1208 return QObject::tr(
"No SSL Support" );
1216 QList<QPair<QSslError::SslError, QString> > errenums;
1217 errenums << qMakePair( QSslError::UnableToGetIssuerCertificate,
1219 errenums << qMakePair( QSslError::UnableToDecryptCertificateSignature,
1221 errenums << qMakePair( QSslError::UnableToDecodeIssuerPublicKey,
1223 errenums << qMakePair( QSslError::CertificateSignatureFailed,
1225 errenums << qMakePair( QSslError::CertificateNotYetValid,
1227 errenums << qMakePair( QSslError::CertificateExpired,
1229 errenums << qMakePair( QSslError::InvalidNotBeforeField,
1231 errenums << qMakePair( QSslError::InvalidNotAfterField,
1233 errenums << qMakePair( QSslError::SelfSignedCertificate,
1235 errenums << qMakePair( QSslError::SelfSignedCertificateInChain,
1237 errenums << qMakePair( QSslError::UnableToGetLocalIssuerCertificate,
1239 errenums << qMakePair( QSslError::UnableToVerifyFirstCertificate,
1241 errenums << qMakePair( QSslError::CertificateRevoked,
1243 errenums << qMakePair( QSslError::InvalidCaCertificate,
1245 errenums << qMakePair( QSslError::PathLengthExceeded,
1247 errenums << qMakePair( QSslError::InvalidPurpose,
1249 errenums << qMakePair( QSslError::CertificateUntrusted,
1251 errenums << qMakePair( QSslError::CertificateRejected,
1253 errenums << qMakePair( QSslError::SubjectIssuerMismatch,
1255 errenums << qMakePair( QSslError::AuthorityIssuerSerialNumberMismatch,
1257 errenums << qMakePair( QSslError::NoPeerCertificate,
1259 errenums << qMakePair( QSslError::HostNameMismatch,
1261 errenums << qMakePair( QSslError::UnspecifiedError,
1263 errenums << qMakePair( QSslError::CertificateBlacklisted,
1270 if ( cert.isNull() )
1272 const QDateTime currentTime = QDateTime::currentDateTime();
1273 return cert.effectiveDate() <= currentTime && cert.expiryDate() >= currentTime;
1278 QList<QSslError> sslErrors;
1280 if ( cert.isNull() )
1283 const QDateTime currentTime = QDateTime::currentDateTime();
1284 if ( cert.expiryDate() <= currentTime )
1286 sslErrors << QSslError( QSslError::SslError::CertificateExpired, cert );
1288 if ( cert.effectiveDate() >= QDateTime::currentDateTime() )
1290 sslErrors << QSslError( QSslError::SslError::CertificateNotYetValid, cert );
1292 if ( cert.isBlacklisted() )
1294 sslErrors << QSslError( QSslError::SslError::CertificateBlacklisted, cert );
1306 const QString &hostName,
1309 QList<QSslError> sslErrors;
1310 QList<QSslCertificate> trustedChain;
1312 for (
const auto &cert : certificateChain )
1314 bool untrusted =
false;
1317 if ( cert.digest( ) == untrustedCert.digest( ) )
1325 trustedChain << cert;
1330 const QList<QSslCertificate> constTrustedChain( trustedChain );
1331 for (
const auto &cert : constTrustedChain )
1337 if ( trustRootCa && trustedChain.count() > 1 && trustedChain.last().isSelfSigned() )
1339 static QMutex sMutex;
1340 QMutexLocker lock( &sMutex );
1341 QSslConfiguration oldSslConfig( QSslConfiguration::defaultConfiguration() );
1342 QSslConfiguration sslConfig( oldSslConfig );
1343 sslConfig.setCaCertificates(
casMerge( sslConfig.caCertificates(), QList<QSslCertificate>() << trustedChain.last() ) );
1344 QSslConfiguration::setDefaultConfiguration( sslConfig );
1345 sslErrors = QSslCertificate::verify( trustedChain, hostName );
1346 QSslConfiguration::setDefaultConfiguration( oldSslConfig );
1350 sslErrors = QSslCertificate::verify( trustedChain, hostName );
1359 errors << QObject::tr(
"Client certificate is NULL." );
1362 errors << QObject::tr(
"Client certificate key is NULL." );
1365 if ( !errors.isEmpty() )
1368 QList<QSslError> sslErrors;
1369 if ( useIntermediates )
1371 QList<QSslCertificate> certsList( bundle.
caChain() );
1377 sslErrors = QSslCertificate::verify( QList<QSslCertificate>() << bundle.
clientCert() );
1379 const QList<QSslError> constSslErrors( sslErrors );
1380 for (
const auto &sslError : constSslErrors )
1382 if ( sslError.error() != QSslError::NoError )
1384 errors << sslError.errorString();
1388 QCA::PrivateKey pvtKey( QCA::PrivateKey::fromPEM( bundle.
clientKey().toPem() ) );
1389 QCA::PublicKey pubKey( QCA::PublicKey::fromPEM( bundle.
clientCert().publicKey().toPem( ) ) );
1390 bool keyValid( ! pvtKey.isNull() );
1391 if ( keyValid && !( pubKey.toRSA().isNull( ) || pvtKey.toRSA().isNull( ) ) )
1393 keyValid = pubKey.toRSA().n() == pvtKey.toRSA().n();
1395 else if ( keyValid && !( pubKey.toDSA().isNull( ) || pvtKey.toDSA().isNull( ) ) )
1397 keyValid = pubKey == QCA::DSAPublicKey( pvtKey.toDSA() );
1401 QgsDebugMsg( QStringLiteral(
"Key is not DSA, RSA: validation is not supported by QCA" ) );
1405 errors << QObject::tr(
"Private key does not match client certificate public key." );