confium 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +38 -0
- data/README.adoc +13 -5
- data/confium.gemspec +0 -1
- data/ext/confium_native/src/attributes.rs +1 -1
- data/ext/confium_native/src/deployment.rs +3 -3
- data/ext/confium_native/src/openpgp.rs +2 -2
- data/ext/confium_native/src/pki.rs +8 -8
- data/ext/confium_native/src/transparency.rs +4 -4
- data/ext/confium_native/src/util.rs +13 -0
- data/lib/confium/audit.rb +1 -0
- data/lib/confium/composite.rb +50 -0
- data/lib/confium/crypto.rb +1 -0
- data/lib/confium/pki/cms/signed_data_builder.rb +4 -1
- data/lib/confium/pki.rb +2 -0
- data/lib/confium/transparency.rb +12 -0
- data/lib/confium/version.rb +1 -1
- data/lib/confium.rb +14 -3
- metadata +4 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c325019a3961cbf877d81c11496cfccba51959282d930b1e5e0420b25b66958
|
|
4
|
+
data.tar.gz: 91ea66bd4a9541e38ce7c01c03c26408a8372debdce0539c13ab70aee4895970
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e70d630fd442cf891ff15cdd27fc335281488ca5c5985f298337559ad9caf2dfb77bdf7993dd47f766116512bff4e3a53e2939b55cc8b91f77744176780faaf5
|
|
7
|
+
data.tar.gz: 3f389ce934ed8f8f81bb13e87346f07b49d06f48acb1196c3774e7c01f1ad810185f22b6708edb0d887193afef4d5d850c3cd4fb6c58e2b246aae09300f5e419
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.3] — 2026-08-23
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Typed native errors everywhere**: PEM/DER, JSON, TOML, DSL, and
|
|
8
|
+
XML parse failures raise `Confium::ParseError`; out-of-range
|
|
9
|
+
sequence indexes raise `Confium::IndexError`; consistency-proof
|
|
10
|
+
failures raise `Confium::VerificationError` — each with a
|
|
11
|
+
structured `details` Hash (format, operation, index, ...).
|
|
12
|
+
Previously these surfaced as bare `RuntimeError`.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- `Confium::Composite::Signature.components_to_json` /
|
|
17
|
+
`.from_json` — JSON transport for composite signatures with the
|
|
18
|
+
binary fields hex-encoded on the wire (fixes the Sinatra example's
|
|
19
|
+
happy path, which called a `from_json` that did not exist).
|
|
20
|
+
- Steep type checking in CI: the Steepfile never loaded before
|
|
21
|
+
(it used a `configure_code_diagnostics` API that does not exist in
|
|
22
|
+
steep 1.10). `sig/confium.rbs` now covers every pure-Ruby
|
|
23
|
+
subsystem — including the TC session machinery — and
|
|
24
|
+
`bundle exec steep check` is green and enforced. Only the FFI
|
|
25
|
+
layer is excluded (the ffi gem has no RBS signatures).
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- `Confium::PKI::CMS::SignedDataBuilder#build` raised KeyError on
|
|
30
|
+
the ECDSA-P256 path (`FrostP256.sign` returns `der`/`fixed`, not
|
|
31
|
+
`signature`); it now uses the DER form, which is what CMS carries.
|
|
32
|
+
- `Confium::PKI::CertificateBuilder`, `Confium::PKI::CNML`, and
|
|
33
|
+
`Confium::Transparency::OTS` were unreachable after
|
|
34
|
+
`require "confium"` (missing autoload wiring); the PKI namespace
|
|
35
|
+
file is now eager-required and registers them.
|
|
36
|
+
- All five `hello_*` quickstart examples, the Sinatra example's
|
|
37
|
+
happy path, and every page under `docs/` were rewritten against
|
|
38
|
+
the real APIs (see the docs audit), and CI now runs every example
|
|
39
|
+
on every push.
|
|
40
|
+
|
|
3
41
|
## [0.3.2] — 2026-08-22
|
|
4
42
|
|
|
5
43
|
Native platform gems (linux x86_64/aarch64, macOS x86_64/arm64) ship
|
data/README.adoc
CHANGED
|
@@ -10,7 +10,7 @@ Confium supports three deployment modes:
|
|
|
10
10
|
* **Mode 2 — TC PKI replacement**: drop-in for existing PKI consumers (PKCS#11 server, OpenSSL 3.0 provider, JCE)
|
|
11
11
|
* **Mode 3 — TC Certificate PKI**: institutional deployments with custom certificate formats (OIML CNML, BIPM, pharma, accreditation)
|
|
12
12
|
|
|
13
|
-
This gem wraps the high-value Confium subsystems via a Rust native extension
|
|
13
|
+
This gem wraps the high-value Confium subsystems via a Rust native extension. Pre-compiled platform gems are published for Linux and macOS, so `gem install` needs no Rust toolchain there; other platforms build from source at install time with `rb_sys` + `magnus`. No separate C ABI library to install; everything is statically linked into the extension.
|
|
14
14
|
|
|
15
15
|
== Installation
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ Add to your Gemfile:
|
|
|
18
18
|
|
|
19
19
|
[source,ruby]
|
|
20
20
|
----
|
|
21
|
-
gem "confium", "~> 0.
|
|
21
|
+
gem "confium", "~> 0.3"
|
|
22
22
|
----
|
|
23
23
|
|
|
24
24
|
Or install directly:
|
|
@@ -31,10 +31,18 @@ $ gem install confium
|
|
|
31
31
|
=== Prerequisites
|
|
32
32
|
|
|
33
33
|
* Ruby ≥ 3.1
|
|
34
|
+
* Nothing else on the pre-compiled platforms: `x86_64-linux`,
|
|
35
|
+
`aarch64-linux`, `x86_64-darwin`, `arm64-darwin` (each gem carries
|
|
36
|
+
one extension per Ruby C-ABI window)
|
|
37
|
+
|
|
38
|
+
Source builds (other platforms, or installing from the repo) also
|
|
39
|
+
need:
|
|
40
|
+
|
|
34
41
|
* Rust stable toolchain (`rustup default stable`)
|
|
35
42
|
* C toolchain (clang/gcc/Xcode CLT)
|
|
36
43
|
|
|
37
|
-
|
|
44
|
+
There is no separate `libconfium` to install — the extension
|
|
45
|
+
statically links everything.
|
|
38
46
|
|
|
39
47
|
== Quick start
|
|
40
48
|
|
|
@@ -76,7 +84,7 @@ recovered = Confium::TC::FrostP256.recover_secret(shares.first(3).map { |s| { "x
|
|
|
76
84
|
recovered == kp["private_key"] # => true
|
|
77
85
|
----
|
|
78
86
|
|
|
79
|
-
== API surface (v0.
|
|
87
|
+
== API surface (v0.3)
|
|
80
88
|
|
|
81
89
|
=== `Confium::Transparency`
|
|
82
90
|
- `MerkleTree.new` / `#append(artifact_hash)` / `#root` / `#length` / `#empty?` / `#inclusion_proof(seq)`
|
|
@@ -127,7 +135,7 @@ After checking out the repo:
|
|
|
127
135
|
----
|
|
128
136
|
$ bundle install
|
|
129
137
|
$ bundle exec rake compile # build the Rust extension
|
|
130
|
-
$ bundle exec rspec #
|
|
138
|
+
$ bundle exec rspec # 226 specs
|
|
131
139
|
----
|
|
132
140
|
|
|
133
141
|
== Architecture
|
data/confium.gemspec
CHANGED
|
@@ -49,7 +49,6 @@ Gem::Specification.new do |spec|
|
|
|
49
49
|
|
|
50
50
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
51
51
|
spec.add_development_dependency 'rake-compiler', '~> 1.3.0'
|
|
52
|
-
spec.add_development_dependency 'rake-compiler-dock', '~> 1.3'
|
|
53
52
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
54
53
|
spec.add_development_dependency 'rubocop', '~> 1.0'
|
|
55
54
|
spec.add_development_dependency 'steep', '~> 1.5'
|
|
@@ -63,7 +63,7 @@ impl SignerWrap {
|
|
|
63
63
|
|
|
64
64
|
fn parse(expr: String) -> Result<Obj<PredicateWrap>, Error> {
|
|
65
65
|
let predicate = dsl_parse(&expr)
|
|
66
|
-
.map_err(|e|
|
|
66
|
+
.map_err(|e| crate::util::parse_error(e.to_string(), "Attributes.parse", Some("dsl"), None))?;
|
|
67
67
|
let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
|
|
68
68
|
Ok(ruby.obj_wrap(PredicateWrap { inner: predicate }))
|
|
69
69
|
}
|
|
@@ -11,7 +11,7 @@ use confium_deployment::{
|
|
|
11
11
|
manifest::{parse_manifest, Manifest as RustManifest},
|
|
12
12
|
validate::validate_manifest,
|
|
13
13
|
};
|
|
14
|
-
use crate::util::enforce_size;
|
|
14
|
+
use crate::util::{enforce_size, parse_error};
|
|
15
15
|
use magnus::{exception, function, method, typed_data::Obj, DataTypeFunctions, Error, Module, Object, Ruby, TypedData};
|
|
16
16
|
|
|
17
17
|
#[derive(TypedData, DataTypeFunctions)]
|
|
@@ -24,7 +24,7 @@ impl Actor {
|
|
|
24
24
|
fn from_json(json: String) -> Result<Obj<Self>, Error> {
|
|
25
25
|
enforce_size(json.len())?;
|
|
26
26
|
let actor: ActorIdentity = serde_json::from_str(&json)
|
|
27
|
-
.map_err(|e|
|
|
27
|
+
.map_err(|e| parse_error(e.to_string(), "Actor.from_json", Some("json"), None))?;
|
|
28
28
|
let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
|
|
29
29
|
Ok(ruby.obj_wrap(Self {
|
|
30
30
|
inner: std::cell::RefCell::new(actor),
|
|
@@ -93,7 +93,7 @@ impl Manifest {
|
|
|
93
93
|
fn from_toml(toml_str: String) -> Result<Obj<Self>, Error> {
|
|
94
94
|
enforce_size(toml_str.len())?;
|
|
95
95
|
let manifest = parse_manifest(&toml_str)
|
|
96
|
-
.map_err(|e|
|
|
96
|
+
.map_err(|e| parse_error(e.to_string(), "Manifest.from_toml", Some("toml"), None))?;
|
|
97
97
|
let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
|
|
98
98
|
Ok(ruby.obj_wrap(Self {
|
|
99
99
|
inner: std::cell::RefCell::new(manifest),
|
|
@@ -26,7 +26,7 @@ fn native_armor(ruby: &Ruby, data: Value, type_str: Value) -> Result<magnus::RSt
|
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
28
|
let armored = armor_bytes(&bytes, ty)
|
|
29
|
-
.map_err(|e|
|
|
29
|
+
.map_err(|e| crate::util::parse_error(e.to_string(), "OpenPGP.armor", Some("openpgp"), None))?;
|
|
30
30
|
Ok(bytes_to_rstring(ruby, &armored))
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -34,7 +34,7 @@ fn native_armor(ruby: &Ruby, data: Value, type_str: Value) -> Result<magnus::RSt
|
|
|
34
34
|
fn native_dearmor(ruby: &Ruby, data: Value) -> Result<magnus::RString, Error> {
|
|
35
35
|
let bytes = bytes_from_value(data)?;
|
|
36
36
|
let raw = dearmor_bytes(&bytes)
|
|
37
|
-
.map_err(|e|
|
|
37
|
+
.map_err(|e| crate::util::parse_error(e.to_string(), "OpenPGP.dearmor", Some("openpgp"), None))?;
|
|
38
38
|
Ok(bytes_to_rstring(ruby, &raw))
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
//! *building* + signing lands in a follow-up once the Rust builder API
|
|
11
11
|
//! stabilizes (currently `confium_pki::cert::builder` is private).
|
|
12
12
|
|
|
13
|
-
use crate::util::{bytes_from_value, bytes_to_rstring, enforce_size};
|
|
13
|
+
use crate::util::{bytes_from_value, bytes_to_rstring, enforce_size, parse_error};
|
|
14
14
|
use chrono::{DateTime, Utc};
|
|
15
15
|
use confium_pki::{
|
|
16
16
|
cert::{Certificate as RustCert, CertificateSigningRequest as RustCsr},
|
|
@@ -34,7 +34,7 @@ impl Certificate {
|
|
|
34
34
|
fn from_der(bytes: Value) -> Result<Obj<Self>, Error> {
|
|
35
35
|
let der = bytes_from_value(bytes)?;
|
|
36
36
|
let cert = RustCert::from_der(&der)
|
|
37
|
-
.map_err(|e|
|
|
37
|
+
.map_err(|e| parse_error(e.to_string(), "Certificate.from_der", Some("der"), None))?;
|
|
38
38
|
let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
|
|
39
39
|
Ok(ruby.obj_wrap(Self { inner: cert }))
|
|
40
40
|
}
|
|
@@ -42,7 +42,7 @@ impl Certificate {
|
|
|
42
42
|
fn from_pem(pem: String) -> Result<Obj<Self>, Error> {
|
|
43
43
|
enforce_size(pem.len())?;
|
|
44
44
|
let cert = RustCert::from_pem(&pem)
|
|
45
|
-
.map_err(|e|
|
|
45
|
+
.map_err(|e| parse_error(e.to_string(), "Certificate.from_pem", Some("pem"), None))?;
|
|
46
46
|
let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
|
|
47
47
|
Ok(ruby.obj_wrap(Self { inner: cert }))
|
|
48
48
|
}
|
|
@@ -102,7 +102,7 @@ impl Csr {
|
|
|
102
102
|
fn from_der(bytes: Value) -> Result<Obj<Self>, Error> {
|
|
103
103
|
let der = bytes_from_value(bytes)?;
|
|
104
104
|
let csr = RustCsr::from_der(&der)
|
|
105
|
-
.map_err(|e|
|
|
105
|
+
.map_err(|e| parse_error(e.to_string(), "Csr.from_der", Some("der"), None))?;
|
|
106
106
|
let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
|
|
107
107
|
Ok(ruby.obj_wrap(Self { inner: csr }))
|
|
108
108
|
}
|
|
@@ -110,7 +110,7 @@ impl Csr {
|
|
|
110
110
|
fn from_pem(pem: String) -> Result<Obj<Self>, Error> {
|
|
111
111
|
enforce_size(pem.len())?;
|
|
112
112
|
let csr = RustCsr::from_pem(&pem)
|
|
113
|
-
.map_err(|e|
|
|
113
|
+
.map_err(|e| parse_error(e.to_string(), "Csr.from_pem", Some("pem"), None))?;
|
|
114
114
|
let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
|
|
115
115
|
Ok(ruby.obj_wrap(Self { inner: csr }))
|
|
116
116
|
}
|
|
@@ -135,7 +135,7 @@ impl SignedData {
|
|
|
135
135
|
fn from_json(json: String) -> Result<Obj<Self>, Error> {
|
|
136
136
|
enforce_size(json.len())?;
|
|
137
137
|
let sd: RustSignedData = serde_json::from_str(&json)
|
|
138
|
-
.map_err(|e|
|
|
138
|
+
.map_err(|e| parse_error(e.to_string(), "SignedData.from_json", Some("json"), None))?;
|
|
139
139
|
let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
|
|
140
140
|
Ok(ruby.obj_wrap(Self {
|
|
141
141
|
inner: std::cell::RefCell::new(sd),
|
|
@@ -362,12 +362,12 @@ impl CertWrapper {
|
|
|
362
362
|
|
|
363
363
|
fn xmldsig_canonicalize(xml: String) -> Result<String, Error> {
|
|
364
364
|
enforce_size(xml.len())?;
|
|
365
|
-
canonicalize(&xml).map_err(|e|
|
|
365
|
+
canonicalize(&xml).map_err(|e| parse_error(e.to_string(), "XMLDSig.canonicalize", Some("xml"), None))
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
fn xmldsig_canonicalize_exclusive(xml: String) -> Result<String, Error> {
|
|
369
369
|
enforce_size(xml.len())?;
|
|
370
|
-
canonicalize_exclusive(&xml).map_err(|e|
|
|
370
|
+
canonicalize_exclusive(&xml).map_err(|e| parse_error(e.to_string(), "XMLDSig.canonicalize_exclusive", Some("xml"), None))
|
|
371
371
|
}
|
|
372
372
|
|
|
373
373
|
pub fn init(ruby: &Ruby, parent: magnus::RModule) -> Result<(), Error> {
|
|
@@ -72,7 +72,7 @@ impl MerkleTree {
|
|
|
72
72
|
.inner
|
|
73
73
|
.borrow()
|
|
74
74
|
.consistency_proof(old_size)
|
|
75
|
-
.map_err(|e|
|
|
75
|
+
.map_err(|e| crate::util::index_error(e.to_string(), "MerkleTree.consistency_proof", Some(old_size as u64)))?;
|
|
76
76
|
let ruby = Ruby::get()
|
|
77
77
|
.map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
|
|
78
78
|
let arr = ruby.ary_new_capa(proof.len());
|
|
@@ -142,7 +142,7 @@ impl MerkleTree {
|
|
|
142
142
|
.borrow()
|
|
143
143
|
.verify_consistency(old_root_hash, new_root_hash, old_size, new_size, &proof_hashes)
|
|
144
144
|
.map(|_| true)
|
|
145
|
-
.map_err(|e|
|
|
145
|
+
.map_err(|e| crate::util::verification_error(e.to_string(), "MerkleTree.verify_consistency", None, None))
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
fn root(&self) -> Value {
|
|
@@ -155,10 +155,10 @@ impl MerkleTree {
|
|
|
155
155
|
let tree = self.inner.borrow();
|
|
156
156
|
let proof = tree
|
|
157
157
|
.inclusion_proof(seq)
|
|
158
|
-
.map_err(|e|
|
|
158
|
+
.map_err(|e| crate::util::index_error(e.to_string(), "MerkleTree.inclusion_proof", Some(seq)))?;
|
|
159
159
|
let entry = tree
|
|
160
160
|
.entry(seq)
|
|
161
|
-
.map_err(|e|
|
|
161
|
+
.map_err(|e| crate::util::index_error(e.to_string(), "MerkleTree.inclusion_proof", Some(seq)))?;
|
|
162
162
|
// Re-derive the leaf hash with the same algorithm the tree uses
|
|
163
163
|
// internally (H(0x01 | entry_hash)).
|
|
164
164
|
let leaf_hash = hash_leaf(entry.entry_hash());
|
|
@@ -148,6 +148,19 @@ pub fn parse_error(msg: impl Into<String>, operation: &str, format: Option<&str>
|
|
|
148
148
|
confium_error(msg, "ParseError", d)
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
#[allow(dead_code)]
|
|
152
|
+
pub fn index_error(msg: impl Into<String>, operation: &str, index: Option<u64>) -> Error {
|
|
153
|
+
let ruby = match Ruby::get() {
|
|
154
|
+
Ok(r) => r,
|
|
155
|
+
Err(_) => return Error::new(exception::runtime_error(), msg.into()),
|
|
156
|
+
};
|
|
157
|
+
let d = new_details(&ruby);
|
|
158
|
+
let _ = d.aset("operation", operation);
|
|
159
|
+
let _ = d.aset("component", "Confium");
|
|
160
|
+
if let Some(i) = index { let _ = d.aset("index", i); }
|
|
161
|
+
confium_error(msg, "IndexError", d)
|
|
162
|
+
}
|
|
163
|
+
|
|
151
164
|
#[allow(dead_code)]
|
|
152
165
|
pub fn validation_error(msg: impl Into<String>, operation: &str, param: &str, expected: &str, actual: &str) -> Error {
|
|
153
166
|
let ruby = match Ruby::get() {
|
data/lib/confium/audit.rb
CHANGED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Confium
|
|
6
|
+
module Composite
|
|
7
|
+
# JSON transport for composite signatures. The native extension
|
|
8
|
+
# defines Signature with algorithms/component_count/verify over
|
|
9
|
+
# component Hashes (algorithm, public_key, signature) whose
|
|
10
|
+
# binary fields cannot ride JSON directly, so the wire format
|
|
11
|
+
# hex-encodes them:
|
|
12
|
+
#
|
|
13
|
+
# json = Confium::Composite::Signature.components_to_json(components)
|
|
14
|
+
# sig = Confium::Composite::Signature.from_json(json)
|
|
15
|
+
# sig.verify(message)
|
|
16
|
+
class Signature
|
|
17
|
+
BINARY_FIELDS = %w[public_key signature].freeze
|
|
18
|
+
|
|
19
|
+
def self.components_to_json(components)
|
|
20
|
+
JSON.generate(components.map do |component|
|
|
21
|
+
component.transform_values do |value|
|
|
22
|
+
value.encoding == Encoding::ASCII_8BIT ? value.unpack1('H*') : value
|
|
23
|
+
end
|
|
24
|
+
end)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Accepts either a bare JSON array of component Hashes or a
|
|
28
|
+
# {"components": [...]} envelope, with public_key/signature
|
|
29
|
+
# hex-encoded on the wire. Takes a JSON string or an
|
|
30
|
+
# already-parsed Array/Hash.
|
|
31
|
+
def self.from_json(json)
|
|
32
|
+
data = json.is_a?(String) ? JSON.parse(json) : json
|
|
33
|
+
components = data.is_a?(Hash) ? data['components'] : data
|
|
34
|
+
unless components.is_a?(Array) && !components.empty?
|
|
35
|
+
raise ArgumentError, 'expected a non-empty "components" array'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
new(components.map { |c| decode_binary_fields(c) })
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.decode_binary_fields(component)
|
|
42
|
+
BINARY_FIELDS.each_with_object(component.dup) do |field, decoded|
|
|
43
|
+
value = component.fetch(field)
|
|
44
|
+
decoded[field] = [value].pack('H*') if value.is_a?(String)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
private_class_method :decode_binary_fields
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/confium/crypto.rb
CHANGED
|
@@ -33,6 +33,7 @@ module Confium
|
|
|
33
33
|
|
|
34
34
|
def initialize
|
|
35
35
|
@content = nil
|
|
36
|
+
# @type ivar @signers: Array[Hash[Symbol, untyped]]
|
|
36
37
|
@signers = []
|
|
37
38
|
end
|
|
38
39
|
|
|
@@ -81,7 +82,9 @@ module Confium
|
|
|
81
82
|
result.fetch('signature')
|
|
82
83
|
when :ecdsa_p256
|
|
83
84
|
result = Confium::TC::FrostP256.sign(private_key, payload)
|
|
84
|
-
|
|
85
|
+
# CMS carries ECDSA signatures DER-encoded (DSA-Sig-Value);
|
|
86
|
+
# FrostP256.sign returns { "der" => ..., "fixed" => ... }.
|
|
87
|
+
result.fetch('der')
|
|
85
88
|
else
|
|
86
89
|
raise ArgumentError, "unsupported algorithm: #{algorithm.inspect}"
|
|
87
90
|
end
|
data/lib/confium/pki.rb
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Confium::Transparency namespace file.
|
|
4
|
+
#
|
|
5
|
+
# The Transparency module itself is defined by the native Rust
|
|
6
|
+
# extension via magnus at require time. This file registers
|
|
7
|
+
# pure-Ruby autoloads for the Transparency submodules.
|
|
8
|
+
module Confium
|
|
9
|
+
module Transparency
|
|
10
|
+
autoload :OTS, 'confium/transparency/ots'
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/confium/version.rb
CHANGED
data/lib/confium.rb
CHANGED
|
@@ -18,8 +18,7 @@ begin
|
|
|
18
18
|
# 3.1 and 3.2 get exact-minor builds while 3.3 covers 3.3+).
|
|
19
19
|
# Source builds install the extension flat, without a version
|
|
20
20
|
# directory.
|
|
21
|
-
|
|
22
|
-
window = major > 3 || minor >= 3 ? '3.3' : "#{major}.#{minor}"
|
|
21
|
+
window = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.3') ? '3.3' : RUBY_VERSION[/\A\d+\.\d+/]
|
|
23
22
|
begin
|
|
24
23
|
require_relative "confium_native/#{window}/confium_native"
|
|
25
24
|
rescue LoadError
|
|
@@ -56,9 +55,21 @@ module Confium
|
|
|
56
55
|
autoload :PolicyViolationError, 'confium/errors/policy_violation_error'
|
|
57
56
|
autoload :SecureBytes, 'confium/secure_bytes'
|
|
58
57
|
autoload :Policy, 'confium/policy'
|
|
59
|
-
|
|
58
|
+
# PKI is native-defined, so an autoload would never fire; the
|
|
59
|
+
# namespace file is eager-required and registers the pure-Ruby
|
|
60
|
+
# submodules (CMS, CertificateBuilder, CNML) as autoloads.
|
|
61
|
+
require_relative 'confium/pki'
|
|
60
62
|
end
|
|
61
63
|
|
|
64
|
+
# Eager-load the Composite Signature JSON companion. The native
|
|
65
|
+
# extension defines Confium::Composite; this file reopens the class
|
|
66
|
+
# to add from_json transport.
|
|
67
|
+
require_relative 'confium/composite'
|
|
68
|
+
|
|
69
|
+
# Eager-load the Transparency namespace for the OTS autoload (the
|
|
70
|
+
# module itself is native-defined).
|
|
71
|
+
require_relative 'confium/transparency'
|
|
72
|
+
|
|
62
73
|
# Eager-load the Audit Ruby companion. The native extension registers
|
|
63
74
|
# `Confium::Audit` as a Ruby module with the `record`/`sink=`/`sink`
|
|
64
75
|
# methods; the companion file defines the Sink class hierarchy on top
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: confium
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Open
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rb_sys
|
|
@@ -52,20 +52,6 @@ dependencies:
|
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: 1.3.0
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: rake-compiler-dock
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - "~>"
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '1.3'
|
|
62
|
-
type: :development
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - "~>"
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '1.3'
|
|
69
55
|
- !ruby/object:Gem::Dependency
|
|
70
56
|
name: rspec
|
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -144,6 +130,7 @@ files:
|
|
|
144
130
|
- lib/confium.rb
|
|
145
131
|
- lib/confium/audit.rb
|
|
146
132
|
- lib/confium/cfm.rb
|
|
133
|
+
- lib/confium/composite.rb
|
|
147
134
|
- lib/confium/crypto.rb
|
|
148
135
|
- lib/confium/digest.rb
|
|
149
136
|
- lib/confium/errors.rb
|
|
@@ -172,6 +159,7 @@ files:
|
|
|
172
159
|
- lib/confium/tc/session.rb
|
|
173
160
|
- lib/confium/tc/session_stub.rb
|
|
174
161
|
- lib/confium/tc/share_file.rb
|
|
162
|
+
- lib/confium/transparency.rb
|
|
175
163
|
- lib/confium/transparency/ots.rb
|
|
176
164
|
- lib/confium/version.rb
|
|
177
165
|
homepage: https://www.confium.org
|