19 #include "ui_qgsauthcertificateinfo.h" 22 #include <QDialogButtonBox> 24 #include <QPlainTextEdit> 25 #include <QPushButton> 56 , mConnectionCAs( connectionCAs )
57 , mDefaultItemForeground(
QBrush() )
58 , mManageTrust( manageCertTrust )
59 , mTrustCacheRebuilt( false )
62 , mSecGeneral( nullptr )
63 , mSecDetails( nullptr )
64 , mSecPemText( nullptr )
70 , mAuthNotifyLayout( nullptr )
71 , mAuthNotify( nullptr )
78 mAuthNotifyLayout->
addWidget( mAuthNotify );
84 lblError->setHidden(
true );
86 treeHierarchy->setRootIsDecorated(
false );
93 setUpCertDetailsTree();
95 grpbxTrust->setVisible( mManageTrust );
102 res = populateQcaCertCollection();
104 res = setQcaCertificate( cert );
106 res = populateCertChain();
110 connect( cmbbxTrust, SIGNAL( currentIndexChanged(
int ) ),
111 this, SLOT( currentPolicyIndexChanged(
int ) ) );
119 void QgsAuthCertInfo::setupError(
const QString &msg )
121 lblError->setVisible(
true );
122 QString out =
tr(
"<b>Setup ERROR:</b>\n\n" );
124 lblError->setText( out );
130 Q_UNUSED( previous );
131 updateCurrentCert( current );
137 item = treeHierarchy->currentItem();
141 int indx( item->
data( 0, Qt::UserRole ).
toInt() );
142 updateCurrentCertInfo( indx );
145 bool QgsAuthCertInfo::populateQcaCertCollection()
148 for (
int i = 0; i < certpairs.size(); ++i )
150 QCA::ConvertResult res;
151 QCA::Certificate acert = QCA::Certificate::fromPEM( certpairs.at( i ).second.toPem(), &res,
QString(
"qca-ossl" ) );
152 if ( res == QCA::ConvertGood && !acert.isNull() )
154 mCaCerts.addCertificate( acert );
157 if ( !mConnectionCAs.
isEmpty() )
161 QCA::ConvertResult res;
162 QCA::Certificate acert = QCA::Certificate::fromPEM( cert.
toPem(), &res,
QString(
"qca-ossl" ) );
163 if ( res == QCA::ConvertGood && !acert.isNull() )
165 mCaCerts.addCertificate( acert );
170 if ( mCaCerts.certificates().size() < 1 )
172 setupError(
tr(
"Could not populate QCA certificate collection" ) );
180 QCA::ConvertResult res;
181 mCert = QCA::Certificate::fromPEM( cert.
toPem(), &res,
QString(
"qca-ossl" ) );
182 if ( res != QCA::ConvertGood || mCert.isNull() )
184 setupError(
tr(
"Could not set QCA certificate" ) );
190 bool QgsAuthCertInfo::populateCertChain()
192 QCA::CertificateChain certchain( mCert );
194 mACertChain = certchain.complete( mCaCerts.certificates(), &valid );
195 if ( valid != QCA::ValidityGood && valid != QCA::ErrorInvalidCA )
198 setupError(
tr(
"Invalid population of QCA certificate chain.<br><br>" 203 if ( mACertChain.isEmpty() )
205 QgsDebugMsg(
"Could not populate QCA certificate chain" );
206 mACertChain = certchain;
209 if ( !mACertChain.last().isSelfSigned() )
212 mACertChain.append( QCA::Certificate() );
216 Q_FOREACH ( QCA::Certificate cert, mACertChain )
219 if ( !cert.isNull() )
223 mQCertChain.
append( qcert );
228 void QgsAuthCertInfo::setCertHierarchy()
232 int i = mQCertChain.
size();
238 bool missingCA = cert.
isNull();
243 cert_source +=
QString(
" (%1)" ).
arg(
tr(
"Missing CA" ) );
249 if ( mCaCertsCache.
contains( sha ) )
254 else if ( mConnectionCAs.
contains( cert ) )
256 cert_source +=
QString(
" (%1)" )
271 item->
setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
274 item->
setData( 0, Qt::UserRole, --i );
276 if ( mDefaultItemForeground.
style() == Qt::NoBrush )
278 mDefaultItemForeground = item->
foreground( 0 );
285 treeHierarchy->addTopLevelItem( item );
288 treeHierarchy->setCurrentItem( item, 0, QItemSelectionModel::ClearAndSelect );
289 treeHierarchy->expandAll();
292 void QgsAuthCertInfo::updateCurrentCertInfo(
int chainindx )
294 btnSaveTrust->setEnabled(
false );
296 mCurrentQCert = mQCertChain.
at( chainindx );
297 mCurrentACert = mACertChain.at( chainindx );
301 grpbxTrust->setHidden( mCurrentQCert.
isNull() );
304 if ( !mCurrentQCert.
isNull() )
307 mCurrentTrustPolicy = trustpolicy;
309 cmbbxTrust->setTrustPolicy( trustpolicy );
310 if ( !mCurrentQCert.
isValid() )
319 void QgsAuthCertInfo::setUpCertDetailsTree()
321 treeDetails->setColumnCount( 2 );
322 treeDetails->setHeaderLabels(
QStringList() <<
tr(
"Field" ) <<
tr(
"Value" ) );
323 treeDetails->setColumnWidth( 0, 200 );
329 treeDetails->setRootIsDecorated(
true );
330 treeDetails->setWordWrap(
true );
336 (
int )DetailsSection );
339 mSecGeneral->
setFlags( Qt::ItemIsEnabled );
341 treeDetails->insertTopLevelItem( 0, mSecGeneral );
346 (
int )DetailsSection );
349 mSecDetails->
setFlags( Qt::ItemIsEnabled );
351 treeDetails->insertTopLevelItem( 0, mSecDetails );
354 mGrpSubj = addGroupItem( mSecDetails,
tr(
"Subject Info" ) );
355 mGrpIssu = addGroupItem( mSecDetails,
tr(
"Issuer Info" ) ) ;
356 mGrpCert = addGroupItem( mSecDetails,
tr(
"Certificate Info" ) );
357 mGrpPkey = addGroupItem( mSecDetails,
tr(
"Public Key Info" ) );
358 mGrpExts = addGroupItem( mSecDetails,
tr(
"Extensions" ) );
363 (
int )DetailsSection );
366 mSecPemText->
setFlags( Qt::ItemIsEnabled );
368 treeDetails->insertTopLevelItem( 0, mSecPemText );
371 void QgsAuthCertInfo::populateCertInfo()
376 populateInfoGeneralSection();
377 populateInfoDetailsSection();
378 populateInfoPemTextSection();
386 (
int )DetailsGroup );
389 grpitem->
setFlags( Qt::ItemIsEnabled );
403 QgsAuthCertInfo::FieldWidget wdgt,
const QColor& color )
410 QStringList() << field << ( wdgt == NoWidget ? value :
"" ),
411 (
int )DetailsField );
420 if ( wdgt == NoWidget )
429 else if ( wdgt == LineEdit )
441 else if ( wdgt == TextEdit )
457 void QgsAuthCertInfo::populateInfoGeneralSection()
461 if ( mCurrentQCert.
isNull() )
463 addFieldItem( mSecGeneral,
tr(
"Type" ),
464 tr(
"Missing CA (incomplete local CA chain)" ),
473 bool isselfsigned = mCurrentACert.isSelfSigned();
474 QString selfsigned(
tr(
"self-signed" ) );
491 if ( isissuer || ( isca && !isselfsigned ) )
495 if (( isissuer || isca ) && isselfsigned )
506 addFieldItem( mSecGeneral,
tr(
"Usage type" ),
509 addFieldItem( mSecGeneral,
tr(
"Subject" ),
512 addFieldItem( mSecGeneral,
tr(
"Issuer" ),
515 addFieldItem( mSecGeneral,
tr(
"Not valid after" ),
521 QString alg( pubkey.algorithm() == QSsl::Rsa ?
"RSA" :
"DSA" );
522 int bitsize( pubkey.length() );
523 addFieldItem( mSecGeneral,
tr(
"Public key" ),
526 addFieldItem( mSecGeneral,
tr(
"Signature algorithm" ),
531 void QgsAuthCertInfo::populateInfoDetailsSection()
539 if ( mCurrentQCert.
isNull() )
543 addFieldItem( mGrpSubj,
tr(
"Country (C)" ),
546 addFieldItem( mGrpSubj,
tr(
"State/Province (ST)" ),
549 addFieldItem( mGrpSubj,
tr(
"Locality (L)" ),
552 addFieldItem( mGrpSubj,
tr(
"Organization (O)" ),
555 addFieldItem( mGrpSubj,
tr(
"Organizational unit (OU)" ),
558 addFieldItem( mGrpSubj,
tr(
"Common name (CN)" ),
561 addFieldItem( mGrpSubj,
tr(
"Email address (E)" ),
562 mCurrentACert.subjectInfo().value( QCA::Email ),
564 addFieldItem( mGrpSubj,
tr(
"Distinguished name" ),
567 addFieldItem( mGrpSubj,
tr(
"Email Legacy" ),
568 mCurrentACert.subjectInfo().value( QCA::EmailLegacy ),
570 addFieldItem( mGrpSubj,
tr(
"Incorporation Country" ),
571 mCurrentACert.subjectInfo().value( QCA::IncorporationCountry ),
573 addFieldItem( mGrpSubj,
tr(
"Incorporation State/Province" ),
574 mCurrentACert.subjectInfo().value( QCA::IncorporationState ),
576 addFieldItem( mGrpSubj,
tr(
"Incorporation Locality" ),
577 mCurrentACert.subjectInfo().value( QCA::IncorporationLocality ),
579 addFieldItem( mGrpSubj,
tr(
"URI" ),
580 mCurrentACert.subjectInfo().value( QCA::URI ),
582 addFieldItem( mGrpSubj,
tr(
"DNS" ),
583 mCurrentACert.subjectInfo().value( QCA::DNS ),
585 addFieldItem( mGrpSubj,
tr(
"IP Address" ),
586 mCurrentACert.subjectInfo().value( QCA::IPAddress ),
588 addFieldItem( mGrpSubj,
tr(
"XMPP" ),
589 mCurrentACert.subjectInfo().value( QCA::XMPP ),
595 QStringList emails( alts.values( QSsl::EmailEntry ) );
596 if ( !emails.isEmpty() )
598 altslist << email + emails.join(
'\n' + email );
602 if ( !dnss.isEmpty() )
604 altslist << dns + dnss.join(
'\n' + dns );
606 addFieldItem( mGrpSubj,
tr(
"Alternate names" ),
607 altslist.join(
"\n" ),
611 addFieldItem( mGrpIssu,
tr(
"Country (C)" ),
614 addFieldItem( mGrpIssu,
tr(
"State/Province (ST)" ),
615 SSL_ISSUER_INFO( mCurrentQCert, QSslCertificate::StateOrProvinceName ),
617 addFieldItem( mGrpIssu,
tr(
"Locality (L)" ),
620 addFieldItem( mGrpIssu,
tr(
"Organization (O)" ),
623 addFieldItem( mGrpIssu,
tr(
"Organizational unit (OU)" ),
624 SSL_ISSUER_INFO( mCurrentQCert, QSslCertificate::OrganizationalUnitName ),
626 addFieldItem( mGrpIssu,
tr(
"Common name (CN)" ),
629 addFieldItem( mGrpIssu,
tr(
"Email address (E)" ),
630 mCurrentACert.issuerInfo().value( QCA::Email ),
632 addFieldItem( mGrpIssu,
tr(
"Distinguished name" ),
635 addFieldItem( mGrpIssu,
tr(
"Email Legacy" ),
636 mCurrentACert.issuerInfo().value( QCA::EmailLegacy ),
638 addFieldItem( mGrpIssu,
tr(
"Incorporation Country" ),
639 mCurrentACert.issuerInfo().value( QCA::IncorporationCountry ),
641 addFieldItem( mGrpIssu,
tr(
"Incorporation State/Province" ),
642 mCurrentACert.issuerInfo().value( QCA::IncorporationState ),
644 addFieldItem( mGrpIssu,
tr(
"Incorporation Locality" ),
645 mCurrentACert.issuerInfo().value( QCA::IncorporationLocality ),
647 addFieldItem( mGrpIssu,
tr(
"URI" ),
648 mCurrentACert.issuerInfo().value( QCA::URI ),
650 addFieldItem( mGrpIssu,
tr(
"DNS" ),
651 mCurrentACert.issuerInfo().value( QCA::DNS ),
653 addFieldItem( mGrpIssu,
tr(
"IP Address" ),
654 mCurrentACert.issuerInfo().value( QCA::IPAddress ),
656 addFieldItem( mGrpIssu,
tr(
"XMPP" ),
657 mCurrentACert.issuerInfo().value( QCA::XMPP ),
661 addFieldItem( mGrpCert,
tr(
"Version" ),
664 addFieldItem( mGrpCert,
tr(
"Serial #" ),
667 addFieldItem( mGrpCert,
tr(
"Not valid before" ),
671 addFieldItem( mGrpCert,
tr(
"Not valid after" ),
675 addFieldItem( mGrpCert,
tr(
"Signature algorithm" ),
678 addFieldItem( mGrpCert,
tr(
"MD5 fingerprint" ),
681 addFieldItem( mGrpCert,
tr(
"SHA1 fingerprint" ),
685 QStringList crllocs( mCurrentACert.crlLocations() );
686 if ( !crllocs.isEmpty() )
688 addFieldItem( mGrpCert,
tr(
"CRL locations" ),
689 crllocs.join(
"\n" ),
692 QStringList issulocs( mCurrentACert.issuerLocations() );
693 if ( !issulocs.isEmpty() )
695 addFieldItem( mGrpCert,
tr(
"Issuer locations" ),
696 issulocs.join(
"\n" ),
699 QStringList ocsplocs( mCurrentACert.ocspLocations() );
700 if ( !ocsplocs.isEmpty() )
702 addFieldItem( mGrpCert,
tr(
"OCSP locations" ),
703 ocsplocs.join(
"\n" ),
710 QString alg( pubqkey.algorithm() == QSsl::Rsa ?
"RSA" :
"DSA" );
711 int bitsize( pubqkey.length() );
712 addFieldItem( mGrpPkey,
tr(
"Algorithm" ),
713 bitsize == -1 ?
QString(
"Unknown (possibly Elliptic Curve)" ) : alg,
715 addFieldItem( mGrpPkey,
tr(
"Key size" ),
720 QCA::PublicKey pubakey( mCurrentACert.subjectPublicKey() );
722 if ( pubqkey.algorithm() == QSsl::Rsa )
724 QCA::RSAPublicKey rsakey( pubakey.toRSA() );
725 QCA::BigInteger modulus = rsakey.n();
726 QByteArray modarray( modulus.toArray().toByteArray().toHex() );
727 if ( modarray.size() > 2 && modarray.mid( 0, 2 ) ==
QByteArray(
"00" ) )
729 modarray = modarray.
mid( 2 );
731 QCA::BigInteger exponent = rsakey.e();
732 addFieldItem( mGrpPkey,
tr(
"Public key" ),
735 addFieldItem( mGrpPkey,
tr(
"Exponent" ),
749 if ( pubakey.canVerify() )
755 if ( pubakey.canEncrypt() )
757 usage.append(
tr(
"Encrypt" ) );
759 #if QCA_VERSION >= 0x020100 760 if ( pubakey.canDecrypt() )
762 usage.append(
tr(
"Decrypt" ) );
765 if ( pubakey.canKeyAgree() )
767 usage.append(
tr(
"Key agreement" ) );
769 if ( pubakey.canExport() )
771 usage.append(
tr(
"Export" ) );
773 if ( !usage.isEmpty() )
775 addFieldItem( mGrpPkey,
tr(
"Key usage" ),
783 basicconst <<
tr(
"Certificate Authority: %1" ).
arg( mCurrentACert.isCA() ?
tr(
"Yes" ) :
tr(
"No" ) )
784 <<
tr(
"Chain Path Limit: %1" ).
arg( mCurrentACert.pathLimit() );
785 addFieldItem( mGrpExts,
tr(
"Basic constraints" ),
786 basicconst.join(
"\n" ),
792 Q_FOREACH (
const QCA::ConstraintType& certconst, certconsts )
794 if ( certconst.section() == QCA::ConstraintType::KeyUsage )
798 else if ( certconst.section() == QCA::ConstraintType::ExtendedKeyUsage )
803 if ( !keyusage.isEmpty() )
805 addFieldItem( mGrpExts,
tr(
"Key usage" ),
806 keyusage.join(
"\n" ),
811 addFieldItem( mGrpExts,
tr(
"Extended key usage" ),
812 extkeyusage.
join(
"\n" ),
816 addFieldItem( mGrpExts,
tr(
"Subject key ID" ),
819 addFieldItem( mGrpExts,
tr(
"Authority key ID" ),
824 void QgsAuthCertInfo::populateInfoPemTextSection()
828 if ( mCurrentQCert.
isNull() )
834 (
int )DetailsField );
846 void QgsAuthCertInfo::on_btnSaveTrust_clicked()
851 QgsDebugMsg(
"Could not set trust policy for certificate" );
853 mCurrentTrustPolicy = newpolicy;
854 decorateCertTreeItem( mCurrentQCert, newpolicy,
nullptr );
855 btnSaveTrust->setEnabled(
false );
859 mTrustCacheRebuilt =
true;
863 void QgsAuthCertInfo::currentPolicyIndexChanged(
int indx )
866 btnSaveTrust->setEnabled( newpolicy != mCurrentTrustPolicy );
869 void QgsAuthCertInfo::decorateCertTreeItem(
const QSslCertificate &cert,
875 item = treeHierarchy->currentItem();
920 bool manageCertTrust,
924 , mCertInfoWdgt( nullptr )
930 mCertInfoWdgt =
new QgsAuthCertInfo( cert, manageCertTrust,
this, connectionCAs );
934 Qt::Horizontal,
this );
bool rebuildTrustedCaCertsCache()
Rebuild trusted certificate authorities cache.
QDateTime effectiveDate() const
static QString certificateUsageTypeString(QgsAuthCertUtils::CertUsageType usagetype)
Certificate usage type strings per enum.
QString toString(Qt::DateFormat format) const
QString & append(QChar ch)
bool contains(const Key &key) const
QgsAuthCertInfo(const QSslCertificate &cert, bool manageCertTrust=false, QWidget *parent=nullptr, const QList< QSslCertificate > &connectionCAs=QList< QSslCertificate >())
static QgsAuthManager * instance()
Enforce singleton pattern.
QList< T > values() const
static void removeChildren_(QTreeWidgetItem *item)
Qt::BrushStyle style() const
static QString qcaKnownConstraint(QCA::ConstraintTypeKnown constraint)
Certificate well-known constraint strings per enum.
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
const T & at(int i) const
QByteArray toUpper() const
Widget for viewing detailed info on a certificate and its hierarchical trust chain.
void moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)
QString join(const QString &separator) const
QMultiMap< QSsl::AlternateNameEntryType, QString > alternateSubjectNames() const
static QList< QgsAuthCertUtils::CertUsageType > certificateUsageTypes(const QSslCertificate &cert)
Try to determine the certificates usage types.
QString tr(const char *sourceText, const char *disambiguation, int n)
Utilities for working with certificates and keys.
void setBold(bool enable)
QString number(int n, int base)
static QColor redColor()
Red color representing invalid, untrusted, etc.
void append(const T &value)
int toInt(bool *ok) const
static QString getCertDistinguishedName(const QSslCertificate &qcert, const QCA::Certificate &acert=QCA::Certificate(), bool issuer=false)
Get combined distinguished name for certificate.
QSslKey publicKey() const
QgsAuthCertInfoDialog(const QSslCertificate &cert, bool manageCertTrust, QWidget *parent=nullptr, const QList< QSslCertificate > &connectionCAs=QList< QSslCertificate >())
Construct a dialog displaying detailed info on a certificate and its hierarchical trust chain...
static void setItemBold_(QTreeWidgetItem *item)
QByteArray mid(int pos, int len) const
void setMargin(int margin)
bool storeCertTrustPolicy(const QSslCertificate &cert, QgsAuthCertUtils::CertTrustPolicy policy)
Store user trust value for a certificate.
void setAlignment(QFlags< Qt::AlignmentFlag > flag)
QByteArray digest(QCryptographicHash::Algorithm algorithm) const
bool contains(const T &value) const
void setItalic(bool enable)
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Get the sha1 hash for certificate.
static QString redTextStyleSheet(const QString &selector="*")
Red text stylesheet representing invalid, untrusted, etc.
void setReadOnly(bool ro)
QByteArray serialNumber() const
QDateTime currentDateTime()
QByteArray version() const
QDateTime expiryDate() const
const QMap< QString, QPair< QgsAuthCertUtils::CaCertSource, QSslCertificate > > getCaCertsCache()
Get all CA certs mapped to their sha1 from cache.
#define SSL_SUBJECT_INFO(var, prop)
static QString qcaSignatureAlgorithm(QCA::SignatureAlgorithm algorithm)
Certificate signature algorithm strings per enum.
const T & peekPrevious() const
void setTextAlignment(int column, int alignment)
CertTrustPolicy
Type of certificate trust policy.
static QString getColonDelimited(const QString &txt)
Get string with colon delimeters every 2 characters.
void setCursorPosition(int)
QgsAuthCertUtils::CertTrustPolicy defaultCertTrustPolicy()
Get the default certificate trust policy perferred by user.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setColor(const QColor &color)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
#define SSL_ISSUER_INFO(var, prop)
static QString getCaSourceName(QgsAuthCertUtils::CaCertSource source, bool single=false)
Get the general name for CA source enum type.
static QString resolvedCertName(const QSslCertificate &cert, bool issuer=false)
Get the general name via RFC 5280 resolution.
static QString qcaValidityMessage(QCA::Validity validity)
Certificate validity check messages per enum.
const T value(const Key &key) const
bool rebuildCertTrustCache()
Rebuild certificate authority cache.