Skip to content

Commit

Permalink
select the certificate to use by its sha256 fingerprint
Browse files Browse the repository at this point in the history
Signed-off-by: Matthieu Gallien <[email protected]>
  • Loading branch information
mgallien committed Nov 30, 2023
1 parent 6bcada6 commit e187be5
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 110 deletions.
9 changes: 3 additions & 6 deletions src/gui/accountmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ constexpr auto serverVersionC = "serverVersion";
constexpr auto serverColorC = "serverColor";
constexpr auto serverTextColorC = "serverTextColor";
constexpr auto skipE2eeMetadataChecksumValidationC = "skipE2eeMetadataChecksumValidation";
constexpr auto encryptionCertificateSerialNumberC = "encryptionCertificateSerialNumber";
constexpr auto encryptionCertificateIssuerC = "encryptionCertificateIssuer";
constexpr auto encryptionCertificateSha256FingerprintC = "encryptionCertificateSha256Fingerprint";
constexpr auto generalC = "General";

constexpr auto dummyAuthTypeC = "dummy";
Expand Down Expand Up @@ -318,8 +317,7 @@ void AccountManager::saveAccountHelper(Account *acc, QSettings &settings, bool s
settings.setValue(QLatin1String(serverVersionC), acc->_serverVersion);
settings.setValue(QLatin1String(serverColorC), acc->_serverColor);
settings.setValue(QLatin1String(serverTextColorC), acc->_serverTextColor);
settings.setValue(QLatin1String(encryptionCertificateSerialNumberC), acc->encryptionCertificateSerialNumber());
settings.setValue(QLatin1String(encryptionCertificateIssuerC), acc->encryptionCertificateIssuer());
settings.setValue(QLatin1String(encryptionCertificateSha256FingerprintC), acc->encryptionCertificateFingerprint());
if (!acc->_skipE2eeMetadataChecksumValidation) {
settings.remove(QLatin1String(skipE2eeMetadataChecksumValidationC));
} else {
Expand Down Expand Up @@ -446,8 +444,7 @@ AccountPtr AccountManager::loadAccountHelper(QSettings &settings)

acc->setCredentials(CredentialsFactory::create(authType));

acc->setEncryptionCertificateSerialNumber(settings.value(QLatin1String(encryptionCertificateSerialNumberC)).toString());
acc->setEncryptionCertificateIssuer(settings.value(QLatin1String(encryptionCertificateIssuerC)).toString());
acc->setEncryptionCertificateFingerprint(settings.value(QLatin1String(encryptionCertificateSha256FingerprintC)).toByteArray());

// now the server cert, it is in the general group
settings.beginGroup(QLatin1String(generalC));
Expand Down
31 changes: 7 additions & 24 deletions src/libsync/account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1035,37 +1035,20 @@ QString Account::encryptionHardwareTokenDriverPath() const
return {};
}

QString Account::encryptionCertificateSerialNumber() const
QByteArray Account::encryptionCertificateFingerprint() const
{
return _encryptionCertificateSerialNumber;
return _encryptionCertificateFingerprint;
}

void Account::setEncryptionCertificateSerialNumber(const QString &serialNumber)
void Account::setEncryptionCertificateFingerprint(const QByteArray &fingerprint)
{
if (_encryptionCertificateSerialNumber == serialNumber) {
if (_encryptionCertificateFingerprint == fingerprint) {
return;
}

_encryptionCertificateSerialNumber = serialNumber;
_e2e.usbTokenInformation()->setSerialNumber(serialNumber);
Q_EMIT encryptionCertificateSerialNumberChanged();
Q_EMIT wantsAccountSaved(this);
}

QString Account::encryptionCertificateIssuer() const
{
return _encryptionCertificateIssuer;
}

void Account::setEncryptionCertificateIssuer(const QString &issuer)
{
if (_encryptionCertificateIssuer == issuer) {
return;
}

_encryptionCertificateIssuer = issuer;
_e2e.usbTokenInformation()->setIssuer(issuer);
Q_EMIT encryptionCertificateIssuerChanged();
_encryptionCertificateFingerprint = fingerprint;
_e2e.usbTokenInformation()->setSha256Fingerprint(fingerprint);
Q_EMIT encryptionCertificateFingerprintChanged();
Q_EMIT wantsAccountSaved(this);
}

Expand Down
18 changes: 5 additions & 13 deletions src/libsync/account.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ class OWNCLOUDSYNC_EXPORT Account : public QObject
Q_PROPERTY(bool askUserForMnemonic READ askUserForMnemonic WRITE setAskUserForMnemonic NOTIFY askUserForMnemonicChanged)
Q_PROPERTY(bool enforceUseHardwareTokenEncryption READ enforceUseHardwareTokenEncryption NOTIFY enforceUseHardwareTokenEncryptionChanged)
Q_PROPERTY(QString encryptionHardwareTokenDriverPath READ encryptionHardwareTokenDriverPath NOTIFY encryptionHardwareTokenDriverPathChanged)
Q_PROPERTY(QString encryptionCertificateSerialNumber READ encryptionCertificateSerialNumber WRITE setEncryptionCertificateSerialNumber NOTIFY encryptionCertificateSerialNumberChanged)
Q_PROPERTY(QString encryptionCertificateIssuer READ encryptionCertificateIssuer WRITE setEncryptionCertificateIssuer NOTIFY encryptionCertificateIssuerChanged)
Q_PROPERTY(QByteArray encryptionCertificateFingerprint READ encryptionCertificateFingerprint WRITE setEncryptionCertificateFingerprint NOTIFY encryptionCertificateFingerprintChanged)

public:
static AccountPtr create();
Expand Down Expand Up @@ -334,13 +333,9 @@ class OWNCLOUDSYNC_EXPORT Account : public QObject

[[nodiscard]] QString encryptionHardwareTokenDriverPath() const;

[[nodiscard]] QString encryptionCertificateSerialNumber() const;
[[nodiscard]] QByteArray encryptionCertificateFingerprint() const;

void setEncryptionCertificateSerialNumber(const QString &serialNumber);

[[nodiscard]] QString encryptionCertificateIssuer() const;

void setEncryptionCertificateIssuer(const QString &issuer);
void setEncryptionCertificateFingerprint(const QByteArray &fingerprint);

public slots:
/// Used when forgetting credentials
Expand Down Expand Up @@ -388,8 +383,7 @@ public slots:
void lockFileSuccess();
void lockFileError(const QString&);

void encryptionCertificateSerialNumberChanged();
void encryptionCertificateIssuerChanged();
void encryptionCertificateFingerprintChanged();

protected Q_SLOTS:
void slotCredentialsFetched();
Expand Down Expand Up @@ -464,9 +458,7 @@ private slots:

QHash<QString, QVector<SyncFileItem::LockStatus>> _lockStatusChangeInprogress;

QString _encryptionCertificateSerialNumber;

QString _encryptionCertificateIssuer;
QByteArray _encryptionCertificateFingerprint;

/* IMPORTANT - remove later - FIXME MS@2019-12-07 -->
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
Expand Down
35 changes: 11 additions & 24 deletions src/libsync/clientsideencryption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ constexpr char e2e_public[] = "_e2e-public";
constexpr char e2e_mnemonic[] = "_e2e-mnemonic";

constexpr auto metadataKeyJsonKey = "metadataKey";
constexpr auto certificateSerialNumberKey = "certificateSerialNumber";
constexpr auto certificateIssuerKey = "certificateIssuer";
constexpr auto certificateSha256FingerprintKey = "certificateSha256Fingerprint";

constexpr qint64 blockSize = 1024;

Expand Down Expand Up @@ -1206,11 +1205,6 @@ void ClientSideEncryption::initializeHardwareTokenEncryption(QWidget *settingsDi

for (auto certificateIndex = 0u; certificateIndex < keysCount; ++certificateIndex) {
const auto currentCertificate = &certificatesFromToken[certificateIndex];
qCInfo(lcCse()) << "certificate metadata:"
<< "label:" << currentCertificate->label;

const auto certificateId = QByteArray{reinterpret_cast<char*>(currentCertificate->id), static_cast<int>(currentCertificate->id_len)};
qCInfo(lcCse()) << "new certificate ID:" << certificateId.toBase64();

Bio out;
const auto ret = PEM_write_bio_X509(out, currentCertificate->x509);
Expand All @@ -1223,9 +1217,8 @@ void ClientSideEncryption::initializeHardwareTokenEncryption(QWidget *settingsDi

const auto result = BIO2ByteArray(out);
const auto sslCertificate = QSslCertificate{result, QSsl::Pem};
if (sslCertificate.issuerDisplayName() != _usbTokenInformation.issuer() ||
sslCertificate.serialNumber() != _usbTokenInformation.serialNumber()) {
qCInfo(lcCse()) << "skipping certificate from" << sslCertificate.issuerDisplayName() << "with serial number" << sslCertificate.serialNumber();
if (sslCertificate.digest(QCryptographicHash::Sha256).toBase64() != _usbTokenInformation.sha256Fingerprint()) {
qCInfo(lcCse()) << "skipping certificate from" << sslCertificate.subjectDisplayName() << "with fingerprint" << sslCertificate.digest(QCryptographicHash::Sha256).toBase64();
continue;
}

Expand Down Expand Up @@ -1615,10 +1608,8 @@ void ClientSideEncryption::forgetSensitiveData(const AccountPtr &account)
deletePrivateKeyJob->start();
deleteCertJob->start();
deleteMnemonicJob->start();
_usbTokenInformation.setSerialNumber({});
_usbTokenInformation.setIssuer({});
account->setEncryptionCertificateSerialNumber({});
account->setEncryptionCertificateIssuer({});
_usbTokenInformation.setSha256Fingerprint({});
account->setEncryptionCertificateFingerprint({});
_tokenPublicKey = nullptr;
_tokenPrivateKey = nullptr;
}
Expand Down Expand Up @@ -1680,7 +1671,7 @@ void ClientSideEncryption::handlePublicKeyDeleted(const QKeychain::Job * const i

bool ClientSideEncryption::sensitiveDataRemaining() const
{
return !_privateKey.isEmpty() || !_certificate.isNull() || !_mnemonic.isEmpty() || !_usbTokenInformation.serialNumber().isEmpty() || !_usbTokenInformation.issuer().isEmpty() || _tokenPublicKey || _tokenPrivateKey;
return !_privateKey.isEmpty() || !_certificate.isNull() || !_mnemonic.isEmpty() || !_usbTokenInformation.sha256Fingerprint().isEmpty() || _tokenPublicKey || _tokenPrivateKey;
}

void ClientSideEncryption::failedToInitialize(const AccountPtr &account)
Expand All @@ -1691,8 +1682,7 @@ void ClientSideEncryption::failedToInitialize(const AccountPtr &account)

void ClientSideEncryption::saveCertificateIdentification(const AccountPtr &account) const
{
account->setEncryptionCertificateIssuer(_usbTokenInformation.issuer());
account->setEncryptionCertificateSerialNumber(_usbTokenInformation.serialNumber());
account->setEncryptionCertificateFingerprint(_usbTokenInformation.sha256Fingerprint());
}

void ClientSideEncryption::cacheTokenPin(const QString pin)
Expand Down Expand Up @@ -2235,17 +2225,15 @@ void FolderMetadata::setupExistingMetadata(const QByteArray& metadata)
const auto files = metaDataDoc.object()["files"].toObject();
const auto metadataKey = metaDataDoc.object()["metadata"].toObject()["metadataKey"].toString().toUtf8();
const auto metadataKeyChecksum = metaDataDoc.object()["metadata"].toObject()["checksum"].toString().toUtf8();
_metadataCertificateSerialNumber = metadataObj[certificateSerialNumberKey].toString();
_metadataCertificateIssuer = metadataObj[certificateIssuerKey].toString();
_metadataCertificateSha256Fingerprint = metadataObj[certificateSha256FingerprintKey].toString().toLatin1();

if (!_metadataCertificateSerialNumber.isEmpty() && !_metadataCertificateIssuer.isEmpty()) {
if (!_metadataCertificateSha256Fingerprint.isEmpty()) {
if (!_account->e2e()->useTokenBasedEncryption()) {
qCWarning(lcCseMetadata()) << "e2ee metadata are missing proper information about the certificate used to encrypt them";
return;
}

if (_metadataCertificateSerialNumber != _account->e2e()->usbTokenInformation()->serialNumber() ||
_metadataCertificateIssuer != _account->e2e()->usbTokenInformation()->issuer()) {
if (_metadataCertificateSha256Fingerprint != _account->e2e()->usbTokenInformation()->sha256Fingerprint()) {
qCInfo(lcCseMetadata()) << "migration of the certificate used to encrypt metadata is needed";
return;
}
Expand Down Expand Up @@ -2442,8 +2430,7 @@ QByteArray FolderMetadata::encryptedMetadata() const {
QJsonObject metadata{
{"version", version},
{metadataKeyJsonKey, QJsonValue::fromVariant(*encryptedMetadataKey)},
{certificateSerialNumberKey, _account->e2e()->usbTokenInformation()->serialNumber()},
{certificateIssuerKey, _account->e2e()->usbTokenInformation()->issuer()},
{certificateSha256FingerprintKey, QJsonValue::fromVariant(_account->e2e()->usbTokenInformation()->sha256Fingerprint())},
{"checksum", QJsonValue::fromVariant(computeMetadataKeyChecksum(*encryptedMetadataKey))},
};

Expand Down
3 changes: 1 addition & 2 deletions src/libsync/clientsideencryption.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,7 @@ class OWNCLOUDSYNC_EXPORT FolderMetadata {
QJsonObject _fileDrop;
// used by unit tests, must get assigned simultaneously with _fileDrop and not erased
QJsonObject _fileDropFromServer;
QString _metadataCertificateSerialNumber;
QString _metadataCertificateIssuer;
QByteArray _metadataCertificateSha256Fingerprint;
bool _isMetadataSetup = false;
bool _encryptedMetadataNeedUpdate = false;
};
Expand Down
38 changes: 12 additions & 26 deletions src/libsync/clientsideencryptiontokenselector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,22 +109,17 @@ ClientSideEncryptionTokenSelector::ClientSideEncryptionTokenSelector(QObject *pa

bool ClientSideEncryptionTokenSelector::isSetup() const
{
return !_issuer.isEmpty() && !_serialNumber.isEmpty();
return !_sha256Fingerprint.isEmpty();
}

QVariantList ClientSideEncryptionTokenSelector::discoveredCertificates() const
{
return _discoveredCertificates;
}

QString ClientSideEncryptionTokenSelector::serialNumber() const
QByteArray ClientSideEncryptionTokenSelector::sha256Fingerprint() const
{
return _serialNumber;
}

QString ClientSideEncryptionTokenSelector::issuer() const
{
return _issuer;
return _sha256Fingerprint;
}

QFuture<void> ClientSideEncryptionTokenSelector::searchForCertificates(const AccountPtr &account)
Expand All @@ -134,24 +129,14 @@ QFuture<void> ClientSideEncryptionTokenSelector::searchForCertificates(const Acc
});
}

void ClientSideEncryptionTokenSelector::setSerialNumber(const QString &serialNumber)
{
if (_serialNumber == serialNumber) {
return;
}

_serialNumber = serialNumber;
Q_EMIT serialNumberChanged();
}

void ClientSideEncryptionTokenSelector::setIssuer(const QString &issuer)
void ClientSideEncryptionTokenSelector::setSha256Fingerprint(const QByteArray &sha256Fingerprint)
{
if (_issuer == issuer) {
if (_sha256Fingerprint == sha256Fingerprint) {
return;
}

_issuer = issuer;
Q_EMIT issuerChanged();
_sha256Fingerprint = sha256Fingerprint;
Q_EMIT sha256FingerprintChanged();
}

void ClientSideEncryptionTokenSelector::discoverCertificates(const AccountPtr &account)
Expand Down Expand Up @@ -233,7 +218,8 @@ void ClientSideEncryptionTokenSelector::discoverCertificates(const AccountPtr &a
<< "issuer:" << sslCertificate.issuerDisplayName()
<< "valid since:" << sslCertificate.effectiveDate()
<< "valid until:" << sslCertificate.expiryDate()
<< "serial number:" << sslCertificate.serialNumber();
<< "serial number:" << sslCertificate.serialNumber()
<< "SHA256 fingerprint:" << sslCertificate.digest(QCryptographicHash::Sha256).toBase64();

if (sslCertificate.isSelfSigned()) {
qCDebug(lcCseSelector()) << "newly found certificate is self signed: goint to ignore it";
Expand All @@ -247,6 +233,7 @@ void ClientSideEncryptionTokenSelector::discoverCertificates(const AccountPtr &a
{QStringLiteral("serialNumber"), sslCertificate.serialNumber()},
{QStringLiteral("validSince"), sslCertificate.effectiveDate()},
{QStringLiteral("validUntil"), sslCertificate.expiryDate()},
{QStringLiteral("sha256Fingerprint"), sslCertificate.digest(QCryptographicHash::Sha256).toBase64()},
{QStringLiteral("certificate"), QVariant::fromValue(sslCertificate)},
});
}
Expand All @@ -269,10 +256,9 @@ void ClientSideEncryptionTokenSelector::processDiscoveredCertificates()
for (const auto &oneError : sslErrors) {
qCInfo(lcCseSelector()) << oneError;
}
qCInfo(lcCseSelector()) << "certificate is valid" << certificateData[QStringLiteral("serialNumber")] << certificateData[QStringLiteral("issuer")];
qCInfo(lcCseSelector()) << "certificate is valid" << certificateData[QStringLiteral("subject")] << "from" << certificateData[QStringLiteral("issuer")] << "fingerprint" << sslCertificate.digest(QCryptographicHash::Sha256).toBase64();

setIssuer(certificateData[QStringLiteral("issuer")].toString());
setSerialNumber(certificateData[QStringLiteral("serialNumber")].toString());
setSha256Fingerprint(sslCertificate.digest(QCryptographicHash::Sha256));
Q_EMIT isSetupChanged();
return;
}
Expand Down
20 changes: 5 additions & 15 deletions src/libsync/clientsideencryptiontokenselector.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ class OWNCLOUDSYNC_EXPORT ClientSideEncryptionTokenSelector : public QObject

Q_PROPERTY(QVariantList discoveredCertificates READ discoveredCertificates NOTIFY discoveredCertificatesChanged)

Q_PROPERTY(QString serialNumber READ serialNumber WRITE setSerialNumber NOTIFY serialNumberChanged)

Q_PROPERTY(QString issuer READ issuer WRITE setIssuer NOTIFY issuerChanged)
Q_PROPERTY(QByteArray sha256Fingerprint READ sha256Fingerprint WRITE setSha256Fingerprint NOTIFY sha256FingerprintChanged)

public:
explicit ClientSideEncryptionTokenSelector(QObject *parent = nullptr);
Expand All @@ -43,16 +41,12 @@ class OWNCLOUDSYNC_EXPORT ClientSideEncryptionTokenSelector : public QObject

[[nodiscard]] QVariantList discoveredCertificates() const;

[[nodiscard]] QString serialNumber() const;

[[nodiscard]] QString issuer() const;
[[nodiscard]] QByteArray sha256Fingerprint() const;

public slots:
QFuture<void> searchForCertificates(const OCC::AccountPtr &account);

void setSerialNumber(const QString &serialNumber);

void setIssuer(const QString &issuer);
void setSha256Fingerprint(const QByteArray &sha256Fingerprint);

signals:

Expand All @@ -62,9 +56,7 @@ public slots:

void certificateIndexChanged();

void serialNumberChanged();

void issuerChanged();
void sha256FingerprintChanged();

void failedToInitialize(const OCC::AccountPtr &account);

Expand All @@ -75,9 +67,7 @@ public slots:

QVariantList _discoveredCertificates;

QString _serialNumber;

QString _issuer;
QByteArray _sha256Fingerprint;
};

}
Expand Down

0 comments on commit e187be5

Please sign in to comment.