Mercurial > trustbridge
view ui/certificate.cpp @ 1300:a3b0f5de3eeb
(issue149) licenses: Mozilla completed.
author | Bernhard Reiter <bernhard@intevation.de> |
---|---|
date | Mon, 29 Sep 2014 16:30:39 +0200 |
parents | c2fd36cd4093 |
children | 60e481aa75ca |
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "certificate.h" #include <QDebug> #include <QFile> #include <QStringList> #include <QObject> #include <QProcess> #include <QTemporaryFile> #include <polarssl/sha1.h> #include "certhelp.h" #include "listutil.h" #ifdef WIN32 #include <cryptuiapi.h> #endif /* Qt wrapper around certhelp functions. */ QString getX509Value(x509_name *namebuf, unsigned char *oid) { QString retval; char * buf = get_oid_valstr(namebuf, oid); if (buf == NULL) { return retval; } retval = QString::fromUtf8(buf, -1); free(buf); return retval; } void Certificate::parseDetails(const QByteArray& cert) { x509_crt chain; x509_crt_init(&chain); if (x509_crt_parse_der(&chain, (const unsigned char *)cert.data(), cert.size()) != 0) { qDebug() << "Failed to parse cert.."; return; } mValidFrom = QDateTime(QDate(chain.valid_from.year, chain.valid_from.mon, chain.valid_from.day), QTime(chain.valid_from.hour, chain.valid_from.min, chain.valid_from.sec)); mValidTo = QDateTime(QDate(chain.valid_to.year, chain.valid_to.mon, chain.valid_to.day), QTime(chain.valid_to.hour, chain.valid_to.min, chain.valid_to.sec)); mSubjectCN = getX509Value(&(chain.subject), CERT_OID_CN); mSubjectOU = getX509Value(&(chain.subject), CERT_OID_OU); mSubjectO = getX509Value(&(chain.subject), CERT_OID_O); mSubjectSN = getX509Value(&(chain.subject), CERT_OID_SN); /* Calculate sha1 fingerprint */ unsigned char sha1sum[20]; sha1(chain.raw.p, chain.raw.len, sha1sum); for (int i=0; i < 20; i++) { mFingerprint += QString("%1").arg(sha1sum[i], 0, 16).rightJustified(2, '0'); if (i != 19) { mFingerprint += ":"; } mFingerprint = mFingerprint.toUpper(); } x509_crt_free(&chain); mDetails = QObject::tr("Certificate:\n" " <bold>%1</bold>\n" " %2, %3\n\n" "Serial number:\n" "%4\n" "Valid from: <bold>%5</bold> to <bold>%6</bold>\n\n" "Issued by: ..") .arg(mSubjectCN) .arg(mSubjectO) .arg(mSubjectOU) .arg(mSubjectSN) .arg(QLocale::system().toString(mValidFrom)) .arg(QLocale::system().toString(mValidTo)); } Certificate::Certificate(const QByteArray& derData) : mValid(false), mEditable(false) { if (derData.isEmpty()) { return; } parseDetails(derData); mValid = !mSubjectCN.isEmpty(); /* Default is installation for new certificates */ mBaseLine = QString::fromLatin1("I:") + derData.toBase64(); } Certificate::Certificate(const QString& b64Line) : mValid(false), mEditable(false) { if (b64Line.isEmpty()) { return; } /* Cut of the first two chars (e.g. I: and decode) */ QByteArray derData = QByteArray::fromBase64( b64Line.right(b64Line.size() - 2).toLatin1()); parseDetails(derData); /* If the subject CN is set then at least one x509parse * in polarssl was successfull. And a root certificate * always needs to have a subject CN */ mValid = !mSubjectCN.isEmpty(); mBaseLine = b64Line; } QString Certificate::shortDescription() const { if (!isValid()) { return QObject::tr("Failed to parse certificate"); } QString ret = mSubjectCN; /* Necessary by definition */ /* if (!mSubjectO.isEmpty()) { ret += " - " + mSubjectO; } */ return ret; } QList<Certificate> Certificate::fromFileName(const QString& file_name) { /* We read the file using Qt to avoid filename encoding problems * on Windows */ QFile certificateFile(file_name); QByteArray fileContent; QList<Certificate> retval; x509_crt chain; int ret = 0; if (!certificateFile.open(QIODevice::ReadOnly)) { qDebug() << "Failed to read file."; return retval; } if (certificateFile.size() > MAX_LINE_LENGTH * MAX_LINES) { qDebug() << "File too large"; return retval; } fileContent = certificateFile.readAll(); x509_crt_init(&chain); ret = x509_crt_parse(&chain, reinterpret_cast<const unsigned char*>(fileContent.constData()), fileContent.size()); if (ret < 0) { qDebug() << "Failed to parse certificates."; return retval; } if (ret > 0) { qDebug() << "Some certificates could not be parsed."; } x509_crt *iter = &chain; while (iter) { QByteArray derData(reinterpret_cast<const char*>(iter->raw.p), static_cast<int>(iter->raw.len)); retval << Certificate(derData); iter = iter->next; } x509_crt_free(&chain); return retval; } void Certificate::setInstallCert(bool install) { if (install && mBaseLine.startsWith("R:")) { mBaseLine.replace(0, 1, "I"); } else if (!install && mBaseLine.startsWith("I:")) { mBaseLine.replace(0, 1, "R"); } } #ifdef WIN32 bool Certificate::showNativeUI(void *parent) { /* Cut of the first two chars (e.g. I: and decode) */ bool retval = false; QByteArray pemData = QByteArray( mBaseLine.right(mBaseLine.size() - 2).toLatin1()); PCCERT_CONTEXT pCert = b64_to_cert_context (pemData.data(), pemData.size()); typedef BOOL (CALLBACK* LPFNVIEWDLG)(DWORD,const void *,HWND,LPCWSTR,DWORD,void *); LPFNVIEWDLG funcPtr; /* CryptUIDlgViewContext is not part of mingw 3.1.0 * so we workaround this by geting the process address dynamically. */ HMODULE hmod = LoadLibraryW(L"cryptui"); if (!hmod) { qDebug() << "Failed to open Cryptui.dll"; goto done; } funcPtr = (LPFNVIEWDLG) GetProcAddress (hmod, "CryptUIDlgViewContext"); if (!funcPtr) { qDebug() << "Failed to find Address of CryptUIDlgViewContext"; goto done; } if (pCert == NULL) { qDebug() << "Failed to parse certificate."; goto done; } if (!funcPtr(CERT_STORE_CERTIFICATE_CONTEXT, pCert, (HWND) parent, NULL, // Default Title 0, NULL)) { qDebug() << "Failed to view certificate."; retval = false; goto done; } retval = true; done: if (pCert) { CertFreeCertificateContext(pCert); } if (hmod) { FreeLibrary(hmod); } return retval; } #else bool Certificate::showNativeUI(void *parent) { QTemporaryFile *tmpCert = new QTemporaryFile; tmpCert->open(); tmpCert->write("-----BEGIN CERTIFICATE-----\n"); tmpCert->write(mBaseLine.right(mBaseLine.size() - 2).toLatin1()); tmpCert->write("-----END CERTIFICATE-----\n"); tmpCert->close(); QStringList args; args << tmpCert->fileName(); QProcess *viewer = new QProcess(); viewer->setProgram("gcr-viewer"); viewer->setArguments(args); QObject::connect (viewer, SIGNAL(finished(int, QProcess::ExitStatus)), tmpCert, SLOT(deleteLater())); QObject::connect (viewer, SIGNAL(finished(int, QProcess::ExitStatus)), viewer, SLOT(deleteLater())); viewer->start(); return !(!viewer->waitForStarted() || viewer->state() == QProcess::NotRunning); } #endif