Skip to content

Commit 2e41d68

Browse files
authored
Keyshare encryption (#47)
Signed-off-by: Lauris Kaplinski <lauris@raulwalter.com>
1 parent 7ae6046 commit 2e41d68

29 files changed

Lines changed: 7793 additions & 24693 deletions

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ if(POLICY CMP0167)
44
cmake_policy(SET CMP0167 NEW)
55
endif()
66

7-
project(libcdoc VERSION 0.1.5)
7+
project(libcdoc VERSION 0.1.6)
88

99
macro(SET_ENV NAME DEF)
1010
if(DEFINED ENV{${NAME}})

cdoc/CDoc.cpp

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -71,32 +71,6 @@ getVersion()
7171
return VERSION_STR;
7272
}
7373

74-
bool
75-
libcdoc::Configuration::getBoolean(std::string_view param, bool def_val) const
76-
{
77-
std::string val = getValue(param);
78-
if (val.empty()) return def_val;
79-
return val == "true";
80-
}
81-
82-
int
83-
libcdoc::Configuration::getInt(std::string_view param, int def_val) const
84-
{
85-
std::string val = getValue(param);
86-
if (val.empty()) return def_val;
87-
return std::stoi(val);
88-
}
89-
90-
#if LIBCDOC_TESTING
91-
int64_t
92-
libcdoc::Configuration::test(std::vector<uint8_t>& dst)
93-
{
94-
LOG_TRACE("Configuration::test::Native superclass");
95-
return OK;
96-
}
97-
#endif
98-
99-
10074
int
10175
libcdoc::CDocReader::getCDocFileVersion(DataSource *src)
10276
{
@@ -179,7 +153,6 @@ libcdoc::CDocReader::testConfig(std::vector<uint8_t>& dst)
179153
LOG_TRACE("CDocReader::testConfig::Native superclass");
180154
if (conf) {
181155
LOG_DBG("CDocReader::testConfig this={} conf={}", reinterpret_cast<void*>(this), reinterpret_cast<void*>(conf));
182-
return conf->test(dst);
183156
}
184157
LOG_ERROR("CDocReader::testConfig::conf is null");
185158
return WORKFLOW_ERROR;

cdoc/CDoc2Reader.cpp

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "CryptoBackend.h"
2424
#include "CDoc2.h"
2525
#include "ILogger.h"
26+
#include "KeyShares.h"
2627
#include "Lock.h"
2728
#include "NetworkBackend.h"
2829
#include "Tar.h"
@@ -111,8 +112,10 @@ libcdoc::result_t
111112
CDoc2Reader::getLockForCert(const std::vector<uint8_t>& cert){
112113
libcdoc::Certificate cc(cert);
113114
std::vector<uint8_t> other_key = cc.getPublicKey();
115+
LOG_DBG("Cert public key: {}", toHex(other_key));
114116
for (int lock_idx = 0; lock_idx < priv->locks.size(); lock_idx++) {
115117
const libcdoc::Lock *ll = priv->locks.at(lock_idx);
118+
LOG_DBG("Lock {} type {}", lock_idx, (int) ll->type);
116119
if (ll->hasTheSameKey(other_key)) {
117120
return lock_idx;
118121
}
@@ -152,7 +155,7 @@ CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)
152155
LOG_TRACE_KEY("kek: {}", kek);
153156

154157
if (kek.empty()) return libcdoc::CRYPTO_ERROR;
155-
} else {
158+
} else if ((lock.type == libcdoc::Lock::Type::PUBLIC_KEY) || (lock.type == libcdoc::Lock::Type::SERVER)) {
156159
// Public/private key
157160
std::vector<uint8_t> key_material;
158161
if(lock.type == libcdoc::Lock::Type::SERVER) {
@@ -210,6 +213,88 @@ CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)
210213

211214
kek = libcdoc::Crypto::expand(kek_pm, std::vector<uint8_t>(info_str.cbegin(), info_str.cend()), libcdoc::CDoc2::KEY_LEN);
212215
}
216+
} else if (lock.type == libcdoc::Lock::Type::SHARE_SERVER) {
217+
/* SALT */
218+
std::vector<uint8_t> salt = lock.getBytes(Lock::SALT);
219+
/* RECIPIENT_ID */
220+
std::string rcpt_id = lock.getString(Lock::RECIPIENT_ID);
221+
/* SHARE_URLS */
222+
/* url,share_id;url,share_id... */
223+
std::string all = lock.getString(Lock::SHARE_URLS);
224+
std::vector<std::string> strs = split(all, ';');
225+
if (strs.empty()) return libcdoc::DATA_FORMAT_ERROR;
226+
std::vector<ShareData> shares;
227+
for (auto& str : strs) {
228+
std::vector<std::string> parts = split(str, ',');
229+
if (parts.size() != 2) return libcdoc::DATA_FORMAT_ERROR;
230+
std::string url = parts[0];
231+
std::string id = parts[1];
232+
LOG_DBG("Share {} url {}", id, url);
233+
234+
std::vector<uint8_t> nonce;
235+
int64_t result = network->fetchNonce(nonce, url, id);
236+
if (result != libcdoc::OK) {
237+
setLastError(t_("Cannot fetch nonce from server"));
238+
LOG_ERROR("Cannot fetch nonce from server {}", url);
239+
return result;
240+
}
241+
LOG_DBG("Nonce: {}", std::string(nonce.cbegin(), nonce.cend()));
242+
ShareData acc(url, id, std::string(nonce.cbegin(), nonce.cend()));
243+
shares.push_back(std::move(acc));
244+
}
245+
/* Create tickets from shares */
246+
std::vector<std::string> tickets;
247+
std::vector<uint8_t> cert;
248+
result_t result = NOT_IMPLEMENTED;
249+
if (conf->getValue(Configuration::SHARE_SIGNER) == "SMART_ID") {
250+
// "https://sid.demo.sk.ee/smart-id-rp/v2"
251+
std::string url = conf->getValue(Configuration::SID_DOMAIN, Configuration::BASE_URL);
252+
// "00000000-0000-0000-0000-000000000000"
253+
std::string relyingPartyUUID = conf->getValue(Configuration::SID_DOMAIN, Configuration::RP_UUID);
254+
// "DEMO"
255+
std::string relyingPartyName = conf->getValue(Configuration::SID_DOMAIN, Configuration::RP_NAME);
256+
SIDSigner signer(url, relyingPartyUUID, relyingPartyName, rcpt_id, network);
257+
result = signer.generateTickets(tickets, shares);
258+
if (result == OK) cert = std::move(signer.cert);
259+
} else if (conf->getValue(Configuration::SHARE_SIGNER) == "MOBILE_ID") {
260+
// "https://sid.demo.sk.ee/smart-id-rp/v2"
261+
std::string url = conf->getValue(Configuration::MID_DOMAIN, Configuration::BASE_URL);
262+
// "00000000-0000-0000-0000-000000000000"
263+
std::string relyingPartyUUID = conf->getValue(Configuration::MID_DOMAIN, Configuration::RP_UUID);
264+
// "DEMO"
265+
std::string relyingPartyName = conf->getValue(Configuration::MID_DOMAIN, Configuration::RP_NAME);
266+
// "37200000566"
267+
std::string phone = conf->getValue(Configuration::MID_DOMAIN, Configuration::PHONE_NUMBER);
268+
MIDSigner signer(url, relyingPartyUUID, relyingPartyName, phone, rcpt_id, network);
269+
result = signer.generateTickets(tickets, shares);
270+
if (result == OK) cert = std::move(signer.cert);
271+
} else {
272+
setLastError(t_("Unknown or missing signer type"));
273+
LOG_ERROR("Unknown or missing signer type");
274+
return result;
275+
}
276+
if (result != libcdoc::OK) {
277+
setLastError(t_("Cannot generate share tickets"));
278+
LOG_ERROR("Cannot generate share tickets");
279+
return result;
280+
}
281+
kek.resize(32);
282+
std::fill(kek.begin(), kek.end(), 0);
283+
for (unsigned int i = 0; i < tickets.size(); i++) {
284+
NetworkBackend::ShareInfo share;
285+
result = network->fetchShare(share, shares[i].base_url, shares[i].share_id, tickets[i], cert);
286+
if (result != libcdoc::OK) {
287+
setLastError(t_("Cannot fetch share"));
288+
LOG_ERROR("Cannot fetch share {}", i);
289+
return result;
290+
}
291+
Crypto::xor_data(kek, kek, share.share);
292+
}
293+
LOG_INFO("Fetched all shares");
294+
} else {
295+
setLastError(t_("Unknown lock type"));
296+
LOG_ERROR("Unknown lock type: %d", (int) lock.type);
297+
return libcdoc::UNSPECIFIED_ERROR;
213298
}
214299

215300
LOG_TRACE_KEY("KEK: {}", kek);
@@ -524,6 +609,40 @@ CDoc2Reader::CDoc2Reader(libcdoc::DataSource *src, bool take_ownership)
524609
priv->locks.push_back(key);
525610
}
526611
break;
612+
case Capsule::recipients_KeySharesCapsule:
613+
if (const auto *capsule = recipient->capsule_as_recipients_KeySharesCapsule()) {
614+
if (capsule->recipient_type() != cdoc20::recipients::KeyShareRecipientType::SID_MID) {
615+
LOG_ERROR("Invalid keyshare recipient type: {}", (int) capsule->recipient_type());
616+
continue;
617+
}
618+
if (capsule->shares_scheme() != cdoc20::recipients::SharesScheme::N_OF_N) {
619+
LOG_ERROR("Invalid keyshare scheme type: {}", (int) capsule->shares_scheme());
620+
continue;
621+
}
622+
/* url,share_id;url,share_id... */
623+
std::vector<std::string> strs;
624+
for (auto cshare = capsule->shares()->cbegin(); cshare != capsule->shares()->cend(); ++cshare) {
625+
std::string id = cshare->share_id()->str();
626+
std::string url = cshare->server_base_url()->str();
627+
std::string str = url + "," + id;
628+
LOG_DBG("Keyshare: {}", str);
629+
strs.push_back(str);
630+
}
631+
std::string urls = join(strs, ";");
632+
LOG_DBG("Keyshare urls: {}", urls);
633+
std::vector<uint8_t> salt(capsule->salt()->cbegin(), capsule->salt()->cend());
634+
LOG_DBG("Keyshare salt: {}", toHex(salt));
635+
std::string recipient_id = capsule->recipient_id()->str();
636+
LOG_DBG("Keyshare recipient id: {}", recipient_id);
637+
libcdoc::Lock *lock = new libcdoc::Lock(libcdoc::Lock::SHARE_SERVER);
638+
lock->label = recipient->key_label()->str();
639+
lock->encrypted_fmk.assign(recipient->encrypted_fmk()->cbegin(), recipient->encrypted_fmk()->cend());
640+
lock->setString(libcdoc::Lock::SHARE_URLS, urls);
641+
lock->setBytes(libcdoc::Lock::SALT, salt);
642+
lock->setString(libcdoc::Lock::RECIPIENT_ID, recipient_id);
643+
priv->locks.push_back(std::move(lock));
644+
}
645+
break;
527646
default:
528647
LOG_ERROR("Unsupported Key Details: skipping");
529648
}

cdoc/CDoc2Writer.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
429429
return libcdoc::CONFIGURATION_ERROR;
430430
}
431431
LOG_DBG("Share servers: {}", url_list);
432-
std::vector<std::string> urls = split(url_list, ',');
432+
std::vector<std::string> urls = libcdoc::JsonToStringArray(url_list);
433433
if (urls.size() < 1) {
434434
setLastError("No server URLs in " + rcpt.server_id);
435435
LOG_ERROR("{}", last_error);
@@ -462,6 +462,13 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
462462
std::string info_str = std::string("CDOC2kek") + cdoc20::header::EnumNameFMKEncryptionMethod(cdoc20::header::FMKEncryptionMethod::XOR) + RecipientInfo_i;
463463
LOG_DBG("Info: {}", info_str);
464464
std::vector<uint8_t> kek = libcdoc::Crypto::expand(kek_pm, std::vector<uint8_t>(info_str.cbegin(), info_str.cend()));
465+
LOG_TRACE_KEY("kek: {}", kek);
466+
if (kek.empty()) return libcdoc::CRYPTO_ERROR;
467+
if (libcdoc::Crypto::xor_data(xor_key, fmk, kek) != libcdoc::OK) {
468+
setLastError("Internal error");
469+
LOG_ERROR("{}", last_error);
470+
return libcdoc::CRYPTO_ERROR;
471+
}
465472

466473
// # Splitting KEK_i into shares
467474
// for j in (2, 3, ..., n):
@@ -483,7 +490,7 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
483490
// # gets corresponding Capsule_i_Share_j_ID for each KEK_i_share_j
484491
// RecipientInfo_i = "etsi/PNOEE-48010010101"
485492
// DistributedKEKInfo_i = {CSS_ID, Capsule_i_Share_j_ID}
486-
std::vector<std::string> transaction_ids(N_SHARES);
493+
std::vector<std::vector<uint8_t>> transaction_ids(N_SHARES);
487494
for (int i = 0; i < N_SHARES; i++) {
488495
std::string send_url = urls[i];// + "key-shares";
489496
LOG_DBG("Sending share: {} {} {}", i, send_url, libcdoc::toHex(kek_shares[i]));
@@ -495,11 +502,11 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
495502
return libcdoc::IO_ERROR;
496503
}
497504
#endif
498-
LOG_DBG("Share {} Transaction Id: {}", i, transaction_ids[i]);
505+
LOG_DBG("Share {} Transaction Id: {}", i, std::string((const char *) transaction_ids[i].data(), transaction_ids[i].size()));
499506
}
500507
std::vector<flatbuffers::Offset<cdoc20::recipients::KeyShare>> shares;
501508
for (int i = 0; i < N_SHARES; i++) {
502-
auto share = cdoc20::recipients::CreateKeyShare(builder, builder.CreateString(urls[i]), builder.CreateString(transaction_ids[i]));
509+
auto share = cdoc20::recipients::CreateKeyShare(builder, builder.CreateString(urls[i]), builder.CreateString(std::string((const char *)transaction_ids[i].data(), transaction_ids[i].size())));
503510
shares.push_back(share);
504511
}
505512
auto fb_shares = builder.CreateVector(shares);

cdoc/CDocCipher.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector<l
219219
LOG_ERROR("Certificate reading from SC card failed. Key label: {}", rcpt.key_label);
220220
return 1;
221221
}
222+
LOG_DBG("Got certificate from P11 module");
222223
label = Recipient::BuildLabelEID(cert_bytes);
223224
break;
224225
}
@@ -394,11 +395,30 @@ int CDocCipher::Decrypt(ToolConf& conf, const std::string& label, const RcptInfo
394395
// Acquire the locks and get the labels according to the index
395396
int lock_idx = -1;
396397
const vector<Lock> locks(rdr->getLocks());
397-
for (unsigned int i = 0; i < locks.size(); i++) {
398-
if (locks[i].label == label) {
399-
lock_idx = i;
400-
break;
398+
if (!label.empty()) {
399+
LOG_DBG("Looking for lock by label");
400+
for (unsigned int i = 0; i < locks.size(); i++) {
401+
if (locks[i].label == label) {
402+
lock_idx = i;
403+
break;
404+
}
405+
}
406+
} else if (crypto.p11) {
407+
bool isRsa;
408+
vector<uint8_t> cert_bytes;
409+
ToolPKCS11* p11 = dynamic_cast<ToolPKCS11*>(crypto.p11.get());
410+
int64_t result = p11->getCertificate(cert_bytes, isRsa, (int) recipient.slot, recipient.secret, recipient.key_id, recipient.key_label);
411+
if (result != libcdoc::OK) {
412+
LOG_ERROR("Certificate reading from SC card failed. Key label: {}", recipient.key_label);
413+
return 1;
414+
}
415+
LOG_DBG("Got certificate from P11 module");
416+
result = rdr->getLockForCert(cert_bytes);
417+
if (result < 0) {
418+
LOG_ERROR("No lock for certificate {}", recipient.key_label);
419+
return 1;
401420
}
421+
lock_idx = (int) result;
402422
}
403423
if (lock_idx < 0) {
404424
LOG_ERROR("Lock not found: {}", label);

cdoc/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ add_library(cdoc
3434
Io.cpp
3535
Recipient.cpp
3636
Lock.cpp
37+
Configuration.cpp
3738
CryptoBackend.cpp
3839
NetworkBackend.cpp
3940
PKCS11Backend.cpp
@@ -51,6 +52,7 @@ add_library(cdoc
5152
CDoc2Writer.cpp CDoc2Writer.h
5253
DDocReader.cpp DDocReader.h
5354
DDocWriter.cpp DDocWriter.h
55+
KeyShares.cpp KeyShares.h
5456
XmlReader.cpp XmlReader.h
5557
XmlWriter.cpp XmlWriter.h
5658
RcptInfo.h

0 commit comments

Comments
 (0)