first version to show an save certificates from files or urls

master
Marc Wäckerlin 9 years ago
parent 06513a9d34
commit 768e910272
  1. 1
      COPYING
  2. 4
      ChangeLog
  3. 1
      INSTALL
  4. 133
      src/certificate.hxx
  5. 59
      src/certificate.ui
  6. 79
      src/certman.hxx
  7. 109
      src/certman.ui
  8. 4
      src/certman_de.ts
  9. 4
      src/certman_en.ts
  10. 4
      src/certman_fr.ts
  11. 4
      src/certman_it.ts
  12. 4
      src/makefile.am
  13. 73
      src/openfromurl.hxx
  14. 101
      src/openfromurl.ui

@ -0,0 +1 @@
/usr/share/automake-1.14/COPYING

@ -0,0 +1,4 @@
2015-10-08 08:50 marc
* .: structure

@ -0,0 +1 @@
/usr/share/automake-1.14/INSTALL

@ -0,0 +1,133 @@
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#ifndef CERTIFICATE_HXX
#define CERTIFICATE_HXX
#include <ui_certificate.hxx>
#include <QtCore/QDateTime>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QtNetwork/QSslCertificate>
#include <QMdiSubWindow>
#include <QtCore/QDebug>
#if QT_VERSION >= 0x050000
namespace QSsl {
typedef AlternativeNameEntryType AlternateNameEntryType;
}
#endif
class Certificate: public QWidget, protected Ui::Certificate {
Q_OBJECT;
public:
Certificate(QWidget * parent = 0): QWidget(parent) {
setupUi(this);
}
Certificate& certificate(const QSslCertificate& cert) {
_certificate = cert;
_cert->clear();
#if QT_VERSION < 0x050000
if (!cert.isValid()) return *this;
#endif
_cert->addTopLevelItem
((new QTreeWidgetItem
(QStringList()<<tr("Valid Since")
<<cert.effectiveDate().toString(Qt::SystemLocaleLongDate))));
_cert->addTopLevelItem
((new QTreeWidgetItem
(QStringList()<<tr("Valid Until")
<<cert.expiryDate().toString(Qt::SystemLocaleLongDate))));
if (!cert.subjectInfo(QByteArray("serialNumber")).isEmpty()) {
_cert->addTopLevelItem
((new QTreeWidgetItem
(QStringList()<<tr("SuisseID Number")
<<cert.subjectInfo(QByteArray("serialNumber")))));
}
_cert->addTopLevelItem
((new QTreeWidgetItem
(QStringList()<<tr("Certificate Serial Number")
<<cert.serialNumber())));
// _cert->addTopLevelItem
// ((new QTreeWidgetItem
// (QStringList()<<tr("Version")
// <<cert.version())));
QTreeWidgetItem *it(0);
_cert->addTopLevelItem
((it = new QTreeWidgetItem(QStringList()<<tr("Subject Info")<<"")));
for (QSslCertificate::SubjectInfo
si(QSslCertificate::StateOrProvinceName);
si>=QSslCertificate::Organization;
si=(QSslCertificate::SubjectInfo)((int)si-1))
if (!cert.subjectInfo(si).isEmpty())
it->addChild
((new QTreeWidgetItem
(QStringList()<<subjectInfo(si)<<cert.subjectInfo(si))));
QTreeWidgetItem *it2(0);
it->addChild
((it2 = new QTreeWidgetItem
(QStringList()<<tr("Alternate Subject")<<"")));
QMultiMap<QSsl::AlternateNameEntryType, QString>
#if QT_VERSION <0x050000
asns(cert.alternateSubjectNames())
#else
asns(cert.subjectAlternativeNames())
#endif
;
for (QMultiMap<QSsl::AlternateNameEntryType, QString>::iterator
asn(asns.begin()); asn!=asns.end(); ++asn)
it2->addChild
((new QTreeWidgetItem
(QStringList()<<alternateName(asn.key())<<asn.value())));
_cert->addTopLevelItem
((it = new QTreeWidgetItem(QStringList()<<tr("Issuer Info")<<"")));
for (QSslCertificate::SubjectInfo
si(QSslCertificate::StateOrProvinceName);
si>=QSslCertificate::Organization;
si=(QSslCertificate::SubjectInfo)((int)si-1))
if (!cert.issuerInfo(si).isEmpty())
it->addChild
((new QTreeWidgetItem
(QStringList()<<subjectInfo(si)<<cert.issuerInfo(si))));
_cert->expandAll();
_cert->resizeColumnToContents(0);
_cert->resizeColumnToContents(1);
return *this;
}
QSslCertificate certificate() {
return _certificate;
}
QString alternateName(QSsl::AlternateNameEntryType an) {
switch (an) {
case QSsl::EmailEntry: return tr("E-Mail");
case QSsl::DnsEntry: return tr("URL");
}
return tr("error", "unknown certificate subject alternate name");
}
QString subjectInfo(QSslCertificate::SubjectInfo si) {
switch (si) {
case QSslCertificate::Organization:
return tr("Organization");
case QSslCertificate::CommonName:
return tr("Common Name");
case QSslCertificate::LocalityName:
return tr("Locality");
case QSslCertificate::OrganizationalUnitName:
return tr("Organizational Unit");
case QSslCertificate::CountryName:
return tr("Country");
case QSslCertificate::StateOrProvinceName:
return tr("State or Province");
}
return tr("error", "unknown certificate subject info");
}
protected:
QSslCertificate _certificate;
};
#endif

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Certificate</class>
<widget class="QWidget" name="Certificate">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>320</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTreeWidget" name="_cert">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="rootIsDecorated">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<attribute name="headerCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Attribute</string>
</property>
</column>
<column>
<property name="text">
<string>Value</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

@ -11,18 +11,93 @@
#ifndef CERTMAN_HXX #ifndef CERTMAN_HXX
#define CERTMAN_HXX #define CERTMAN_HXX
#include <QMainWindow> #include <certificate.hxx>
#include <openfromurl.hxx>
#include <ui_certman.hxx> #include <ui_certman.hxx>
#include <QMainWindow>
#include <QFileDialog>
#include <QFileInfo>
#include <QRegExp>
#include <QDebug>
/// Main Window /// Main Window
/** Main window for certman */ /** Main window for certman */
class CertMan: public QMainWindow, protected Ui::CertMan { class CertMan: public QMainWindow, protected Ui::CertMan {
Q_OBJECT; Q_OBJECT;
public: public:
explicit CertMan(QWidget *parent = 0): QMainWindow(parent) { explicit CertMan(QWidget *parent = 0):
QMainWindow(parent),
_openFromURL(this) {
setupUi(this); setupUi(this);
connect(&_openFromURL, SIGNAL(certificate(QUrl, QSslCertificate)),
SLOT(certificate(QUrl, QSslCertificate)));
} }
virtual ~CertMan() {} virtual ~CertMan() {}
protected slots:
void on__actionOpenCertificate_triggered() {
QString fileName = QFileDialog::getOpenFileName(this);
if (fileName.isEmpty()) return;
QFile file(fileName);
file.open(QIODevice::ReadOnly);
QSslCertificate c(&file);
file.close();
if (c.isNull()) {
qDebug()<<QObject::trUtf8("Cannot read PEM certificate from file: %1")
.arg(fileName);
return;
}
Certificate* win(new Certificate(_mdi));
_mdi->addSubWindow(win)->setWindowTitle(QFileInfo(fileName).fileName());
win->show();
win->certificate(c);
}
void on__actionOpenFromURL_triggered() {
if (_openFromURL.exec()==QDialog::Accepted) {
_openFromURL.read();
}
}
void certificate(QUrl url, QSslCertificate cert) {
qDebug()<<"got certificate: "<<cert.subjectInfo(QSslCertificate::CommonName).join("/");
Certificate* win(new Certificate(_mdi));
_mdi->addSubWindow(win)->setWindowTitle
(url.host()+" - "+
cert.subjectInfo(QSslCertificate::CommonName).join("/"));
win->show();
win->certificate(cert);
}
void on__actionSaveAs_triggered() {
QMdiSubWindow* win(_mdi->currentSubWindow());
if (!win) return;
Certificate* cert(dynamic_cast<Certificate*>(win->widget()));
QString fileName(QFileDialog::getSaveFileName
(this,
win->windowTitle(),
win->windowTitle()
.replace(" ", "_").replace(QRegExp("\.(pem|der)$"), "")
+".pem",
tr("Certificates (*.der *.pem *.txt)")));
if (fileName.isEmpty()) return;
QFile file(fileName);
file.open(QIODevice::WriteOnly);
QFileInfo fileInfo(fileName);
if (fileInfo.suffix()=="der") {
QDataStream out(&file);
out<<cert->certificate().toDer();
} else if (fileInfo.suffix()=="pem") {
QDataStream out(&file);
out<<cert->certificate().toPem();
} else if (fileInfo.suffix()=="txt") {
QTextStream out(&file);
out<<cert->certificate().toText();
} else { // defaults to pem
QDataStream out(&file);
out<<cert->certificate().toPem();
}
file.close();
}
private:
OpenFromURL _openFromURL;
}; };
#endif #endif

@ -13,7 +13,13 @@
<property name="windowTitle"> <property name="windowTitle">
<string>CertMan</string> <string>CertMan</string>
</property> </property>
<widget class="QWidget" name="centralwidget"/> <widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QMdiArea" name="_mdi"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar"> <widget class="QMenuBar" name="menubar">
<property name="geometry"> <property name="geometry">
<rect> <rect>
@ -23,9 +29,108 @@
<height>22</height> <height>22</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="_actionOpenCertificate"/>
<addaction name="_actionOpenFromURL"/>
<addaction name="_actionSaveAs"/>
<addaction name="separator"/>
<addaction name="_actionExit"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menuWindows">
<property name="title">
<string>Windows</string>
</property>
<addaction name="_actionCascade"/>
<addaction name="_actionTile"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuWindows"/>
</widget> </widget>
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
<action name="_actionOpenCertificate">
<property name="text">
<string>Open Certificate ...</string>
</property>
</action>
<action name="_actionExit">
<property name="text">
<string>Exit</string>
</property>
</action>
<action name="_actionCascade">
<property name="text">
<string>Cascade</string>
</property>
</action>
<action name="_actionTile">
<property name="text">
<string>Tile</string>
</property>
</action>
<action name="_actionOpenFromURL">
<property name="text">
<string>Open From URL ...</string>
</property>
</action>
<action name="_actionSaveAs">
<property name="text">
<string>Save As ...</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections>
<connection>
<sender>_actionExit</sender>
<signal>triggered()</signal>
<receiver>CertMan</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>_actionTile</sender>
<signal>triggered()</signal>
<receiver>_mdi</receiver>
<slot>tileSubWindows()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>_actionCascade</sender>
<signal>triggered()</signal>
<receiver>_mdi</receiver>
<slot>cascadeSubWindows()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections>
</ui> </ui>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de">
</TS>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en">
</TS>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="fr">
</TS>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="it">
</TS>

@ -33,10 +33,10 @@ QT_PLUGINS = iconengines imageformats platforms
noinst_HEADERS = version.hxx noinst_HEADERS = version.hxx
## list all %.hxx files with Q_OBJECT as moc_%.cxx ## list all %.hxx files with Q_OBJECT as moc_%.cxx
certman_MOCFILES = moc_certman.cxx certman_MOCFILES = moc_certman.cxx moc_certificate.cxx moc_openfromurl.cxx
## list all %.ui files as ui_%.hxx ## list all %.ui files as ui_%.hxx
certman_UIFILES = ui_certman.hxx certman_UIFILES = ui_certman.hxx ui_certificate.hxx ui_openfromurl.hxx
## list all %.qrc resource files as qrc_%.cxx ## list all %.qrc resource files as qrc_%.cxx
## note: if there exists a directory %, the file %.qrc is generated from that ## note: if there exists a directory %, the file %.qrc is generated from that

@ -0,0 +1,73 @@
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#ifndef OPENFROMURL_HXX
#define OPENFROMURL_HXX
#include <ui_openfromurl.hxx>
#include <QDialog>
#include <QNetworkAccessManager>
#include <QNetworkReply>
class OpenFromURL: public QDialog, public Ui::OpenFromURL {
Q_OBJECT;
public:
OpenFromURL(QWidget* p): QDialog(p) {
setupUi(this);
}
QString url() {
return _url->currentText();
}
void read() {
QNetworkReply* reply
(_net.head(QNetworkRequest(QUrl("https://"+_url->currentText()))));
connect(reply, SIGNAL(finished()), SLOT(finished()));
connect(reply, SIGNAL(encrypted()), SLOT(encrypted()));
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)),
SLOT(sslErrors(const QList<QSslError>&)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
SLOT(error(QNetworkReply::NetworkError)));
}
signals:
void certificate(QUrl, QSslCertificate);
protected slots:
void on__buttons_accepted() {
_url->addItem(_url->currentText());
}
void finished() {
qDebug()<<"finished";
QNetworkReply* reply(dynamic_cast<QNetworkReply*>(sender()));
QList<QSslCertificate> certs(reply->sslConfiguration()
.peerCertificateChain());
qDebug()<<"number of peer certificates: "<<certs.size();
if (certs.size()) {
Q_FOREACH(QSslCertificate cert, certs) {
certificate(reply->url(), cert);
}
} else {
QSslCertificate cert(reply->sslConfiguration().peerCertificate());
if (!cert.isNull()) {
certificate(reply->url(), cert);
} else {
qDebug()<<"no peer certificate found";
}
}
}
void encrypted() {
qDebug()<<"encrypted";
}
void sslErrors(const QList<QSslError>& errors) {
qDebug()<<"sslErrors";
}
void error(QNetworkReply::NetworkError code) {
qDebug()<<"error";
}
private:
QNetworkAccessManager _net;
};
#endif

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OpenFromURL</class>
<widget class="QDialog" name="OpenFromURL">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>434</width>
<height>89</height>
</rect>
</property>
<property name="windowTitle">
<string>Open Certificate From URL</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Hostname:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="_url">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="_buttons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>_buttons</sender>
<signal>accepted()</signal>
<receiver>OpenFromURL</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>_buttons</sender>
<signal>rejected()</signal>
<receiver>OpenFromURL</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
Loading…
Cancel
Save