From ccba914c5078d8a9188d643306f88cd238f745e2 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sat, 25 Nov 2023 22:46:59 -0800 Subject: [PATCH] adds x509 certificate support Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/Cargo.toml | 1 + cryptoki-rustcrypto/src/lib.rs | 8 ++ cryptoki-rustcrypto/src/x509.rs | 95 ++++++++++++++++++ ...b05c4865410c6b3ff76a4e8f3d87276756bd0c.der | Bin 0 -> 1582 bytes cryptoki-rustcrypto/tests/x509.rs | 41 ++++++++ 5 files changed, 145 insertions(+) create mode 100644 cryptoki-rustcrypto/src/x509.rs create mode 100644 cryptoki-rustcrypto/tests/15b05c4865410c6b3ff76a4e8f3d87276756bd0c.der create mode 100644 cryptoki-rustcrypto/tests/x509.rs diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml index 9e79dd8b..ba6c5855 100644 --- a/cryptoki-rustcrypto/Cargo.toml +++ b/cryptoki-rustcrypto/Cargo.toml @@ -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] diff --git a/cryptoki-rustcrypto/src/lib.rs b/cryptoki-rustcrypto/src/lib.rs index cda9612a..68b1ccc3 100644 --- a/cryptoki-rustcrypto/src/lib.rs +++ b/cryptoki-rustcrypto/src/lib.rs @@ -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; fn find_objects(&self, template: &[Attribute]) -> Result>; fn get_attributes( &self, @@ -22,6 +24,9 @@ pub trait SessionLike { } impl SessionLike for Session { + fn create_object(&self, template: &[Attribute]) -> Result { + Session::create_object(self, template) + } fn find_objects(&self, template: &[Attribute]) -> Result> { Session::find_objects(self, template) } @@ -38,6 +43,9 @@ impl SessionLike for Session { } impl<'s> SessionLike for &'s Session { + fn create_object(&self, template: &[Attribute]) -> Result { + Session::create_object(self, template) + } fn find_objects(&self, template: &[Attribute]) -> Result> { Session::find_objects(self, template) } diff --git a/cryptoki-rustcrypto/src/x509.rs b/cryptoki-rustcrypto/src/x509.rs new file mode 100644 index 00000000..76461c8a --- /dev/null +++ b/cryptoki-rustcrypto/src/x509.rs @@ -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>>( + &self, + session: &S, + base_template: T, + ) -> Result; + + fn pkcs11_load>>( + session: &S, + template: T, + ) -> Result + where + Self: Sized; +} + +impl

CertPkcs11 for CertificateInner

+where + P: Profile, +{ + fn pkcs11_store>>( + &self, + session: &S, + base_template: T, + ) -> Result { + 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>>( + session: &S, + template: T, + ) -> Result { + 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) + } + } +} diff --git a/cryptoki-rustcrypto/tests/15b05c4865410c6b3ff76a4e8f3d87276756bd0c.der b/cryptoki-rustcrypto/tests/15b05c4865410c6b3ff76a4e8f3d87276756bd0c.der new file mode 100644 index 0000000000000000000000000000000000000000..d94106f82a6e99fe50725261735e5eb377421147 GIT binary patch literal 1582 zcmb_cYfuwc6wYoo8$m%Z7?9`6LjxhunHlBxDv9sS&U$<7&T*c zlv3*yDRv^-YEdgy>w|)%YHcaDOb4e@TdUYo@mWCdiETH;IAuEi>;AcW&-?rCIR{L5 z7?=c;EPNC}QMVOEP4CD$Z(i`p^1t-Bt1lE>aHlYHviXq=^dCn>?-(}e_3l94d_<$1brWhhC7B2pQn zjLC!bE&mtTSrB6ftH{(ar3Qj79tERfiRCO?W{8c5FdB{WRUCx|jzYPbE{$NyR0PKi z31k$^u%ngz2W^U;)iC-|a4H>_qaF zmCA3s#g_)vv+?-vVZ*%8;5`SoJehz0*dLY`KUMMQQh0+Z9cSZd&#-Zsuh=#y~5W_kwb_$$W|lQXgXR; zkL|QohEbU0k&KaYME{cF*_<$GrBRB5oKysq)e-na|#HxRp^cd0nL@@5wQT|Uxng3>BXCpq_O{Kj^wwDe&+>f>)5We0Cm_J44#K=ZT;;K@ zOSAv%)w^HxgVTe=n5XEGNX~!k>f>ey;Z5-TGvFD&)@p1SnQUDYBB*PaEw!ds&S`&o zUvc~M_qJ5jrY%oU)vO*ob>M#629Lh@ep%4up5P|9CG_#@?TuRJCPRd}j86?Sa|YD8 zOHb^r3;$Z4)^qQTfz6+7z@$P}KC(NyaQ^$l!Li@DSDh=7Ha 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(()) +}