Skip to content

Commit 76c1808

Browse files
authored
Add 'RELATIVE OID' support with fork of 'der' crate (#58)
- Clean up some dependencies, using x509-cert and der directly where applicable instead of re-exports from x509-verify crate. - Add basic 'RELATIVE OID' parsing support. Eventually, we should upstream this. - Bump 'der' dependency to '0.7.10', and switch to fork that has 'RELATIVE OID' tag support. PR to upstream support is at RustCrypto/formats#1942.
1 parent 73b7438 commit 76c1808

File tree

18 files changed

+183
-72
lines changed

18 files changed

+183
-72
lines changed

Cargo.lock

Lines changed: 43 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ console_error_panic_hook = "0.1.1"
3838
console_log = { version = "1.0" }
3939
criterion = { version = "0.5", features = ["html_reports"] }
4040
generic_log_worker = { path = "crates/generic_log_worker", version = "0.2.0" }
41-
der = "0.7.9"
41+
der = "0.7.10"
4242
ed25519-dalek = { version = "2.1.1", features = ["pem"] }
4343
futures-executor = "0.3.31"
4444
futures-util = "0.3.31"
@@ -69,6 +69,7 @@ tlog_tiles = { path = "crates/tlog_tiles", version = "0.2.0" }
6969
tokio = { version = "1", features = ["sync"] }
7070
url = "2.2"
7171
worker = "0.5.0"
72+
x509-cert = "0.2.5"
7273
x509-verify = { version = "0.4.4", features = [
7374
"md2",
7475
"md5",
@@ -86,3 +87,6 @@ x509-verify = { version = "0.4.4", features = [
8687
"pem",
8788
] }
8889
x509_util = { path = "crates/x509_util" }
90+
91+
[patch.crates-io]
92+
der = { git = "https://github.com/lukevalenta/formats", branch = "relative-oid-tag-v0.7.10" }

crates/ct_worker/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jsonschema.workspace = true
2929
serde_json.workspace = true
3030
serde.workspace = true
3131
url.workspace = true
32-
x509-verify.workspace = true
32+
x509-cert.workspace = true
3333

3434
[dev-dependencies]
3535
rand = { workspace = true, features = ["small_rng"] }
@@ -55,7 +55,7 @@ static_ct_api.workspace = true
5555
signed_note.workspace = true
5656
tlog_tiles.workspace = true
5757
worker.workspace = true
58-
x509-verify.workspace = true
58+
x509-cert.workspace = true
5959
x509_util.workspace = true
6060
prometheus.workspace = true
6161

crates/ct_worker/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use serde_json::from_str;
99
use std::env;
1010
use std::fs;
1111
use url::Url;
12-
use x509_verify::x509_cert::Certificate;
12+
use x509_cert::Certificate;
1313

1414
fn main() {
1515
let env = env::var("DEPLOY_ENV").unwrap_or_else(|_| "dev".to_string());

crates/ct_worker/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use std::sync::{LazyLock, OnceLock};
1111
use tlog_tiles::{LookupKey, SequenceMetadata};
1212
#[allow(clippy::wildcard_imports)]
1313
use worker::*;
14+
use x509_cert::Certificate;
1415
use x509_util::CertPool;
15-
use x509_verify::x509_cert::Certificate;
1616

1717
mod batcher_do;
1818
mod frontend_worker;

crates/mtc_api/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ sha2.workspace = true
2222
signed_note.workspace = true
2323
thiserror.workspace = true
2424
tlog_tiles.workspace = true
25-
x509-verify.workspace = true
25+
x509-cert.workspace = true
2626
x509_util.workspace = true

crates/mtc_api/src/lib.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
// Copyright (c) 2025 Cloudflare, Inc.
22
// Licensed under the BSD-3-Clause license found in the LICENSE file or at https://opensource.org/licenses/BSD-3-Clause
33

4+
mod relative_oid;
45
mod subtree_cosignature;
5-
use byteorder::{BigEndian, ReadBytesExt};
6+
pub use relative_oid::*;
67
pub use subtree_cosignature::*;
78

89
use anyhow::{anyhow, bail, ensure};
10+
use byteorder::{BigEndian, ReadBytesExt};
911
use der::{
10-
asn1::BitString,
12+
asn1::{BitString, OctetString},
1113
oid::{db::rfc5280, ObjectIdentifier},
1214
Decode, Encode, Sequence, ValueOrd,
1315
};
@@ -18,26 +20,24 @@ use sha2::{Digest, Sha256};
1820
use std::{
1921
collections::{BTreeSet, HashMap},
2022
io::Read,
23+
num::ParseIntError,
2124
};
2225
use thiserror::Error;
2326
use tlog_tiles::{
2427
Hash, LeafIndex, LogEntry, PathElem, PendingLogEntry, SequenceMetadata, TlogError,
2528
TlogTilesLogEntry, TlogTilesPendingLogEntry, UnixTimestamp,
2629
};
27-
use x509_util::CertPool;
28-
use x509_verify::{
29-
der::asn1::OctetString,
30-
x509_cert::{
31-
certificate::Version,
32-
ext::{
33-
pkix::{ExtendedKeyUsage, KeyUsage, KeyUsages},
34-
Extension,
35-
},
36-
name::RdnSequence,
37-
time::Validity,
38-
Certificate, TbsCertificate,
30+
use x509_cert::{
31+
certificate::Version,
32+
ext::{
33+
pkix::{ExtendedKeyUsage, KeyUsage, KeyUsages},
34+
Extension,
3935
},
36+
name::RdnSequence,
37+
time::Validity,
38+
Certificate, TbsCertificate,
4039
};
40+
use x509_util::CertPool;
4141

4242
// The OID to use for experimentaion. Eventually, we'll switch to "1.3.6.1.5.5.7.TBD1.TBD2"
4343
// as described in <https://www.ietf.org/archive/id/draft-davidben-tls-merkle-tree-certs-05.html#name-log-ids>.
@@ -133,8 +133,12 @@ pub enum MtcError {
133133
Der(#[from] der::Error),
134134
#[error(transparent)]
135135
IO(#[from] std::io::Error),
136+
#[error(transparent)]
137+
ParseInt(#[from] ParseIntError),
136138
#[error("empty chain")]
137139
EmptyChain,
140+
#[error("invalid relative OID")]
141+
InvalidRelativeOID,
138142
#[error("unknown entry type")]
139143
UnknownEntryType,
140144
}
@@ -488,7 +492,7 @@ pub fn validate_chain(
488492
mod tests {
489493
use der::asn1::UtcTime;
490494
use std::time::Duration;
491-
use x509_verify::x509_cert::{time::Time, Certificate};
495+
use x509_cert::{time::Time, Certificate};
492496

493497
use super::*;
494498

crates/mtc_api/src/relative_oid.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use crate::MtcError;
2+
use std::str::FromStr;
3+
4+
/// ASN.1 `RELATIVE OID`.
5+
///
6+
/// TODO upstream this to the `der` crate.
7+
pub struct RelativeOid {
8+
ber: Vec<u8>,
9+
}
10+
11+
impl RelativeOid {
12+
fn from_arcs(arcs: &[u32]) -> Result<Self, MtcError> {
13+
let mut ber = Vec::new();
14+
for arc in arcs {
15+
for j in (0..=4).rev() {
16+
#[allow(clippy::cast_possible_truncation)]
17+
let cur = (arc >> (j * 7)) as u8;
18+
19+
if cur != 0 || j == 0 {
20+
let mut to_write = cur & 0x7f; // lower 7 bits
21+
22+
if j != 0 {
23+
to_write |= 0x80;
24+
}
25+
ber.push(to_write);
26+
}
27+
}
28+
}
29+
if ber.len() > 255 {
30+
return Err(MtcError::InvalidRelativeOID);
31+
}
32+
Ok(Self { ber })
33+
}
34+
35+
/// Returns the DER-encoded content bytes.
36+
pub fn as_bytes(&self) -> &[u8] {
37+
&self.ber
38+
}
39+
}
40+
41+
impl FromStr for RelativeOid {
42+
type Err = MtcError;
43+
/// Parse the [`RelativeOid`] from a decimal-dotted string.
44+
fn from_str(s: &str) -> Result<Self, Self::Err> {
45+
let parts = s.split('.');
46+
let mut arcs = Vec::new();
47+
for part in parts {
48+
let i = part.parse::<u32>()?;
49+
arcs.push(i);
50+
}
51+
Self::from_arcs(&arcs)
52+
}
53+
}
54+
55+
#[cfg(test)]
56+
mod tests {
57+
58+
use der::{Any, Encode, Tag};
59+
60+
use super::*;
61+
62+
#[test]
63+
fn encode_decode() {
64+
let relative_oid = RelativeOid::from_str("13335.2").unwrap();
65+
let any = Any::new(Tag::RelativeOid, relative_oid.as_bytes()).unwrap();
66+
assert_eq!(any.to_der().unwrap(), b"\x0d\x03\xe8\x17\x02");
67+
}
68+
}

crates/mtc_worker/Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ mtc_api.workspace = true
3030
serde_json.workspace = true
3131
serde.workspace = true
3232
url.workspace = true
33-
x509-verify.workspace = true
33+
x509-cert.workspace = true
34+
der.workspace = true
3435

3536
[dev-dependencies]
3637
rand = { workspace = true, features = ["small_rng"] }
@@ -41,6 +42,7 @@ futures-executor.workspace = true
4142
[dependencies]
4243
base64.workspace = true
4344
config = { path = "./config", package = "mtc_worker_config" }
45+
der.workspace = true
4446
generic_log_worker.workspace = true
4547
ed25519-dalek.workspace = true
4648
futures-util.workspace = true
@@ -55,7 +57,7 @@ sha2.workspace = true
5557
signed_note.workspace = true
5658
tlog_tiles.workspace = true
5759
worker.workspace = true
58-
x509-verify.workspace = true
60+
x509-cert.workspace = true
5961
x509_util.workspace = true
6062
prometheus.workspace = true
6163
mtc_api.workspace = true

0 commit comments

Comments
 (0)