Skip to content

Commit

Permalink
add primitive crate for x509 certificate verification
Browse files Browse the repository at this point in the history
  • Loading branch information
vedhavyas committed Mar 22, 2024
1 parent 5d7e296 commit 3187043
Show file tree
Hide file tree
Showing 5 changed files with 394 additions and 16 deletions.
149 changes: 133 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions domains/primitives/certificate-registry/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[package]
name = "sp-certificate-registry"
version = "0.1.0"
authors = ["Vedhavyas Singareddi <[email protected]>"]
edition = "2021"
license = "Apache-2.0"
homepage = "https://subspace.network"
repository = "https://github.com/subspace/subspace"
description = "Primitives for X509 Cerificate verification"
include = [
"/src",
"/Cargo.toml",
"/README.md",
]

[dependencies]
codec = { package = "parity-scale-codec", version = "3.6.5", default-features = false, features = ["derive"] }
scale-info = { version = "2.7.0", default-features = false, features = ["derive"] }
sc-executor = { version = "0.10.0-dev", git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8", default-features = false, optional = true }
sp-api = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8" }
sp-blockchain = { version = "4.0.0-dev", git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8", optional = true }
sp-core = { version = "21.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8" }
sp-externalities = { version = "0.19.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8" }
sp-runtime = { version = "24.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8" }
sp-runtime-interface = { version = "17.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "d6b500960579d73c43fc4ef550b703acfa61c4c8" }
subspace-runtime-primitives = { version = "0.1.0", default-features = false, path = "../../../crates/subspace-runtime-primitives" }
time = {version = "0.3.34", optional = true }
x509-parser = { version = "0.16.0", features = ["verify"], optional = true }

[features]
default = ["std"]
std = [
"codec/std",
"scale-info/std",
"sc-executor",
"sp-api/std",
"sp-blockchain",
"sp-core/std",
"sp-externalities/std",
"sp-runtime/std",
"sp-runtime-interface/std",
"subspace-runtime-primitives/std",
"time",
"x509-parser"
]

runtime-benchmarks = []
64 changes: 64 additions & 0 deletions domains/primitives/certificate-registry/src/host_functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crate::{Validity, X509CertificateVerificationRequest, X509CertificateVerificationResponse};
use sp_core::U256;
use std::sync::Arc;
use std::time::{Duration, UNIX_EPOCH};
use time::OffsetDateTime;
use x509_parser::certificate::X509Certificate;
use x509_parser::prelude::{FromDer, SubjectPublicKeyInfo};

/// Host function trait for Certificate registration
pub trait HostFunctions: Send + Sync {
fn verify_x509_certificate(
&self,
req: X509CertificateVerificationRequest,
) -> Option<X509CertificateVerificationResponse>;
}

sp_externalities::decl_extension! {
pub struct HostFunctionExtension(Arc<dyn HostFunctions>);
}

impl HostFunctionExtension {
/// Create a new instance of [`HostFunctionExtension`].
#[allow(dead_code)]
pub fn new(inner: Arc<dyn HostFunctions>) -> Self {
Self(inner)
}
}

/// Implementation of host functions for Certificate registry.
#[derive(Default)]
pub struct HostFunctionsImpl;

impl HostFunctions for HostFunctionsImpl {
fn verify_x509_certificate(
&self,
req: X509CertificateVerificationRequest,
) -> Option<X509CertificateVerificationResponse> {
let (cert_bytes, maybe_issuer_pki, block_time) = req.destruct();
let (_, cert) = X509Certificate::from_der(cert_bytes.as_ref()).ok()?;
if let Some(encoded_issuer_pki) = maybe_issuer_pki {
let (_, pki) = SubjectPublicKeyInfo::from_der(encoded_issuer_pki.as_ref()).ok()?;
// verify the certificate signature using issuer pki
cert.verify_signature(Some(&pki)).ok()?
} else {
// verify signature using subject pki as an issuer
cert.verify_signature(None).ok()?;
};

// block time is in milliseconds since unix epoch
let block_time = OffsetDateTime::from(UNIX_EPOCH + Duration::from_millis(block_time));

// check certificate validity
cert.validity()
.is_valid_at(block_time.into())
.then_some(())?;

Some(X509CertificateVerificationResponse {
issuer_serial: U256::from_big_endian(&cert.serial.to_bytes_be()),
subject: cert.subject.as_raw().to_vec().into(),
subject_pki: cert.subject_pki.raw.to_vec().into(),
validity: Validity::from(cert.validity().clone()),
})
}
}
Loading

0 comments on commit 3187043

Please sign in to comment.