aheinecke@404: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik aheinecke@404: * Software engineering by Intevation GmbH aheinecke@404: * aheinecke@404: * This file is Free Software under the GNU GPL (v>=2) aheinecke@404: * and comes with ABSOLUTELY NO WARRANTY! aheinecke@404: * See LICENSE.txt for details. aheinecke@404: */ aheinecke@21: #include "certificate.h" aheinecke@82: #include andre@349: #include andre@186: #include aheinecke@21: #include aheinecke@21: andre@378: #include andre@378: aheinecke@338: #include "certhelp.h" andre@349: #include "listutil.h" aheinecke@94: aheinecke@338: /* Qt wrapper around certhelp functions. */ aheinecke@338: QString getX509Value(x509_name *namebuf, unsigned char *oid) { aheinecke@338: QString retval; aheinecke@338: char * buf = get_oid_valstr(namebuf, oid); aheinecke@338: if (buf == NULL) { aheinecke@338: return retval; aheinecke@338: } aheinecke@338: retval = QString::fromUtf8(buf, -1); aheinecke@338: free(buf); aheinecke@338: return retval; aheinecke@338: } aheinecke@338: aheinecke@338: void Certificate::parseDetails(const QByteArray& cert) { aheinecke@338: x509_crt chain; aheinecke@338: aheinecke@338: x509_crt_init(&chain); aheinecke@338: if (x509_crt_parse_der(&chain, (const unsigned char *)cert.data(), aheinecke@338: cert.size()) != 0) { aheinecke@338: qDebug() << "Failed to parse cert.."; aheinecke@338: return; aheinecke@338: } aheinecke@338: aheinecke@338: mValidFrom = QDateTime(QDate(chain.valid_from.year, aheinecke@338: chain.valid_from.mon, aheinecke@338: chain.valid_from.day), aheinecke@338: QTime(chain.valid_from.hour, aheinecke@338: chain.valid_from.min, aheinecke@338: chain.valid_from.sec)); aheinecke@338: aheinecke@338: mValidTo = QDateTime(QDate(chain.valid_to.year, aheinecke@338: chain.valid_to.mon, aheinecke@338: chain.valid_to.day), aheinecke@338: QTime(chain.valid_to.hour, aheinecke@338: chain.valid_to.min, aheinecke@338: chain.valid_to.sec)); aheinecke@338: aheinecke@338: mSubjectCN = getX509Value(&(chain.subject), CERT_OID_CN); andre@380: mIssuerCN = getX509Value(&(chain.issuer), CERT_OID_CN); aheinecke@338: mSubjectOU = getX509Value(&(chain.subject), CERT_OID_OU); aheinecke@338: mSubjectO = getX509Value(&(chain.subject), CERT_OID_O); andre@380: mIssuerO = getX509Value(&(chain.issuer), CERT_OID_O); aheinecke@338: mSubjectSN = getX509Value(&(chain.subject), CERT_OID_SN); andre@378: andre@378: /* Calculate sha1 fingerprint */ andre@378: unsigned char sha1sum[20]; andre@378: sha1(chain.raw.p, chain.raw.len, sha1sum); andre@378: for (int i=0; i < 20; i++) { aheinecke@403: mFingerprint += QString("%1").arg(sha1sum[i], 0, 16).rightJustified(2, '0'); andre@378: if (i != 19) { andre@378: mFingerprint += ":"; andre@378: } andre@379: mFingerprint = mFingerprint.toUpper(); andre@378: } andre@378: aheinecke@338: x509_crt_free(&chain); aheinecke@338: aheinecke@338: mDetails = QObject::tr("Certificate:\n" aheinecke@338: " %1\n" aheinecke@338: " %2, %3\n\n" aheinecke@338: "Serial number:\n" aheinecke@338: "%4\n" aheinecke@338: "Valid from: %5 to %6\n\n" aheinecke@338: "Issued by: ..") aheinecke@338: .arg(mSubjectCN) aheinecke@338: .arg(mSubjectO) aheinecke@338: .arg(mSubjectOU) aheinecke@338: .arg(mSubjectSN) aheinecke@338: .arg(QLocale::system().toString(mValidFrom)) aheinecke@338: .arg(QLocale::system().toString(mValidTo)); andre@378: aheinecke@338: } andre@186: andre@349: Certificate::Certificate(const QByteArray& derData) : andre@349: mValid(false) andre@349: { andre@349: if (derData.isEmpty()) { andre@349: return; andre@349: } andre@349: andre@349: parseDetails(derData); andre@349: andre@349: mValid = !mSubjectCN.isEmpty(); andre@349: andre@356: /* Default is installation for new certificates */ andre@356: mBaseLine = QString::fromLatin1("I:") + derData.toBase64(); andre@349: } andre@349: aheinecke@83: Certificate::Certificate(const QString& b64Line) : andre@186: mValid(false) aheinecke@81: { andre@204: if (b64Line.isEmpty()) { andre@204: return; andre@204: } andre@204: aheinecke@83: /* Cut of the first two chars (e.g. I: and decode) */ andre@349: QByteArray derData = QByteArray::fromBase64( aheinecke@83: b64Line.right(b64Line.size() - 2).toLatin1()); aheinecke@83: andre@349: parseDetails(derData); andre@186: aheinecke@338: /* If the subject CN is set then at least one x509parse aheinecke@338: * in polarssl was successfull. And a root certificate aheinecke@338: * always needs to have a subject CN */ aheinecke@338: mValid = !mSubjectCN.isEmpty(); aheinecke@83: aheinecke@83: mBaseLine = b64Line; aheinecke@81: } andre@186: aheinecke@338: QString Certificate::shortDescription() const { aheinecke@338: if (!isValid()) { aheinecke@338: return QObject::tr("Failed to parse certificate"); aheinecke@338: } aheinecke@338: aheinecke@338: QString ret = mSubjectCN; /* Necessary by definition */ aheinecke@338: if (!mSubjectO.isEmpty()) { aheinecke@338: ret += " - " + mSubjectO; aheinecke@338: } aheinecke@338: if (!mSubjectOU.isEmpty()) { aheinecke@338: ret += ", " + mSubjectOU; aheinecke@338: } aheinecke@338: return ret; andre@186: } andre@349: andre@349: QList Certificate::fromFileName(const QString& file_name) { andre@349: /* We read the file using Qt to avoid filename encoding problems andre@349: * on Windows */ andre@349: andre@349: /* TODO change qDebug errors into messageboxes */ andre@349: QFile certificateFile(file_name); andre@349: QByteArray fileContent; andre@349: QList retval; andre@349: x509_crt chain; andre@349: int ret = 0; andre@349: if (!certificateFile.open(QIODevice::ReadOnly)) { andre@349: qDebug() << "Failed to read file."; andre@349: return retval; andre@349: } andre@349: andre@349: if (certificateFile.size() > MAX_LINE_LENGTH * MAX_LINES) { andre@349: qDebug() << "File too large"; andre@349: return retval; andre@349: } andre@349: andre@349: fileContent = certificateFile.readAll(); andre@349: andre@349: x509_crt_init(&chain); andre@349: andre@349: ret = x509_crt_parse(&chain, andre@349: reinterpret_cast(fileContent.constData()), andre@349: fileContent.size()); andre@349: andre@349: if (ret < 0) { andre@349: qDebug() << "Failed to parse certificates."; andre@349: return retval; andre@349: } andre@349: andre@349: if (ret > 0) { andre@349: qDebug() << "Some certificates could not be parsed."; andre@349: /* Maybe return here? */ andre@349: } andre@349: andre@349: x509_crt *iter = &chain; andre@349: andre@349: while (iter) { andre@349: QByteArray derData(reinterpret_cast(iter->raw.p), andre@349: static_cast(iter->raw.len)); andre@349: retval << Certificate(derData); andre@349: iter = iter->next; andre@349: } andre@349: x509_crt_free(&chain); andre@349: andre@349: return retval; andre@349: } rrenkert@355: rrenkert@352: void Certificate::setInstallCert(bool install) rrenkert@352: { rrenkert@352: if (install && mBaseLine.startsWith("R:")) { rrenkert@352: mBaseLine.replace(0, 1, "I"); rrenkert@352: } rrenkert@352: else if (!install && mBaseLine.startsWith("I:")) { rrenkert@352: mBaseLine.replace(0, 1, "R"); rrenkert@352: } rrenkert@352: }