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    QgsDebugError( 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    QgsDebugError( 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    QgsDebugError( 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() )
 
 
  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    QgsDebugError( QStringLiteral( 
"ERROR, passed DER is empty" ) );
 
  317  if ( ! asnDefsRsrc.exists() )
 
  319    QgsDebugError( 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      QgsDebugError( 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      QgsDebugError( QStringLiteral( 
"ERROR, asn1 parsing: %1" ).arg( errorDescription ) );
 
  350      QgsDebugError( 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    QgsDebugError( 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    QgsDebugError( QStringLiteral( 
"ERROR, decoding: %1" ).arg( errorDescription ) );
 
  385    QgsDebugMsgLevel( QStringLiteral( 
"Decoding: %1" ).arg( asn1_strerror( asn1_result ) ), 4 );
 
  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    QgsDebugError( QStringLiteral( 
"ERROR, asn1 read privateKey value type: %1" ).arg( asn1_strerror( asn1_result ) ) );
 
  407  if ( oct_etype != ASN1_ETYPE_OCTET_STRING )
 
  409    QgsDebugError( QStringLiteral( 
"ERROR, asn1 privateKey value not octet string, but type: %1" ).arg( 
static_cast<int>( oct_etype ) ) );
 
  415    QgsDebugError( 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    QgsDebugError( QStringLiteral( 
"ERROR, asn1 read privateKey value: %1" ).arg( asn1_strerror( asn1_result ) ) );
 
  430    QgsDebugError( 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    QgsDebugError( QStringLiteral( 
"QCA does not support PKCS#12" ) );
 
  458  if ( bundle.isNull() )
 
  460    QgsDebugError( 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    QgsDebugError( 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      QgsDebugError( 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      QgsDebugError( 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      QgsDebugError( 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      QgsDebugError( QStringLiteral( 
"FAILED to write to temp PEM file: %1" ).arg( pemFilePath ) );
 
  593    QgsDebugError( QStringLiteral( 
"FAILED to open writing for temp PEM file: %1" ).arg( pemFilePath ) );
 
  597  if ( !pemFile.setPermissions( QFile::ReadUser ) )
 
  599    QgsDebugError( 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      QgsDebugError( 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    QgsDebugError( 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    QgsDebugError( QStringLiteral( 
"Certificate could not be converted to QCA cert" ) );
 
  954  if ( qcacert.isCA() )
 
  956    QgsDebugMsgLevel( QStringLiteral( 
"Certificate has 'CA:TRUE' basic constraint" ), 2 );
 
  960  const QList<QCA::ConstraintType> certconsts = qcacert.constraints();
 
  961  for ( 
const auto &certconst : certconsts )
 
  963    if ( certconst.known() == QCA::KeyCertificateSign )
 
  965      QgsDebugMsgLevel( QStringLiteral( 
"Certificate has 'Certificate Sign' key usage" ), 2 );
 
  968    else if ( certconst.known() == QCA::ServerAuth )
 
  970      QgsDebugMsgLevel( QStringLiteral( 
"Certificate has 'server authentication' extended key usage" ), 2 );
 
  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    QgsDebugError( QStringLiteral( 
"Certificate could not be converted to QCA cert" ) );
 
 1054  if ( qcacert.isCA() )
 
 1056    QgsDebugMsgLevel( QStringLiteral( 
"SSL server certificate has 'CA:TRUE' basic constraint (and should not)" ), 2 );
 
 1060  const QList<QCA::ConstraintType> certconsts = qcacert.constraints();
 
 1061  for ( 
const auto & certconst, certconsts )
 
 1063    if ( certconst.known() == QCA::KeyCertificateSign )
 
 1065      QgsDebugError( 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      QgsDebugMsgLevel( QStringLiteral( 
"SSL server certificate has 'digital signature' key usage" ), 2 );
 
 1082    else if ( certconst.known() == QCA::KeyEncipherment )
 
 1084      QgsDebugMsgLevel( QStringLiteral( 
"SSL server certificate has 'key encipherment' key usage" ), 2 );
 
 1087    else if ( certconst.known() == QCA::KeyAgreement )
 
 1089      QgsDebugMsgLevel( QStringLiteral( 
"SSL server certificate has 'key agreement' key usage" ), 2 );
 
 1092    else if ( certconst.known() == QCA::ServerAuth )
 
 1094      QgsDebugMsgLevel( QStringLiteral( 
"SSL server certificate has 'server authentication' extended key usage" ), 2 );
 
 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        QgsDebugMsgLevel( QStringLiteral( 
"SSL server public key has 'encipher only' key usage" ), 2 );
 
 1134        encipheronly = 
true;
 
 1136      else if ( certconst.known() == QCA::DecipherOnly )
 
 1138        QgsDebugMsgLevel( QStringLiteral( 
"SSL server public key has 'decipher only' key usage" ), 2 );
 
 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    QgsDebugError( 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....
 
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)