Skip to content

Commit

Permalink
adds x509 certificate support
Browse files Browse the repository at this point in the history
Signed-off-by: Arthur Gautier <[email protected]>
  • Loading branch information
baloo committed Nov 26, 2023
1 parent 7a73aad commit ccba914
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 0 deletions.
1 change: 1 addition & 0 deletions cryptoki-rustcrypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ signature = { version = "2.2.0", features = ["digest"] }
sha1 = { version = "0.10", features = ["oid"] }
sha2 = { version = "0.10", features = ["oid"] }
spki = "0.7.2"
x509-cert = "0.2.4"
thiserror = "1.0"

[dev-dependencies]
Expand Down
8 changes: 8 additions & 0 deletions cryptoki-rustcrypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ use cryptoki::{

pub mod ecdsa;
pub mod rsa;
pub mod x509;

pub trait SessionLike {
fn create_object(&self, template: &[Attribute]) -> Result<ObjectHandle>;
fn find_objects(&self, template: &[Attribute]) -> Result<Vec<ObjectHandle>>;
fn get_attributes(
&self,
Expand All @@ -22,6 +24,9 @@ pub trait SessionLike {
}

impl SessionLike for Session {
fn create_object(&self, template: &[Attribute]) -> Result<ObjectHandle> {
Session::create_object(self, template)
}
fn find_objects(&self, template: &[Attribute]) -> Result<Vec<ObjectHandle>> {
Session::find_objects(self, template)
}
Expand All @@ -38,6 +43,9 @@ impl SessionLike for Session {
}

impl<'s> SessionLike for &'s Session {
fn create_object(&self, template: &[Attribute]) -> Result<ObjectHandle> {
Session::create_object(self, template)
}
fn find_objects(&self, template: &[Attribute]) -> Result<Vec<ObjectHandle>> {
Session::find_objects(self, template)
}
Expand Down
95 changes: 95 additions & 0 deletions cryptoki-rustcrypto/src/x509.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2023 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0

use cryptoki::object::{Attribute, AttributeType, CertificateType, ObjectClass, ObjectHandle};
use thiserror::Error;
use x509_cert::{
certificate::{CertificateInner, Profile},
der::{Decode, Encode},
};

use crate::SessionLike;

#[derive(Debug, Error)]
pub enum Error {
#[error("Cryptoki error: {0}")]
Cryptoki(#[from] cryptoki::error::Error),

#[error("Missing attribute: {0}")]
MissingAttribute(AttributeType),

#[error(transparent)]
Der(#[from] x509_cert::der::Error),

#[error("No such certificate found")]
MissingCert,
}

pub trait CertPkcs11 {
fn pkcs11_store<S: SessionLike, T: Into<Vec<Attribute>>>(
&self,
session: &S,
base_template: T,
) -> Result<ObjectHandle, Error>;

fn pkcs11_load<S: SessionLike, T: Into<Vec<Attribute>>>(
session: &S,
template: T,
) -> Result<Self, Error>
where
Self: Sized;
}

impl<P> CertPkcs11 for CertificateInner<P>
where
P: Profile,
{
fn pkcs11_store<S: SessionLike, T: Into<Vec<Attribute>>>(
&self,
session: &S,
base_template: T,
) -> Result<ObjectHandle, Error> {
let mut template = base_template.into();
template.push(Attribute::Class(ObjectClass::CERTIFICATE));
template.push(Attribute::CertificateType(CertificateType::X_509));
template.push(Attribute::Token(true));
template.push(Attribute::Value(self.to_der()?));
if !self.tbs_certificate.subject.is_empty() {
template.push(Attribute::Subject(self.tbs_certificate.subject.to_der()?));
}

Ok(session.create_object(&template)?)
}

fn pkcs11_load<S: SessionLike, T: Into<Vec<Attribute>>>(
session: &S,
template: T,
) -> Result<Self, Error> {
let mut template = template.into();
template.push(Attribute::Class(ObjectClass::CERTIFICATE));
template.push(Attribute::CertificateType(CertificateType::X_509));

let certs = session.find_objects(&template)?;
if let Some(cert) = certs.first() {
let attributes = session.get_attributes(*cert, &[AttributeType::Value])?;

let mut value = None;
for attribute in attributes {
match attribute {
Attribute::Value(v) if value.is_none() => {
value = Some(v);
}
_ => {}
}
}

let value = value.ok_or(Error::MissingAttribute(AttributeType::Value))?;

let cert = Self::from_der(&value)?;

Ok(cert)
} else {
Err(Error::MissingCert)
}
}
}
Binary file not shown.
41 changes: 41 additions & 0 deletions cryptoki-rustcrypto/tests/x509.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2023 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0

mod common;

use crate::common::USER_PIN;
use common::init_pins;
use cryptoki::{object::Attribute, session::UserType, types::AuthPin};
use cryptoki_rustcrypto::x509::CertPkcs11;
use der::Decode;
use serial_test::serial;
use testresult::TestResult;
use x509_cert::Certificate;

const VERISIGN_CERT: &[u8] = include_bytes!("./15b05c4865410c6b3ff76a4e8f3d87276756bd0c.der");

#[test]
#[serial]
fn test_x509() -> TestResult {
let (pkcs11, slot) = init_pins();

// open a session
let session = pkcs11.open_rw_session(slot)?;

// log in the session
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;

let cert = Certificate::from_der(VERISIGN_CERT).expect("read certificate from der");

let base_template = vec![Attribute::Label(b"demo-cert".to_vec())];

cert.pkcs11_store(&session, base_template.clone())
.expect("Store cert with the PKCS11 provider");

let new = Certificate::pkcs11_load(&session, base_template)
.expect("Lookup cert from PKCS11 provider");

assert_eq!(cert, new);

Ok(())
}

0 comments on commit ccba914

Please sign in to comment.