confium 0.3.2 → 0.3.4
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 +61 -0
- data/README.adoc +13 -5
- data/confium.gemspec +0 -1
- data/ext/confium_native/src/attributes.rs +5 -5
- data/ext/confium_native/src/audit.rs +8 -8
- data/ext/confium_native/src/composite.rs +10 -14
- data/ext/confium_native/src/deployment.rs +10 -9
- data/ext/confium_native/src/ers.rs +7 -11
- data/ext/confium_native/src/openpgp.rs +3 -3
- data/ext/confium_native/src/path.rs +8 -8
- data/ext/confium_native/src/pki.rs +34 -38
- data/ext/confium_native/src/tc.rs +27 -59
- data/ext/confium_native/src/transparency.rs +20 -61
- data/ext/confium_native/src/util.rs +45 -11
- 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: fdc8059371955b1e4ee89982856fb39a1fb758c9d1b3264bb2f3bd21fe77c028
|
|
4
|
+
data.tar.gz: a392f2b3d8b87e4d296f5f68dec94e61ae3e2263eea032f12240b2f625b7ba56
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ccdae726768ecf965b3f21f000b42bbc7c67a01b31d7715a2f23f0e243873453da7539ae57fbfb0ffda185d3ea572b74d0f3c033518e1e154fdc0b739db0b1b1
|
|
7
|
+
data.tar.gz: db63f19d08cf86076df52ec0f583493019e03a1512268aa1d83b56edce182d42c18120369e46ca054e66dfdf79619b04fdfe91175607845260cc668894fa680d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.4] — 2026-08-23
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Typed-error sweep completed.** Crypto operation failures
|
|
8
|
+
(FrostP256 sign, ElGamal encapsulate/decrypt/aggregate, composite
|
|
9
|
+
sign) raise `Confium::CryptoError` with the primitive in `details`;
|
|
10
|
+
`PathValidator` DER extraction failures raise `Confium::ParseError`;
|
|
11
|
+
`Manifest#tier_name_at` and `SignedData#certificate_at` out-of-range
|
|
12
|
+
raise the typed `Confium::IndexError` (unifying with the
|
|
13
|
+
transparency proofs — they previously raised Ruby's core
|
|
14
|
+
`IndexError`).
|
|
15
|
+
- **Zero compiler warnings.** All 80 direct
|
|
16
|
+
`magnus::exception::*` constructor sites are centralized into
|
|
17
|
+
`util::runtime`/`util::arg_error` (the deprecated API survives in
|
|
18
|
+
exactly one module whose job is wrapping it); the remaining magnus
|
|
19
|
+
deprecations (`RString::buf_new`, `RArray::each`) and dead imports
|
|
20
|
+
are fixed.
|
|
21
|
+
- **DoS guard now covers every byte input**: the duplicate local
|
|
22
|
+
`bytes_from_value` copies in tc/transparency — one of which
|
|
23
|
+
skipped the 1 MiB size cap — are consolidated onto the util
|
|
24
|
+
version that enforces it.
|
|
25
|
+
|
|
26
|
+
## [0.3.3] — 2026-08-23
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **Typed native errors everywhere**: PEM/DER, JSON, TOML, DSL, and
|
|
31
|
+
XML parse failures raise `Confium::ParseError`; out-of-range
|
|
32
|
+
sequence indexes raise `Confium::IndexError`; consistency-proof
|
|
33
|
+
failures raise `Confium::VerificationError` — each with a
|
|
34
|
+
structured `details` Hash (format, operation, index, ...).
|
|
35
|
+
Previously these surfaced as bare `RuntimeError`.
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- `Confium::Composite::Signature.components_to_json` /
|
|
40
|
+
`.from_json` — JSON transport for composite signatures with the
|
|
41
|
+
binary fields hex-encoded on the wire (fixes the Sinatra example's
|
|
42
|
+
happy path, which called a `from_json` that did not exist).
|
|
43
|
+
- Steep type checking in CI: the Steepfile never loaded before
|
|
44
|
+
(it used a `configure_code_diagnostics` API that does not exist in
|
|
45
|
+
steep 1.10). `sig/confium.rbs` now covers every pure-Ruby
|
|
46
|
+
subsystem — including the TC session machinery — and
|
|
47
|
+
`bundle exec steep check` is green and enforced. Only the FFI
|
|
48
|
+
layer is excluded (the ffi gem has no RBS signatures).
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- `Confium::PKI::CMS::SignedDataBuilder#build` raised KeyError on
|
|
53
|
+
the ECDSA-P256 path (`FrostP256.sign` returns `der`/`fixed`, not
|
|
54
|
+
`signature`); it now uses the DER form, which is what CMS carries.
|
|
55
|
+
- `Confium::PKI::CertificateBuilder`, `Confium::PKI::CNML`, and
|
|
56
|
+
`Confium::Transparency::OTS` were unreachable after
|
|
57
|
+
`require "confium"` (missing autoload wiring); the PKI namespace
|
|
58
|
+
file is now eager-required and registers them.
|
|
59
|
+
- All five `hello_*` quickstart examples, the Sinatra example's
|
|
60
|
+
happy path, and every page under `docs/` were rewritten against
|
|
61
|
+
the real APIs (see the docs audit), and CI now runs every example
|
|
62
|
+
on every push.
|
|
63
|
+
|
|
3
64
|
## [0.3.2] — 2026-08-22
|
|
4
65
|
|
|
5
66
|
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'
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
use confium_attributes::{evaluate, parse as dsl_parse, Predicate, SignerAttributes};
|
|
14
14
|
use magnus::{
|
|
15
|
-
|
|
15
|
+
function, method, typed_data::Obj, DataTypeFunctions, Error, Module,
|
|
16
16
|
Object, Ruby, TryConvert, TypedData, Value,
|
|
17
17
|
};
|
|
18
18
|
|
|
@@ -26,8 +26,8 @@ impl PredicateWrap {
|
|
|
26
26
|
fn satisfied_by(&self, signers_value: Value) -> Result<bool, Error> {
|
|
27
27
|
let arr = magnus::RArray::try_convert(signers_value)?;
|
|
28
28
|
let mut owned: Vec<SignerAttributes> = Vec::with_capacity(arr.len());
|
|
29
|
-
for v in arr.
|
|
30
|
-
let signer_wrap = Obj::<SignerWrap>::try_convert(v
|
|
29
|
+
for v in arr.into_iter() {
|
|
30
|
+
let signer_wrap = Obj::<SignerWrap>::try_convert(v)?;
|
|
31
31
|
owned.push(signer_wrap.inner.borrow().clone());
|
|
32
32
|
}
|
|
33
33
|
let refs: Vec<&SignerAttributes> = owned.iter().collect();
|
|
@@ -63,8 +63,8 @@ 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|
|
|
67
|
-
let ruby = Ruby::get().map_err(|e|
|
|
66
|
+
.map_err(|e| crate::util::parse_error(e.to_string(), "Attributes.parse", Some("dsl"), None))?;
|
|
67
|
+
let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
68
68
|
Ok(ruby.obj_wrap(PredicateWrap { inner: predicate }))
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
//! sink raises, the calling operation still succeeds. Audit
|
|
12
12
|
//! failures must never break a signing ceremony.
|
|
13
13
|
|
|
14
|
-
use magnus::{
|
|
14
|
+
use magnus::{function, prelude::*, Error, Module, Ruby, Value};
|
|
15
15
|
use sha2::{Digest, Sha256};
|
|
16
16
|
|
|
17
17
|
const SINK_IVAR: &str = "@sink";
|
|
@@ -94,12 +94,12 @@ fn record(
|
|
|
94
94
|
algorithm: Option<String>,
|
|
95
95
|
error: Option<String>,
|
|
96
96
|
) -> Result<(), Error> {
|
|
97
|
-
let ruby = Ruby::get().map_err(|e|
|
|
97
|
+
let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
98
98
|
let audit_mod: magnus::RModule = ruby
|
|
99
99
|
.class_object()
|
|
100
100
|
.const_get("Confium")
|
|
101
101
|
.and_then(|m: magnus::RModule| m.const_get("Audit"))
|
|
102
|
-
.map_err(|e|
|
|
102
|
+
.map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
103
103
|
|
|
104
104
|
let sink: Value = audit_mod.ivar_get(SINK_IVAR)?;
|
|
105
105
|
if sink.is_nil() {
|
|
@@ -123,31 +123,31 @@ fn record(
|
|
|
123
123
|
|
|
124
124
|
let _: Value = sink
|
|
125
125
|
.funcall("call", (h,))
|
|
126
|
-
.map_err(|e|
|
|
126
|
+
.map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
127
127
|
Ok(())
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
/// Set the global audit sink. `callback` is a Proc that receives a Hash
|
|
131
131
|
/// or nil to disable auditing.
|
|
132
132
|
fn set_sink(callback: Value) -> Result<(), Error> {
|
|
133
|
-
let ruby = Ruby::get().map_err(|e|
|
|
133
|
+
let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
134
134
|
let audit_mod: magnus::RModule = ruby
|
|
135
135
|
.class_object()
|
|
136
136
|
.const_get("Confium")
|
|
137
137
|
.and_then(|m: magnus::RModule| m.const_get("Audit"))
|
|
138
|
-
.map_err(|e|
|
|
138
|
+
.map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
139
139
|
audit_mod.ivar_set(SINK_IVAR, callback)?;
|
|
140
140
|
Ok(())
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
/// Get the current audit sink (or nil if not set).
|
|
144
144
|
fn get_sink() -> Result<Value, Error> {
|
|
145
|
-
let ruby = Ruby::get().map_err(|e|
|
|
145
|
+
let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
146
146
|
let audit_mod: magnus::RModule = ruby
|
|
147
147
|
.class_object()
|
|
148
148
|
.const_get("Confium")
|
|
149
149
|
.and_then(|m: magnus::RModule| m.const_get("Audit"))
|
|
150
|
-
.map_err(|e|
|
|
150
|
+
.map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
151
151
|
audit_mod.ivar_get(SINK_IVAR)
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
use confium_composite::{CompositeSignature, ComponentSignature, VerificationResult};
|
|
15
15
|
use ed25519_dalek::SigningKey;
|
|
16
16
|
use magnus::{
|
|
17
|
-
|
|
17
|
+
function, method, prelude::*, scan_args,
|
|
18
18
|
typed_data::Obj, DataTypeFunctions, Error, IntoValue,
|
|
19
19
|
Module, Object, RHash, Ruby, TryConvert, TypedData, Value,
|
|
20
20
|
};
|
|
@@ -79,7 +79,7 @@ impl CompositeSig {
|
|
|
79
79
|
let details = new_details(&ruby);
|
|
80
80
|
confium_error(e.to_string(), "VerificationError", details)
|
|
81
81
|
})?;
|
|
82
|
-
let ruby = Ruby::get().map_err(|e|
|
|
82
|
+
let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
83
83
|
Ok(ruby.obj_wrap(VerificationResultWrap { inner: result }))
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -133,7 +133,7 @@ impl VerificationResultWrap {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
fn per_component(&self) -> Result<Value, Error> {
|
|
136
|
-
let ruby = Ruby::get().map_err(|e|
|
|
136
|
+
let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
137
137
|
let result = ruby.hash_new();
|
|
138
138
|
for c in &self.inner.per_component {
|
|
139
139
|
let entry = ruby.hash_new();
|
|
@@ -156,9 +156,7 @@ fn sign_ed25519(ruby: &Ruby, private_key: Value, message: Value) -> Result<RHash
|
|
|
156
156
|
let pk_bytes = bytes_from_value(private_key)?;
|
|
157
157
|
let msg = bytes_from_value(message)?;
|
|
158
158
|
if pk_bytes.len() != 32 {
|
|
159
|
-
return Err(
|
|
160
|
-
exception::arg_error(),
|
|
161
|
-
format!("Ed25519 private key must be 32 bytes, got {}", pk_bytes.len()),
|
|
159
|
+
return Err(crate::util::arg_error(format!("Ed25519 private key must be 32 bytes, got {}", pk_bytes.len()),
|
|
162
160
|
));
|
|
163
161
|
}
|
|
164
162
|
let mut pk_arr = [0u8; 32];
|
|
@@ -174,7 +172,7 @@ fn sign_ed25519(ruby: &Ruby, private_key: Value, message: Value) -> Result<RHash
|
|
|
174
172
|
Some(&msg),
|
|
175
173
|
Some(&e.to_string()),
|
|
176
174
|
);
|
|
177
|
-
return Err(
|
|
175
|
+
return Err(crate::util::crypto_error(e.to_string(), "Composite.sign_ed25519", "ed25519"));
|
|
178
176
|
}
|
|
179
177
|
};
|
|
180
178
|
|
|
@@ -204,16 +202,14 @@ fn sign_p256(ruby: &Ruby, private_key: Value, message: Value) -> Result<RHash, E
|
|
|
204
202
|
let pk_bytes = bytes_from_value(private_key)?;
|
|
205
203
|
let msg = bytes_from_value(message)?;
|
|
206
204
|
if pk_bytes.len() != 32 {
|
|
207
|
-
return Err(
|
|
208
|
-
exception::arg_error(),
|
|
209
|
-
format!("P-256 private key must be 32 bytes, got {}", pk_bytes.len()),
|
|
205
|
+
return Err(crate::util::arg_error(format!("P-256 private key must be 32 bytes, got {}", pk_bytes.len()),
|
|
210
206
|
));
|
|
211
207
|
}
|
|
212
208
|
let mut arr = [0u8; 32];
|
|
213
209
|
arr.copy_from_slice(&pk_bytes);
|
|
214
210
|
use p256::ecdsa::{Signature, SigningKey, signature::Signer};
|
|
215
211
|
let signing = SigningKey::from_bytes(&arr.into())
|
|
216
|
-
.map_err(|e|
|
|
212
|
+
.map_err(|e| crate::util::arg_error(format!("invalid P-256 private key: {e}")))?;
|
|
217
213
|
let sig: Signature = match signing.try_sign(msg.as_slice()) {
|
|
218
214
|
Ok(s) => s,
|
|
219
215
|
Err(e) => {
|
|
@@ -224,7 +220,7 @@ fn sign_p256(ruby: &Ruby, private_key: Value, message: Value) -> Result<RHash, E
|
|
|
224
220
|
Some(&msg),
|
|
225
221
|
Some(&format!("sign error: {e}")),
|
|
226
222
|
);
|
|
227
|
-
return Err(
|
|
223
|
+
return Err(crate::util::crypto_error(format!("sign error: {e}"), "Composite.sign_p256", "ecdsa-p256"));
|
|
228
224
|
}
|
|
229
225
|
};
|
|
230
226
|
let verifying = signing.verifying_key();
|
|
@@ -259,8 +255,8 @@ fn generate_ed25519_keypair(ruby: &Ruby) -> Result<RHash, Error> {
|
|
|
259
255
|
fn parse_components(value: Value) -> Result<Vec<ComponentSignature>, Error> {
|
|
260
256
|
let arr = magnus::RArray::try_convert(value)?;
|
|
261
257
|
let mut out = Vec::with_capacity(arr.len());
|
|
262
|
-
for v in arr.
|
|
263
|
-
let h: RHash = RHash::try_convert(v
|
|
258
|
+
for v in arr.into_iter() {
|
|
259
|
+
let h: RHash = RHash::try_convert(v)?;
|
|
264
260
|
let algorithm: String = h.fetch::<_, String>("algorithm")?;
|
|
265
261
|
let public_key: Value = h.fetch::<_, Value>("public_key")?;
|
|
266
262
|
let signature: Value = h.fetch::<_, Value>("signature")?;
|
|
@@ -11,8 +11,8 @@ use confium_deployment::{
|
|
|
11
11
|
manifest::{parse_manifest, Manifest as RustManifest},
|
|
12
12
|
validate::validate_manifest,
|
|
13
13
|
};
|
|
14
|
-
use crate::util::enforce_size;
|
|
15
|
-
use magnus::{
|
|
14
|
+
use crate::util::{enforce_size, parse_error};
|
|
15
|
+
use magnus::{function, method, typed_data::Obj, DataTypeFunctions, Error, Module, Object, Ruby, TypedData};
|
|
16
16
|
|
|
17
17
|
#[derive(TypedData, DataTypeFunctions)]
|
|
18
18
|
#[magnus(class = "Confium::Identity::Actor", size)]
|
|
@@ -24,8 +24,8 @@ 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|
|
|
28
|
-
let ruby = Ruby::get().map_err(|e|
|
|
27
|
+
.map_err(|e| parse_error(e.to_string(), "Actor.from_json", Some("json"), None))?;
|
|
28
|
+
let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
29
29
|
Ok(ruby.obj_wrap(Self {
|
|
30
30
|
inner: std::cell::RefCell::new(actor),
|
|
31
31
|
}))
|
|
@@ -33,7 +33,7 @@ impl Actor {
|
|
|
33
33
|
|
|
34
34
|
fn to_json(&self) -> Result<String, Error> {
|
|
35
35
|
serde_json::to_string(&*self.inner.borrow())
|
|
36
|
-
.map_err(|e|
|
|
36
|
+
.map_err(|e| crate::util::runtime(e.to_string()))
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
fn actor_id(&self) -> String {
|
|
@@ -93,8 +93,8 @@ 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|
|
|
97
|
-
let ruby = Ruby::get().map_err(|e|
|
|
96
|
+
.map_err(|e| parse_error(e.to_string(), "Manifest.from_toml", Some("toml"), None))?;
|
|
97
|
+
let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
98
98
|
Ok(ruby.obj_wrap(Self {
|
|
99
99
|
inner: std::cell::RefCell::new(manifest),
|
|
100
100
|
}))
|
|
@@ -123,9 +123,10 @@ impl Manifest {
|
|
|
123
123
|
.get(index)
|
|
124
124
|
.map(|t| t.name.clone())
|
|
125
125
|
.ok_or_else(|| {
|
|
126
|
-
|
|
127
|
-
exception::index_error(),
|
|
126
|
+
crate::util::index_error(
|
|
128
127
|
format!("tier index {index} out of range"),
|
|
128
|
+
"Manifest.tier_name_at",
|
|
129
|
+
Some(index as u64),
|
|
129
130
|
)
|
|
130
131
|
})
|
|
131
132
|
}
|
|
@@ -5,7 +5,7 @@ use confium_transparency::ers::{
|
|
|
5
5
|
EvidenceRecord, HashAlgorithm,
|
|
6
6
|
};
|
|
7
7
|
use magnus::{
|
|
8
|
-
|
|
8
|
+
function, method, typed_data::Obj,
|
|
9
9
|
DataTypeFunctions, Error, Module, Object, Ruby, TryConvert, TypedData, Value,
|
|
10
10
|
};
|
|
11
11
|
|
|
@@ -20,13 +20,11 @@ pub struct ErsRecord {
|
|
|
20
20
|
impl ErsRecord {
|
|
21
21
|
fn build_initial(args: &[Value]) -> Result<Obj<Self>, Error> {
|
|
22
22
|
let first = args.first().ok_or_else(|| {
|
|
23
|
-
|
|
23
|
+
crate::util::arg_error("data_hash required")
|
|
24
24
|
})?;
|
|
25
25
|
let data_hash = bytes_from_value(*first)?;
|
|
26
26
|
if data_hash.len() != 32 {
|
|
27
|
-
return Err(
|
|
28
|
-
exception::arg_error(),
|
|
29
|
-
format!("data_hash must be 32 bytes, got {}", data_hash.len()),
|
|
27
|
+
return Err(crate::util::arg_error(format!("data_hash must be 32 bytes, got {}", data_hash.len()),
|
|
30
28
|
));
|
|
31
29
|
}
|
|
32
30
|
let mut hash = [0u8; 32];
|
|
@@ -42,7 +40,7 @@ impl ErsRecord {
|
|
|
42
40
|
let record =
|
|
43
41
|
build_initial_evidence_record(hash, HashAlgorithm::Sha256, tsa_id, token_bytes);
|
|
44
42
|
let ruby = Ruby::get()
|
|
45
|
-
.map_err(|e|
|
|
43
|
+
.map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
46
44
|
Ok(ruby.obj_wrap(Self {
|
|
47
45
|
inner: std::cell::RefCell::new(record),
|
|
48
46
|
}))
|
|
@@ -50,13 +48,11 @@ impl ErsRecord {
|
|
|
50
48
|
|
|
51
49
|
fn renew(&self, args: &[Value]) -> Result<Obj<Self>, Error> {
|
|
52
50
|
let first = args.first().ok_or_else(|| {
|
|
53
|
-
|
|
51
|
+
crate::util::arg_error("new_hash required")
|
|
54
52
|
})?;
|
|
55
53
|
let new_hash_bytes = bytes_from_value(*first)?;
|
|
56
54
|
if new_hash_bytes.len() != 32 {
|
|
57
|
-
return Err(
|
|
58
|
-
exception::arg_error(),
|
|
59
|
-
format!("new_hash must be 32 bytes, got {}", new_hash_bytes.len()),
|
|
55
|
+
return Err(crate::util::arg_error(format!("new_hash must be 32 bytes, got {}", new_hash_bytes.len()),
|
|
60
56
|
));
|
|
61
57
|
}
|
|
62
58
|
let mut hash = [0u8; 32];
|
|
@@ -72,7 +68,7 @@ impl ErsRecord {
|
|
|
72
68
|
let mut cloned = self.inner.borrow().clone();
|
|
73
69
|
renew_evidence_record(&mut cloned, HashAlgorithm::Sha256, hash, tsa_id, token_bytes);
|
|
74
70
|
let ruby = Ruby::get()
|
|
75
|
-
.map_err(|e|
|
|
71
|
+
.map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
76
72
|
Ok(ruby.obj_wrap(Self {
|
|
77
73
|
inner: std::cell::RefCell::new(cloned),
|
|
78
74
|
}))
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//!
|
|
3
3
|
//! Confium ships RNP functionality baked into the native extension.
|
|
4
4
|
|
|
5
|
-
use magnus::{
|
|
5
|
+
use magnus::{function, prelude::*, Error, Module, RModule, Ruby, TryConvert, Value};
|
|
6
6
|
use rnp::ops::ArmorType;
|
|
7
7
|
use rnp::{armor_bytes, dearmor_bytes};
|
|
8
8
|
|
|
@@ -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 @@ use confium_pki::{
|
|
|
10
10
|
path::{validate_path, CertPath},
|
|
11
11
|
result::VerificationResult as PathVerificationResult,
|
|
12
12
|
};
|
|
13
|
-
use magnus::{
|
|
13
|
+
use magnus::{function, method, prelude::*, DataTypeFunctions, Error, Module, Ruby, TypedData, Value};
|
|
14
14
|
|
|
15
15
|
/// Wraps a confium_pki::path::VerificationResult.
|
|
16
16
|
#[derive(TypedData, DataTypeFunctions)]
|
|
@@ -63,17 +63,17 @@ fn validate(args: &[Value]) -> Result<magnus::typed_data::Obj<PathResult>, Error
|
|
|
63
63
|
Vec::new()
|
|
64
64
|
} else {
|
|
65
65
|
let arr = magnus::RArray::try_convert(intermediates_value)
|
|
66
|
-
.map_err(|e|
|
|
66
|
+
.map_err(|e| crate::util::arg_error(e.to_string()))?;
|
|
67
67
|
let mut out = Vec::with_capacity(arr.len());
|
|
68
|
-
for v in arr.
|
|
69
|
-
out.push(extract_cert(v
|
|
68
|
+
for v in arr.into_iter() {
|
|
69
|
+
out.push(extract_cert(v, "intermediate")?);
|
|
70
70
|
}
|
|
71
71
|
out
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
let now = match now_iso8601 {
|
|
75
75
|
Some(s) => chrono::DateTime::parse_from_rfc3339(&s)
|
|
76
|
-
.map_err(|e|
|
|
76
|
+
.map_err(|e| crate::util::arg_error(format!("invalid time: {e}")))?
|
|
77
77
|
.with_timezone(&Utc),
|
|
78
78
|
None => Utc::now(),
|
|
79
79
|
};
|
|
@@ -86,7 +86,7 @@ fn validate(args: &[Value]) -> Result<magnus::typed_data::Obj<PathResult>, Error
|
|
|
86
86
|
let result = validate_path(&path, now);
|
|
87
87
|
|
|
88
88
|
let ruby = Ruby::get()
|
|
89
|
-
.map_err(|e|
|
|
89
|
+
.map_err(|e| crate::util::runtime(e.to_string()))?;
|
|
90
90
|
Ok(ruby.obj_wrap(PathResult { inner: result }))
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -98,10 +98,10 @@ fn extract_cert(value: Value, label: &str) -> Result<RustCert, Error> {
|
|
|
98
98
|
// We re-parse those bytes into a fresh RustCert.
|
|
99
99
|
let der_value: Value = value
|
|
100
100
|
.funcall("to_der", ())
|
|
101
|
-
.map_err(|e|
|
|
101
|
+
.map_err(|e| crate::util::parse_error(format!("{label}: cannot get DER: {e}"), "PathValidator.validate", Some("der"), None))?;
|
|
102
102
|
let der = crate::util::bytes_from_value(der_value)?;
|
|
103
103
|
RustCert::from_der(&der)
|
|
104
|
-
.map_err(|e|
|
|
104
|
+
.map_err(|e| crate::util::parse_error(format!("{label}: invalid DER: {e}"), "PathValidator.validate", Some("der"), None))
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
pub fn init(ruby: &Ruby, parent: magnus::RModule) -> Result<(), Error> {
|