Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
25ab007
Tar and workflow fixes and tests
Jan 23, 2026
98224e6
Merge branch 'open-eid:master' into master
lauris71 Jan 26, 2026
b4a1736
Create locks even if capsule is not supported
Jan 30, 2026
414452e
Update cdoc/CDoc2Reader.cpp
lauris71 Feb 2, 2026
0854344
Use toUint8Vector helper
Feb 2, 2026
777700c
Removed some extra check from parsing
Feb 2, 2026
8cdc652
Remove INVALID lock type and rename UNSUPPORTED to UNKNOWN
Feb 3, 2026
5ef36d7
Return NULL from frontend if CDoc constructor fails
Feb 4, 2026
f2c9091
Merge branch 'open-eid:master' into master
lauris71 Feb 4, 2026
b76e104
Merge branch 'open-eid:master' into master
lauris71 Feb 11, 2026
625c768
Remove label creation from Java test
Feb 11, 2026
678a318
Merge branch 'open-eid:master' into master
lauris71 Feb 12, 2026
372f7f7
Keep Java references in CDocReader and CDocWriter to prevent prematur…
Feb 12, 2026
e9155eb
Merge branch 'open-eid:master' into master
lauris71 Feb 12, 2026
4dc229f
Cleaned up logging
Feb 13, 2026
209042f
Renamed ILogger -> Logger
Feb 13, 2026
ee33b97
Added Logger.h
Feb 13, 2026
9930c35
Removed ConsoleLogger from public interface
Feb 13, 2026
ce13f36
Fixed WinBackend.cpp
Feb 13, 2026
4453784
Fixed WinBackend.cpp more
Feb 13, 2026
cb10179
One more Winbackend fix
Feb 13, 2026
1db00de
Merge branch 'open-eid:master' into master
lauris71 Feb 13, 2026
252333f
Merge branch 'logging'
Feb 13, 2026
985e226
Merge branch 'open-eid:master' into master
lauris71 Feb 17, 2026
d939504
Implement secp256r1 curve support
Feb 17, 2026
db3a58b
Added CDoc.h
Feb 17, 2026
44669de
Merge branch 'master' into multi_curve
Feb 17, 2026
df088d7
Added cdoc-tool support and testing for secp256 curve
Feb 18, 2026
4a7a230
Allow unknown curve type while decrypting
Feb 18, 2026
4f41425
Minor cleanups
Feb 18, 2026
7f4aa1c
Removed Algorithm enum from Certificate and PKCS11 cleanup
Feb 19, 2026
7d5f35d
Export CDocCipher internally for cdoc-tool
Mar 3, 2026
40c6fe0
Merge branch 'open-eid:master' into master
lauris71 Mar 9, 2026
8229269
Merge commit '40c6fe0d026ca10fc83bd8bf6691f38c6618cdf2' into multi_curve
Mar 9, 2026
1022623
Fix label parsing
Mar 11, 2026
fe80e76
Handle "PaxHeaders" paths correctly
Mar 13, 2026
04fd236
Merge branch 'open-eid:master' into master
lauris71 Mar 13, 2026
1be01a7
Apply suggestions from code review
lauris71 Mar 16, 2026
c4ed519
Merge branch 'open-eid:master' into master
lauris71 Mar 25, 2026
7d533a0
Fix tar filenames if only PAX size is used
Mar 25, 2026
8bb1c86
Moved parseLabel to Lock, take minimum of expiry time
Mar 26, 2026
a9bb137
Fixed CDocTool.java
Mar 26, 2026
2af5e5a
Merge branch 'open-eid:master' into master
lauris71 Mar 26, 2026
af001aa
Merge commit '2af5e5a73ee3cfdc923ef3995c696e509c8cbee6' into rel1_7
Mar 27, 2026
84a4a92
Use property system for automatic label generation
Mar 27, 2026
129976b
Merge commit '7aa1eac3d147f40374be18cc1cdb189f5268a080'
Mar 27, 2026
e2d5b44
Merge branch 'master' into rel1_7
Mar 27, 2026
4fb60a3
remove final from CDoc2
Mar 27, 2026
7f94de4
Exclude CDoc2 from swig for the time being
Mar 27, 2026
3493f79
Remove commented-out code
Mar 27, 2026
cb79943
Remove 'final' once more
Mar 27, 2026
90fd645
Made CDoc2 back to namespace
Mar 27, 2026
5429a11
Moved label strings to Label namespace
Mar 27, 2026
992aa6d
#undef VERSION
Mar 27, 2026
f70afa7
Merge branch 'open-eid:master' into master
lauris71 Mar 30, 2026
917fef8
Merge branch 'open-eid:master' into master
lauris71 Mar 31, 2026
db96491
Merge branch 'open-eid:master' into master
lauris71 Mar 31, 2026
ad7a18e
Check recipient validity in addRecipient
Mar 31, 2026
afaaa7a
Apply suggestions from code review
lauris71 Apr 1, 2026
e4aa39c
Fix CDoc2 label parsing
Apr 8, 2026
c541dae
Merge branch 'open-eid:master' into master
lauris71 Apr 8, 2026
8405adf
Do not truncate user-specified expiry to 6 months, force cdoc-tool to…
Apr 8, 2026
68cc8d0
Comment out keyshares support
Apr 8, 2026
f1e070c
Merged master
Apr 8, 2026
4f61b5b
Set version to 0.5.0
Apr 8, 2026
a9a67a5
Remove forced Debug build
Apr 8, 2026
11c519d
Merge branch 'open-eid:master' into master
lauris71 Apr 9, 2026
031981f
Merge branch 'master' into multi_curve
Apr 9, 2026
d25ad52
Fixed Recipient
Apr 9, 2026
475041c
Merge branch 'master' into rel1_7
Apr 9, 2026
1031bbf
Added secp521r1 curve support
Apr 9, 2026
3f6ab5f
Merge branch 'rel1_7' of github.com:lauris71/libcdoc into rel1_7
Apr 10, 2026
7931b7d
Merge branch 'open-eid:master' into master
lauris71 Apr 15, 2026
eba8bd2
Merge branch 'open-eid:master' into master
lauris71 Apr 17, 2026
b7c1f73
Merge branch 'open-eid:master' into master
lauris71 Apr 28, 2026
c9234a7
Merge branch 'master' into multi_curve
Apr 28, 2026
0deebb2
Remove unused variable
Apr 28, 2026
2c01fb5
Added secp521r1 test keys/certificates
Apr 28, 2026
043d31a
Fix recipient
Apr 29, 2026
759e2af
Merge branch 'rel1_7'
Apr 29, 2026
3c8b1e3
Merge branch 'master' of github.com:lauris71/libcdoc
Apr 29, 2026
7aca4fe
Merge branch 'master' into multi_curve
Apr 29, 2026
6c80629
Cleaned Recipient building
May 6, 2026
43a1c95
Merge branch 'open-eid:master' into master
lauris71 May 6, 2026
62da531
Merge commit '43a1c95572873609ba2f1fcb2f2a7a28333317c8' into multi_curve
May 6, 2026
098ebe8
Unify server and public key recipient constructors
May 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ obj-x86_64-linux-gnu/
test/data/tmp/
vcpkg/
vcpkg_installed/
examples/java/.gradle
examples/java/bin
42 changes: 27 additions & 15 deletions cdoc/CDoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#ifndef __CDOC_H__
#define __CDOC_H__

#include "Exports.h"
#include <cdoc/Exports.h>

#include <cstdint>
#include <string>
Expand All @@ -31,20 +31,6 @@ namespace libcdoc {
*/
using result_t = int64_t;

/**
* @brief The public key type
*/
enum class PKType : uint8_t {
/**
* Elliptic curve
*/
ECC,
/**
* RSA
*/
RSA
};

enum {
/**
* @brief Operation completed successfully
Expand Down Expand Up @@ -154,6 +140,32 @@ CDOC_EXPORT std::string getErrorStr(int64_t code);
*/
CDOC_EXPORT std::string getVersion();

/**
* @brief The public key algorithm
*/
enum Algorithm : uint8_t {
UNKNOWN_ALGORITHM,
/**
* Elliptic curve
*/
ECC,
/**
* RSA
*/
RSA
};

/**
* @brief The EC curve used
*/
enum Curve : uint8_t {
UNKNOWN_CURVE,
SECP_384_R1,
SECP_256_R1,
SECP_521_R1
};


// Logging interface

/**
Expand Down
4 changes: 2 additions & 2 deletions cdoc/CDoc1Reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ CDoc1Reader::getLockForCert(const std::vector<uint8_t>& cert)
ll.encrypted_fmk.empty())
continue;
switch(cc.getAlgorithm()) {
case libcdoc::PKType::RSA:
case libcdoc::Algorithm::RSA:
if (ll.getString(Lock::Params::METHOD) == libcdoc::Crypto::RSA_MTH) {
return i;
}
break;
case libcdoc::PKType::ECC:
case libcdoc::Algorithm::ECC:
if(!ll.getBytes(Lock::Params::KEY_MATERIAL).empty() &&
std::find(SUPPORTED_KWAES.cbegin(), SUPPORTED_KWAES.cend(), ll.getString(Lock::Params::METHOD)) != SUPPORTED_KWAES.cend()) {
return i;
Expand Down
54 changes: 33 additions & 21 deletions cdoc/CDoc2Reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,44 +504,56 @@ CDoc2Reader::Private::buildLock(Lock& lock, const cdoc20::header::RecipientRecor
switch(recipient.capsule_type())
{
case Capsule::recipients_ECCPublicKeyCapsule:
if(const auto *key = recipient.capsule_as_recipients_ECCPublicKeyCapsule()) {
if(key->curve() == EllipticCurve::secp384r1) {
lock.type = Lock::Type::PUBLIC_KEY;
lock.pk_type = PKType::ECC;
lock.setBytes(Lock::Params::RCPT_KEY, toUint8Vector(key->recipient_public_key()));
lock.setBytes(Lock::Params::KEY_MATERIAL, toUint8Vector(key->sender_public_key()));
LOG_DBG("Load PK: {}", toHex(lock.getBytes(Lock::Params::RCPT_KEY)));
if(const auto *capsule = recipient.capsule_as_recipients_ECCPublicKeyCapsule()) {
lock.type = Lock::Type::PUBLIC_KEY;
lock.pk_type = Algorithm::ECC;
if(capsule->curve() == EllipticCurve::secp384r1) {
lock.ec_type = Curve::SECP_384_R1;
} else if (capsule->curve() == EllipticCurve::secp256r1) {
lock.ec_type = Curve::SECP_256_R1;
} else if (capsule->curve() == EllipticCurve::secp521r1) {
lock.ec_type = Curve::SECP_521_R1;
} else {
LOG_ERROR("Unsupported ECC curve: skipping");
LOG_WARN("Unknown ECC curve: {}", (int) capsule->curve());
lock.ec_type = Curve::UNKNOWN_CURVE;
}
lock.setBytes(Lock::Params::RCPT_KEY, toUint8Vector(capsule->recipient_public_key()));
lock.setBytes(Lock::Params::KEY_MATERIAL, toUint8Vector(capsule->sender_public_key()));
LOG_DBG("Load PK: {}", toHex(lock.getBytes(Lock::Params::RCPT_KEY)));
}
return;
case Capsule::recipients_RSAPublicKeyCapsule:
if(const auto *key = recipient.capsule_as_recipients_RSAPublicKeyCapsule())
{
lock.type = Lock::Type::PUBLIC_KEY;
lock.pk_type = PKType::RSA;
lock.pk_type = Algorithm::RSA;
lock.setBytes(Lock::Params::RCPT_KEY, toUint8Vector(key->recipient_public_key()));
lock.setBytes(Lock::Params::KEY_MATERIAL, toUint8Vector(key->encrypted_kek()));
}
return;
case Capsule::recipients_KeyServerCapsule:
if (const KeyServerCapsule *server = recipient.capsule_as_recipients_KeyServerCapsule()) {
KeyDetailsUnion details = server->recipient_key_details_type();
if (const KeyServerCapsule *capsule = recipient.capsule_as_recipients_KeyServerCapsule()) {
KeyDetailsUnion details = capsule->recipient_key_details_type();
switch (details) {
case KeyDetailsUnion::EccKeyDetails:
if(const EccKeyDetails *eccDetails = server->recipient_key_details_as_EccKeyDetails()) {
if(eccDetails->curve() != EllipticCurve::secp384r1) {
LOG_ERROR("Unsupported elliptic curve key type");
return;
}
lock.pk_type = PKType::ECC;
if(const EccKeyDetails *eccDetails = capsule->recipient_key_details_as_EccKeyDetails()) {
lock.pk_type = Algorithm::ECC;
lock.setBytes(Lock::Params::RCPT_KEY, toUint8Vector(eccDetails->recipient_public_key()));
if(eccDetails->curve() == EllipticCurve::secp384r1) {
lock.ec_type = Curve::SECP_384_R1;
} else if (eccDetails->curve() == EllipticCurve::secp256r1) {
lock.ec_type = Curve::SECP_256_R1;
} else if (eccDetails->curve() == EllipticCurve::secp521r1) {
lock.ec_type = Curve::SECP_521_R1;
} else {
LOG_WARN("Unknown ECC curve: {}", (int) eccDetails->curve());
lock.ec_type = Curve::UNKNOWN_CURVE;
}
}
break;
case KeyDetailsUnion::RsaKeyDetails:
if(const RsaKeyDetails *rsaDetails = server->recipient_key_details_as_RsaKeyDetails()) {
lock.pk_type = PKType::RSA;
if(const RsaKeyDetails *rsaDetails = capsule->recipient_key_details_as_RsaKeyDetails()) {
lock.pk_type = Algorithm::RSA;
lock.setBytes(Lock::Params::RCPT_KEY, toUint8Vector(rsaDetails->recipient_public_key()));
}
break;
Expand All @@ -550,8 +562,8 @@ CDoc2Reader::Private::buildLock(Lock& lock, const cdoc20::header::RecipientRecor
return;
}
lock.type = Lock::Type::SERVER;
lock.setString(Lock::Params::KEYSERVER_ID, server->keyserver_id()->str());
lock.setString(Lock::Params::TRANSACTION_ID, server->transaction_id()->str());
lock.setString(Lock::Params::KEYSERVER_ID, capsule->keyserver_id()->str());
lock.setString(Lock::Params::TRANSACTION_ID, capsule->transaction_id()->str());
}
return;
case Capsule::recipients_SymmetricKeyCapsule:
Expand Down
29 changes: 22 additions & 7 deletions cdoc/CDoc2Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ CDoc2Writer::writeHeader(const std::vector<libcdoc::Recipient> &recipients)
return OK;
}

struct ECData {
int ossl_nid;
cdoc20::recipients::EllipticCurve fb_type;
const char *api_id;
};

static std::map<Curve,ECData> ecdata = {
{Curve::SECP_384_R1, {NID_secp384r1, cdoc20::recipients::EllipticCurve::secp384r1, "ecc_secp384r1"}},
{Curve::SECP_256_R1, {NID_X9_62_prime256v1, cdoc20::recipients::EllipticCurve::secp256r1, "ecc_secp256r1"}},
{Curve::SECP_521_R1, {NID_secp521r1, cdoc20::recipients::EllipticCurve::secp521r1, "ecc_secp521r1"}}
};

static flatbuffers::Offset<cdoc20::header::RecipientRecord>
createRSACapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::Recipient& rcpt, const std::vector<uint8_t>& encrypted_kek, const std::vector<uint8_t>& xor_key)
{
Expand Down Expand Up @@ -130,7 +142,7 @@ static flatbuffers::Offset<cdoc20::header::RecipientRecord>
createECCCapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::Recipient& rcpt, const std::vector<uint8_t>& eph_public_key, const std::vector<uint8_t>& xor_key)
{
auto capsule = cdoc20::recipients::CreateECCPublicKeyCapsule(builder,
cdoc20::recipients::EllipticCurve::secp384r1,
ecdata[rcpt.ec_type].fb_type,
builder.CreateVector(rcpt.rcpt_key),
builder.CreateVector(eph_public_key));
return cdoc20::header::CreateRecipientRecord(builder,
Expand All @@ -145,7 +157,7 @@ static flatbuffers::Offset<cdoc20::header::RecipientRecord>
createECCServerCapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::Recipient& rcpt, const std::string& transaction_id, uint64_t expiry_time, const std::vector<uint8_t>& xor_key)
{
auto eccKeyServer = cdoc20::recipients::CreateEccKeyDetails(builder,
cdoc20::recipients::EllipticCurve::secp384r1,
ecdata[rcpt.ec_type].fb_type,
builder.CreateVector(rcpt.rcpt_key));
auto capsule = cdoc20::recipients::CreateKeyServerCapsule(builder,
cdoc20::recipients::KeyDetailsUnion::EccKeyDetails,
Expand Down Expand Up @@ -211,7 +223,7 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
if (send_url.empty())
FAIL("Missing keyserver URL for ID " + rcpt.server_id, libcdoc::CONFIGURATION_ERROR);
}
if(rcpt.pk_type == libcdoc::PKType::RSA) {
if(rcpt.pk_type == libcdoc::Algorithm::RSA) {
crypto->random(kek, libcdoc::CDoc2::KEY_LEN);
if (auto err = libcdoc::Crypto::xor_data(xor_key, fmk, kek); err != libcdoc::OK)
FAIL("Internal error", err);
Expand All @@ -238,9 +250,13 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
fb_rcpts.push_back(createRSACapsule(builder, rcpt, key_material, xor_key));
}
} else {
auto publicKey = libcdoc::Crypto::fromECPublicKeyDer(rcpt.rcpt_key, NID_secp384r1);
if(!publicKey)
if (!ecdata.contains(rcpt.ec_type)) {
FAIL("Invalid EC Curve", libcdoc::CRYPTO_ERROR);
}
auto publicKey = libcdoc::Crypto::fromECPublicKeyDer(rcpt.rcpt_key, ecdata[rcpt.ec_type].ossl_nid);
if(!publicKey) {
FAIL("Invalid ECC key", libcdoc::CRYPTO_ERROR);
}
auto ephKey = libcdoc::Crypto::genECKey(publicKey.get());
std::vector<uint8_t> sharedSecret = libcdoc::Crypto::deriveSharedSecret(ephKey.get(), publicKey.get());
key_material = libcdoc::Crypto::toPublicKeyDer(ephKey.get());
Expand All @@ -260,10 +276,9 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
LOG_TRACE_KEY("xor: {}", xor_key);
if(rcpt.isKeyServer()) {
libcdoc::NetworkBackend::CapsuleInfo cinfo;
auto result = network->sendKey(cinfo, send_url, rcpt.rcpt_key, key_material, "ecc_secp384r1", rcpt.expiry_ts);
auto result = network->sendKey(cinfo, send_url, rcpt.rcpt_key, key_material, ecdata[rcpt.ec_type].api_id, rcpt.expiry_ts);
if (result < 0)
FAIL(network->getLastErrorStr(result), result);

LOG_DBG("Keyserver Id: {}", rcpt.server_id);
LOG_DBG("Transaction Id: {}", cinfo.transaction_id);

Expand Down
Loading
Loading