mirror of
https://github.com/chris2511/xca.git
synced 2026-09-14 11:06:19 +05:00
Close #104: Also show sha256 digests of public keys
Print digest of public keys in the key details in different formats: Print SHA256 SSH digest as used to by SSH users: ssh-keygen -l -f ~/.ssh/id_rsa.pub Print SHA1 X509 key digest as shown in the Subject key identifier of a certificate Print SHA256 digest as in: openssl pkey -pubout -outform DER < key.pem | sha256sum as requested by this issue. Refactored digesting functionality by a generic Digest() function working with QByteArrays. The function formatHash() now also expects a QByteArray input.
This commit is contained in:
parent
c41bbf9b23
commit
1bc340a0ef
27
lib/func.cpp
27
lib/func.cpp
@ -10,6 +10,7 @@
|
||||
#include "func.h"
|
||||
#include "exception.h"
|
||||
#include "lib/asn1time.h"
|
||||
#include "lib/settings.h"
|
||||
#include "widgets/validity.h"
|
||||
#include "widgets/XcaWarning.h"
|
||||
#include <openssl/objects.h>
|
||||
@ -485,13 +486,27 @@ bool _ign_openssl_error(const QString txt, const char *file, int line)
|
||||
return !errtxt.isEmpty();
|
||||
}
|
||||
|
||||
QString formatHash(const unsigned char *md, unsigned size, bool colon)
|
||||
QString formatHash(const QByteArray &data, QString sep, int width)
|
||||
{
|
||||
QString s, t;
|
||||
for (unsigned j = 0; j < size; j++)
|
||||
s += t.sprintf("%02X%s", md[j],
|
||||
(j+1 == size) || !colon ? "" : ":");
|
||||
return s;
|
||||
return QString(data.toHex()).toUpper()
|
||||
.replace(QRegExp(QString("(.{%1})(?=.)").arg(width)),
|
||||
QString("\\1") + sep);
|
||||
}
|
||||
|
||||
QByteArray Digest(const QByteArray &data, const EVP_MD *type)
|
||||
{
|
||||
unsigned int n;
|
||||
unsigned char m[EVP_MAX_MD_SIZE];
|
||||
|
||||
EVP_Digest(data.constData(), data.size(), m, &n, type, NULL);
|
||||
openssl_error();
|
||||
return QByteArray((char*)m, (int)n);
|
||||
}
|
||||
|
||||
QString fingerprint(const QByteArray &data, const EVP_MD *type)
|
||||
{
|
||||
return formatHash(Digest(data, type),
|
||||
Settings["fp_separator"], Settings["fp_digits"]);
|
||||
}
|
||||
|
||||
void inc_progress_bar(int, int, void *p)
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include "base.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
class Validity;
|
||||
extern QString currentDB;
|
||||
@ -31,7 +32,7 @@ QString getFullFilename(const QString &filename, const QString &selectedFilter);
|
||||
QStringList getLibExtensions();
|
||||
QString hostId();
|
||||
|
||||
QString formatHash(const unsigned char *md, unsigned size, bool colon = true);
|
||||
QString formatHash(const QByteArray &data, QString sep = ":", int width = 2);
|
||||
QByteArray filename2bytearray(const QString &fname);
|
||||
QString filename2QString(const char *fname);
|
||||
QString compressFilename(QString filename, int maxlen = 50);
|
||||
@ -39,6 +40,9 @@ QString compressFilename(QString filename, int maxlen = 50);
|
||||
QString asn1ToQString(const ASN1_STRING *str, bool quote = false);
|
||||
ASN1_STRING *QStringToAsn1(QString s, int nid);
|
||||
|
||||
QByteArray Digest(const QByteArray &data, const EVP_MD *type);
|
||||
QString fingerprint(const QByteArray &data, const EVP_MD *type);
|
||||
|
||||
const char *OBJ_ln2sn(const char *ln);
|
||||
const char *OBJ_sn2ln(const char *sn);
|
||||
const char *OBJ_obj2sn(ASN1_OBJECT *a);
|
||||
|
||||
@ -403,10 +403,7 @@ static QString icsValue(QString s)
|
||||
QStringList pki_base::icsVEVENT(const a1time &expires,
|
||||
const QString &summary, const QString &description) const
|
||||
{
|
||||
QByteArray ba = i2d();
|
||||
unsigned char md[MD5_DIGEST_LENGTH];
|
||||
MD5((const unsigned char *)ba.constData(), ba.length(), md);
|
||||
QString uniqueid = formatHash(md, MD5_DIGEST_LENGTH, false);
|
||||
QString uniqueid = formatHash(Digest(i2d(), EVP_sha1()), "");
|
||||
QString desc = icsValue(description + "\n----------\n" + comment);
|
||||
QString alarm = Settings["ical_expiry"];
|
||||
return QStringList() <<
|
||||
|
||||
@ -834,63 +834,21 @@ QVariant pki_evp::getIcon(const dbheader *hd) const
|
||||
|
||||
QString pki_evp::md5passwd(QByteArray pass)
|
||||
{
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
EVP_MD_CTX mdctxbuf;
|
||||
#endif
|
||||
EVP_MD_CTX *mdctx;
|
||||
int n;
|
||||
unsigned char m[EVP_MAX_MD_SIZE];
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
mdctx = EVP_MD_CTX_new();
|
||||
#else
|
||||
mdctx = &mdctxbuf;
|
||||
#endif
|
||||
|
||||
EVP_DigestInit(mdctx, EVP_md5());
|
||||
EVP_DigestUpdate(mdctx, pass.constData(), pass.size());
|
||||
EVP_DigestFinal(mdctx, m, (unsigned*)&n);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
#endif
|
||||
return formatHash(m, n);
|
||||
return formatHash(Digest(pass, EVP_md5()));
|
||||
}
|
||||
|
||||
QString pki_evp::_sha512passwd(QByteArray pass, QString salt,
|
||||
int size, int repeat)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
EVP_MD_CTX mdctxbuf;
|
||||
#endif
|
||||
EVP_MD_CTX *mdctx;
|
||||
QString str;
|
||||
int n;
|
||||
unsigned char m[EVP_MAX_MD_SIZE];
|
||||
Q_ASSERT(salt.length() >= size);
|
||||
|
||||
if (salt.length() < size) {
|
||||
abort();
|
||||
}
|
||||
str = salt.left(size);
|
||||
pass = str.toLatin1() + pass;
|
||||
salt = salt.left(size);
|
||||
pass = salt.toLatin1() + pass;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
mdctx = EVP_MD_CTX_new();
|
||||
#else
|
||||
mdctx = &mdctxbuf;
|
||||
#endif
|
||||
while (repeat--) {
|
||||
EVP_DigestInit(mdctx, EVP_sha512());
|
||||
EVP_DigestUpdate(mdctx, pass.constData(), pass.size());
|
||||
EVP_DigestFinal(mdctx, m, (unsigned*)&n);
|
||||
pass = QByteArray((char*)m, n);
|
||||
while (repeat--)
|
||||
pass = Digest(pass, EVP_sha512());
|
||||
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
#endif
|
||||
return str + formatHash(m, n, false);
|
||||
return salt + formatHash(pass, "");
|
||||
}
|
||||
|
||||
QString pki_evp::sha512passwd(QByteArray pass, QString salt)
|
||||
|
||||
@ -622,7 +622,7 @@ void pki_key::ssh_key_bn2data(const BIGNUM *bn, QByteArray *data)
|
||||
ssh_key_QBA2data(big, data);
|
||||
}
|
||||
|
||||
QByteArray pki_key::SSH2publicQByteArray()
|
||||
QByteArray pki_key::SSH2publicQByteArray(bool raw)
|
||||
{
|
||||
QByteArray txt, data;
|
||||
|
||||
@ -655,6 +655,8 @@ QByteArray pki_key::SSH2publicQByteArray()
|
||||
default:
|
||||
return QByteArray();
|
||||
}
|
||||
if (raw)
|
||||
return data;
|
||||
return txt + " " + data.toBase64() + "\n";
|
||||
}
|
||||
|
||||
@ -706,3 +708,51 @@ bool pki_key::verify_priv(EVP_PKEY *) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QString pki_key::fingerprint(const QString format)
|
||||
{
|
||||
const EVP_MD *md;
|
||||
QByteArray data;
|
||||
QStringList sl = format.toLower().split(" ");
|
||||
|
||||
if (sl.size() < 2)
|
||||
return QString("Invalid format: %1").arg(format);
|
||||
if (sl[0] == "ssh")
|
||||
data = SSH2publicQByteArray(true);
|
||||
else if (sl[0] == "x509")
|
||||
data = X509_PUBKEY_public_key();
|
||||
else if (sl[0] == "der")
|
||||
data = i2d_bytearray(I2D_VOID(i2d_PUBKEY), key);
|
||||
else
|
||||
return QString("Invalid format: %1").arg(sl[0]);
|
||||
|
||||
md = EVP_get_digestbyname(CCHAR(sl[1]));
|
||||
if (!md)
|
||||
return QString("Invalid hash: %1").arg(sl[1]);
|
||||
|
||||
if (sl.size() > 2 && sl[2] == "b64") {
|
||||
QString s(Digest(data, md).toBase64());
|
||||
s.chop(1);
|
||||
return s;
|
||||
}
|
||||
return ::fingerprint(data, md);
|
||||
}
|
||||
|
||||
QByteArray pki_key::X509_PUBKEY_public_key() const
|
||||
{
|
||||
X509_PUBKEY *pk = NULL;
|
||||
const unsigned char *p;
|
||||
int len;
|
||||
|
||||
X509_PUBKEY_set(&pk, key);
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10000000L
|
||||
p = pk->public_key->data;
|
||||
len = pk->public_key->length;
|
||||
#else
|
||||
X509_PUBKEY_get0_param(NULL, &p, &len, NULL, pk);
|
||||
#endif
|
||||
|
||||
QByteArray data((const char*)p, len);
|
||||
X509_PUBKEY_free(pk);
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -35,7 +35,8 @@ class pki_key: public pki_base
|
||||
EVP_PKEY *key;
|
||||
QString BN2QString(const BIGNUM *bn) const;
|
||||
QString BNoneLine(BIGNUM *bn) const;
|
||||
QByteArray SSH2publicQByteArray();
|
||||
QByteArray SSH2publicQByteArray(bool raw=false);
|
||||
QByteArray X509_PUBKEY_public_key() const;
|
||||
|
||||
private:
|
||||
BIGNUM *ssh_key_data2bn(QByteArray *ba, bool skip = false);
|
||||
@ -93,6 +94,7 @@ class pki_key: public pki_base
|
||||
QByteArray i2d() const;
|
||||
EVP_PKEY *load_ssh2_key(FILE *fp);
|
||||
void writeSSH2public(QString fname);
|
||||
QString fingerprint(const QString format);
|
||||
void resetUcount()
|
||||
{
|
||||
useCount = -1;
|
||||
|
||||
@ -838,13 +838,7 @@ void pki_x509::setPubKey(pki_key *key)
|
||||
|
||||
QString pki_x509::fingerprint(const EVP_MD *digest) const
|
||||
{
|
||||
unsigned int n;
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
|
||||
pki_openssl_error();
|
||||
X509_digest(cert, digest, md, &n);
|
||||
pki_openssl_error();
|
||||
return formatHash(md, n);
|
||||
return ::fingerprint(i2d_bytearray(I2D_VOID(i2d_X509), cert), digest);
|
||||
}
|
||||
|
||||
bool pki_x509::checkDate()
|
||||
|
||||
@ -35,6 +35,8 @@ settings::settings()
|
||||
defaul["ical_expiry"] = "1W";
|
||||
defaul["cert_expiry"] = "80%";
|
||||
defaul["serial_len"] = "64";
|
||||
defaul["fp_separator"] = ":";
|
||||
defaul["fp_digits"] = "2";
|
||||
|
||||
hostspecific << "pkcs11path" << "workingdir" << "mw_geometry";
|
||||
|
||||
|
||||
@ -193,6 +193,12 @@
|
||||
<layout class="QGridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="TextLabel1_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>MD5</string>
|
||||
</property>
|
||||
@ -200,6 +206,12 @@
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="CopyLabel" name="fpMD5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>An md5 hashsum of the certificate</string>
|
||||
</property>
|
||||
@ -207,6 +219,12 @@
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="TextLabel2_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SHA1</string>
|
||||
</property>
|
||||
@ -214,6 +232,12 @@
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="CopyLabel" name="fpSHA1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>A SHA-1 hashsum of the certificate</string>
|
||||
</property>
|
||||
@ -221,6 +245,12 @@
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="TextLabel2_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SHA256</string>
|
||||
</property>
|
||||
@ -228,6 +258,12 @@
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="CopyLabel" name="fpSHA256">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>A SHA-256 hashsum of the certificate</string>
|
||||
</property>
|
||||
@ -355,8 +391,8 @@
|
||||
<string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html></string>
|
||||
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"><br /></p></body></html></string>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
|
||||
@ -101,7 +101,7 @@
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="key">
|
||||
<attribute name="title">
|
||||
@ -325,6 +325,11 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="fingerprint">
|
||||
<attribute name="title">
|
||||
<string>Fingerprint</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="commenttab">
|
||||
<attribute name="title">
|
||||
<string>Comment</string>
|
||||
@ -339,8 +344,8 @@
|
||||
<string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@ -38,6 +38,30 @@ static QString CurveComment(int nid)
|
||||
}
|
||||
#endif
|
||||
|
||||
void KeyDetail::setupFingerprints(pki_key *key)
|
||||
{
|
||||
int pos = 0;
|
||||
QGridLayout *g = new QGridLayout(fingerprint);
|
||||
QStringList sl; sl <<
|
||||
"ssh MD5" << "ssh SHA256 B64" <<
|
||||
"x509 SHA1" << "DER SHA256";
|
||||
|
||||
foreach(QString type, sl) {
|
||||
qDebug() << type << key->fingerprint(type);
|
||||
|
||||
QLabel *left = new QLabel(fingerprint);
|
||||
CopyLabel *right = new CopyLabel(fingerprint);
|
||||
|
||||
left->setTextFormat(Qt::PlainText);
|
||||
left->setText(type);
|
||||
right->setText(key->fingerprint(type));
|
||||
|
||||
g->addWidget(left, pos, 0);
|
||||
g->addWidget(right, pos, 1);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
void KeyDetail::setKey(pki_key *key)
|
||||
{
|
||||
keyDesc->setText(key->getIntName());
|
||||
@ -49,6 +73,8 @@ void KeyDetail::setKey(pki_key *key)
|
||||
tlHeader->setText(tr("Details of the %1 key").arg(key->getTypeString()));
|
||||
comment->setPlainText(key->getComment());
|
||||
|
||||
setupFingerprints(key);
|
||||
|
||||
if (key->isPubKey()) {
|
||||
keyPrivEx->setText(tr("Not available"));
|
||||
keyPrivEx->setRed();
|
||||
|
||||
@ -19,6 +19,8 @@ class KeyDetail: public QDialog, public Ui::KeyDetail
|
||||
public:
|
||||
KeyDetail(QWidget *parent);
|
||||
void setKey(pki_key *key);
|
||||
void setupFingerprints(pki_key *key);
|
||||
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -68,12 +68,10 @@ void ClickLabel::disableToolTip()
|
||||
setToolTip(QString());
|
||||
}
|
||||
|
||||
|
||||
CopyLabel::CopyLabel(QWidget *parent)
|
||||
:DoubleClickLabel(parent)
|
||||
{
|
||||
setFrameShape(QFrame::Panel);
|
||||
setFrameShadow(QFrame::Sunken);
|
||||
setFrameStyle(QFrame::StyledPanel);
|
||||
setTextFormat(Qt::PlainText);
|
||||
|
||||
#if QT_VERSION >= 0x040200
|
||||
|
||||
Loading…
Reference in New Issue
Block a user