Skip to content
This repository has been archived by the owner on Sep 1, 2023. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow only sign with non-repudiation certificate
IB-6797

Signed-off-by: Raul Metsma <raul@metsma.ee>
  • Loading branch information
metsma committed Dec 16, 2020
1 parent 25809dd commit 82d5f5c
Show file tree
Hide file tree
Showing 23 changed files with 132 additions and 148 deletions.
2 changes: 1 addition & 1 deletion VERSION.mk
Expand Up @@ -18,6 +18,6 @@

MAJOR_VERSION=1
MINOR_VERSION=1
RELEASE_VERSION=2
RELEASE_VERSION=3
VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(RELEASE_VERSION)
VERSIONEX=$(VERSION).$(BUILD_NUMBER)
49 changes: 20 additions & 29 deletions host-linux/CertificateSelection.h
Expand Up @@ -35,7 +35,7 @@

class CertificateSelection: public QDialog {
public:
static QVariantMap getCert(bool forSigning)
static QVariantMap getCert()
{
try {
QList<QStringList> certs;
Expand Down Expand Up @@ -66,8 +66,8 @@ class CertificateSelection: public QDialog {
}
}

if (forSigning != isNonRepudiation) {
_log("certificate is non-repu: %u, requesting signing certificate %u, moving on to next token...", isNonRepudiation, forSigning);
if (!isNonRepudiation) {
_log("certificate is not non-repu: moving on to next token...");
continue;
}

Expand All @@ -78,10 +78,10 @@ class CertificateSelection: public QDialog {
}
if (certs.empty())
return {{"result", "no_certificates"}};
CertificateSelection dialog(certs);
if (dialog.exec() == 0)
int result = CertificateSelection(certs).exec();
if (result == -1)
return {{"result", "user_cancel"}};
return {{"cert", certs.at(dialog.table->currentIndex().row())[3]}};
return {{"cert", certs.at(result)[3]}};
} catch (const BaseException &e) {
qDebug() << e.what();
return {{"result", QString::fromStdString(e.getErrorCode())}};
Expand All @@ -98,48 +98,39 @@ class CertificateSelection: public QDialog {
}

CertificateSelection(const QList<QStringList> &certs)
: message(new QLabel(this))
, table(new QTreeWidget(this))
, buttons(new QDialogButtonBox(this))
{
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(message);
layout->addWidget(table);
layout->addWidget(buttons);
layout->addWidget(new QLabel(Labels::l10n.get("cert info").c_str()));

setWindowFlags(Qt::WindowStaysOnTopHint);
setWindowTitle(Labels::l10n.get("select certificate").c_str());
message->setText(Labels::l10n.get("cert info").c_str());

QTreeWidget *table = new QTreeWidget(this);
layout->addWidget(table);
table->setColumnCount(3);
table->setRootIsDecorated(false);
table->setHeaderLabels(QStringList()
<< Labels::l10n.get("certificate").c_str()
<< Labels::l10n.get("type").c_str()
<< Labels::l10n.get("valid to").c_str());
table->setHeaderLabels({
Labels::l10n.get("certificate").c_str(),
Labels::l10n.get("type").c_str(),
Labels::l10n.get("valid to").c_str()});
table->header()->setStretchLastSection(false);
table->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
table->header()->setSectionResizeMode(0, QHeaderView::Stretch);
for(const QStringList &row: certs)
table->insertTopLevelItem(0, new QTreeWidgetItem(table, row));
table->setCurrentIndex(table->model()->index(0, 0));

ok = buttons->addButton(Labels::l10n.get("select").c_str(), QDialogButtonBox::AcceptRole);
cancel = buttons->addButton(Labels::l10n.get("cancel").c_str(), QDialogButtonBox::RejectRole);
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(table, &QTreeWidget::clicked, [&]{
ok->setEnabled(true);
});
QDialogButtonBox *buttons = new QDialogButtonBox(this);
layout->addWidget(buttons);
QPushButton *ok = buttons->addButton(Labels::l10n.get("select").c_str(), QDialogButtonBox::AcceptRole);
buttons->addButton(Labels::l10n.get("cancel").c_str(), QDialogButtonBox::RejectRole);
connect(buttons, &QDialogButtonBox::accepted, this, [this, table] { done(table->currentIndex().row()); });
connect(buttons, &QDialogButtonBox::rejected, this, [this] { done(-1); });
connect(table, &QTreeWidget::clicked, [ok] { ok->setEnabled(true); });

show();
// Make sure window is in foreground and focus
raise();
activateWindow();
}

QLabel *message;
QTreeWidget *table;
QDialogButtonBox *buttons;
QPushButton *ok = nullptr, *cancel = nullptr;
};
59 changes: 25 additions & 34 deletions host-linux/Signer.h
Expand Up @@ -47,6 +47,21 @@ class Signer: public QDialog {
public:
static QVariantMap sign(const QString &hash, const QString &cert) {
std::vector<unsigned char> data = fromHex(cert);
QSslCertificate c(QByteArray::fromRawData((const char*)data.data(), int(data.size())), QSsl::Der);
bool isNonRepudiation = false;
for(const QSslCertificateExtension &ex: c.extensions())
{
if(ex.name() == QStringLiteral("keyUsage"))
{
for(const QVariant &item: ex.value().toList())
if(item.toString() == QStringLiteral("Non Repudiation"))
isNonRepudiation = true;
}
}
if (!isNonRepudiation) {
return {{"result", "invalid_argument"}};
}

PKCS11CardManager::Token selected;
PKCS11Path::Params p11 = PKCS11Path::getPkcs11ModulePath();
PKCS11CardManager pkcs11(p11.path);
Expand All @@ -65,26 +80,8 @@ class Signer: public QDialog {
if(selected.cert.empty())
return {{"result", "invalid_argument"}};

QSslCertificate c(QByteArray::fromRawData((const char*)data.data(), int(data.size())), QSsl::Der);
bool isNonRepudiation = false;
for(const QSslCertificateExtension &ex: c.extensions())
{
if(ex.name() == QStringLiteral("keyUsage"))
{
for(const QVariant &item: ex.value().toList())
if(item.toString() == QStringLiteral("Non Repudiation"))
isNonRepudiation = true;
}
}
QString label;
if (isNonRepudiation) {
label = Labels::l10n.get(selected.pinpad ? "sign PIN pinpad" : "sign PIN").c_str();
label.replace("@PIN@", p11.signPINLabel.c_str());
}
else {
label = Labels::l10n.get(selected.pinpad ? "auth PIN pinpad" : "auth PIN").c_str();
label.replace("@PIN@", p11.authPINLabel.c_str());
}
QString label = Labels::l10n.get(selected.pinpad ? "sign PIN pinpad" : "sign PIN").c_str();
label.replace("@PIN@", p11.signPINLabel.c_str());

bool isInitialCheck = true;
for (int retriesLeft = selected.retry; retriesLeft > 0; ) {
Expand Down Expand Up @@ -172,48 +169,46 @@ class Signer: public QDialog {

Signer(const QString &label, unsigned long minPinLen, bool isPinpad)
: nameLabel(new QLabel(this))
, pinLabel(new QLabel(this))
, errorLabel(new QLabel(this))
{
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(errorLabel);
layout->addWidget(nameLabel);
layout->addWidget(pinLabel);
layout->addWidget(new QLabel(label, this));

setMinimumWidth(400);
setWindowFlags(Qt::WindowStaysOnTopHint);
pinLabel->setText(label);
errorLabel->setTextFormat(Qt::RichText);
errorLabel->hide();

if(isPinpad) {
setWindowFlags((windowFlags()|Qt::CustomizeWindowHint) & ~Qt::WindowCloseButtonHint);
progress = new QProgressBar(this);
QProgressBar *progress = new QProgressBar(this);
progress->setRange(0, 30);
progress->setValue(progress->maximum());
progress->setTextVisible(false);

statusTimer = new QTimeLine(progress->maximum() * 1000, this);
QTimeLine *statusTimer = new QTimeLine(progress->maximum() * 1000, this);
statusTimer->setCurveShape(QTimeLine::LinearCurve);
statusTimer->setFrameRange(progress->maximum(), progress->minimum());
connect(statusTimer, &QTimeLine::frameChanged, progress, &QProgressBar::setValue);
statusTimer->start();

layout->addWidget(progress);
} else {
buttons = new QDialogButtonBox(this);
QDialogButtonBox *buttons = new QDialogButtonBox(this);
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
cancel = buttons->addButton(Labels::l10n.get("cancel").c_str(), QDialogButtonBox::RejectRole);
ok = buttons->addButton("OK", QDialogButtonBox::AcceptRole);
buttons->addButton(Labels::l10n.get("cancel").c_str(), QDialogButtonBox::RejectRole);
QPushButton *ok = buttons->addButton("OK", QDialogButtonBox::AcceptRole);
ok->setEnabled(false);

pin = new QLineEdit(this);
pin->setEchoMode(QLineEdit::Password);
pin->setFocus();
pin->setValidator(new QRegExpValidator(QRegExp(QString("\\d{%1,12}").arg(minPinLen)), pin));
pin->setMaxLength(12);
connect(pin, &QLineEdit::textEdited, [=](const QString &text){
connect(pin, &QLineEdit::textEdited, ok, [=](const QString &text) {
ok->setEnabled(text.size() >= int(minPinLen));
});

Expand All @@ -223,10 +218,6 @@ class Signer: public QDialog {
show();
}

QLabel *nameLabel, *pinLabel, *errorLabel;
QDialogButtonBox *buttons = nullptr;
QPushButton *ok = nullptr, *cancel = nullptr;
QLabel *nameLabel, *errorLabel;
QLineEdit *pin = nullptr;
QProgressBar *progress = nullptr;
QTimeLine *statusTimer = nullptr;
};
8 changes: 6 additions & 2 deletions host-linux/chrome-host.cpp
Expand Up @@ -117,8 +117,12 @@ void Application::parse()
resp = Signer::sign(json.value("hash").toString(), cert);
}
} else if (type == "CERT") {
resp = CertificateSelection::getCert(json.value("filter").toString() != "AUTH");
cert = resp.value("cert").toString();
if (json.value("filter").toString() == "AUTH") {
resp = {{"result", "invalid_argument"}};
} else {
resp = CertificateSelection::getCert();
cert = resp.value("cert").toString();
}
} else {
resp = {{"result", "invalid_argument"}};
}
Expand Down
2 changes: 1 addition & 1 deletion host-linux/chrome-token-signing.pro
Expand Up @@ -2,7 +2,7 @@ TEMPLATE = app
CONFIG += console c++11 link_pkgconfig
CONFIG -= app_bundle
QT += widgets network
isEmpty(VERSION):VERSION=1.1.2.0
isEmpty(VERSION):VERSION=1.1.3.0
PKGCONFIG += libpcsclite
INCLUDEPATH += ../host-shared
LIBS += -ldl
Expand Down
2 changes: 1 addition & 1 deletion host-osx/CertificateSelection.h
Expand Up @@ -20,6 +20,6 @@

@interface CertificateSelection : NSObject

+ (NSDictionary *)show:(bool)forSigning;
+ (NSDictionary *)show;

@end
19 changes: 10 additions & 9 deletions host-osx/CertificateSelection.mm
Expand Up @@ -56,7 +56,7 @@ - (bool)isDuplicate:(NSString*)certificate {
return false;
}

- (instancetype)init:(bool)forSigning
- (instancetype)init
{
if (self = [super init]) {
certificates = [[NSMutableArray alloc] init];
Expand All @@ -73,9 +73,8 @@ - (instancetype)init:(bool)forSigning
CFRelease(cert);

NSNumber *ku = dict[(__bridge id)kSecOIDKeyUsage][(__bridge id)kSecPropertyKeyValue];
const bool isNonRepudiation = ku.unsignedIntValue & kSecKeyUsageNonRepudiation;
if (forSigning != isNonRepudiation) {
_log("certificate is non-repu: %u, requesting signing certificate %u, moving on to next token...", isNonRepudiation, forSigning);
if ((ku.unsignedIntValue & kSecKeyUsageNonRepudiation) == 0) {
_log("certificate is not non-repu: moving on to next token...");
continue;
}

Expand Down Expand Up @@ -125,7 +124,9 @@ - (instancetype)init:(bool)forSigning
return self;
}

window.touchBar = [self makeTouchBar];
if (@available(macOS 10_12_2, *)) {
window.touchBar = [self makeTouchBar];
}
window.title = _L("select certificate");
cancelButton.title = _L("cancel");
okButton.title = _L("select");
Expand All @@ -141,10 +142,10 @@ - (instancetype)init:(bool)forSigning
return self;
}

+ (NSDictionary *)show:(bool)forSigning
+ (NSDictionary *)show
{
try {
CertificateSelection *dialog = [[CertificateSelection alloc] init:forSigning];
CertificateSelection *dialog = [[CertificateSelection alloc] init];
if (!dialog) {
return @{@"result": @"technical_error"};
}
Expand Down Expand Up @@ -209,7 +210,7 @@ - (IBAction)changeSelection:(id)sender

#pragma mark - NSTouchBarProvider

- (NSTouchBar *)makeTouchBar
- (NSTouchBar *)makeTouchBar NS_AVAILABLE_MAC(10_12_2)
{
NSTouchBar *touchBar = [[NSTouchBar alloc] init];
touchBar.delegate = self;
Expand All @@ -220,7 +221,7 @@ - (NSTouchBar *)makeTouchBar

#pragma mark - NSTouchBarDelegate

- (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
- (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier NS_AVAILABLE_MAC(10_12_2)
{
if ([identifier isEqualToString:touchBarItemGroupId])
{
Expand Down
25 changes: 13 additions & 12 deletions host-osx/PINDialog.mm
Expand Up @@ -131,7 +131,9 @@ - (instancetype)init:(NSString*)label pinpad:(BOOL)pinpad
else {
cancelButton.title = _L("cancel");
}
window.touchBar = [self makeTouchBar];
if (@available(macOS 10_12_2, *)) {
window.touchBar = [self makeTouchBar];
}
pinFieldLabel.stringValue = label;
}
return self;
Expand Down Expand Up @@ -186,18 +188,15 @@ + (NSDictionary *)show:(NSDictionary*)params cert:(NSString *)cert
CFRelease(data);
NSDictionary *dict = CFBridgingRelease(SecCertificateCopyValues(x509, nil, nil));
CFRelease(x509);
NSNumber *ku = dict[(__bridge id)kSecOIDKeyUsage][(__bridge id)kSecPropertyKeyValue];
if ((ku.unsignedIntValue & kSecKeyUsageNonRepudiation) == 0) {
return @{@"result": @"invalid_argument"};
}

bool isInitialCheck = true;
for (int retriesLeft = selected.retry; retriesLeft > 0; )
{
NSString *label;
NSNumber *ku = dict[(__bridge id)kSecOIDKeyUsage][(__bridge id)kSecPropertyKeyValue];
if (ku.unsignedIntValue & kSecKeyUsageNonRepudiation) {
label = [_L(selected.pinpad ? "sign PIN pinpad" : "sign PIN") stringByReplacingOccurrencesOfString:@"@PIN@" withString:@(p11.signPINLabel.c_str())];
}
else {
label = [_L(selected.pinpad ? "auth PIN pinpad" : "auth PIN") stringByReplacingOccurrencesOfString:@"@PIN@" withString:@(p11.authPINLabel.c_str())];
}
NSString *label = [_L(selected.pinpad ? "sign PIN pinpad" : "sign PIN") stringByReplacingOccurrencesOfString:@"@PIN@" withString:@(p11.signPINLabel.c_str())];
PINPanel *dialog = [[PINPanel alloc] init:label pinpad:selected.pinpad];
if (!dialog) {
return @{@"result": @"technical_error"};
Expand Down Expand Up @@ -310,7 +309,9 @@ - (void)controlTextDidChange:(NSNotification*)notification;
if (okButton.enabled != pinField.stringValue.length >= minPinLen)
{
okButton.enabled = pinField.stringValue.length >= minPinLen;
window.touchBar = [self makeTouchBar];
if (@available(macOS 10_12_2, *)) {
window.touchBar = [self makeTouchBar];
}
}
}

Expand All @@ -325,7 +326,7 @@ - (void)handleTimerTick:(NSTimer*)timer

#pragma mark - NSTouchBarProvider

- (NSTouchBar *)makeTouchBar
- (NSTouchBar *)makeTouchBar NS_AVAILABLE_MAC(10_12_2)
{
NSTouchBar *touchBar = [[NSTouchBar alloc] init];
touchBar.delegate = self;
Expand All @@ -336,7 +337,7 @@ - (NSTouchBar *)makeTouchBar

#pragma mark - NSTouchBarDelegate

- (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
- (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier NS_AVAILABLE_MAC(10_12_2)
{
if ([identifier isEqualToString:touchBarItemGroupId])
{
Expand Down
8 changes: 6 additions & 2 deletions host-osx/chrome-host.mm
Expand Up @@ -126,8 +126,12 @@ int main(int argc, const char * argv[]) {
result = @{@"result": @"not_allowed"};
}
else if([dict[@"type"] isEqualToString:@"CERT"]) {
result = [CertificateSelection show:![@"AUTH" isEqualToString:dict[@"filter"]]];
cert = (NSString*)result[@"cert"];
if ([@"AUTH" isEqualToString:dict[@"filter"]]) {
result = @{@"result": @"invalid_argument"};
} else {
result = [CertificateSelection show];
cert = (NSString*)result[@"cert"];
}
}
else if ([dict[@"type"] isEqualToString:@"SIGN"]) {
result = [PINPanel show:dict cert:cert];
Expand Down

0 comments on commit 82d5f5c

Please sign in to comment.