mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
rust: Add library for pv tools
Add a `pv` crate that bundles useful functions and structs for creating requests like `Attestation`, `Add Secret`, or even `Boot` a.k.a. Secure Execution Image. Note pv includes a subcrate `openssl_extensions` that (temporarily) bundles some needed `openssl-rust` functionalities that are not upstream yet. The plan is to remove these, when they become upstream. The pv crate has multiple features: * request - code to generate requests * uvsecret - code to access the UV-secret api with request enabled also generating requests is possible Signed-off-by: Steffen Eiden <seiden@linux.ibm.com> Acked-by: Jan Höppner <hoeppner@linux.ibm.com> Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
e6add997eb
commit
c6f621d0dc
@@ -0,0 +1,120 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
|
||||
use libc::c_int;
|
||||
use openssl::x509::{X509CrlRef, X509Ref};
|
||||
|
||||
mod ffi {
|
||||
extern "C" {
|
||||
pub fn X509_check_akid(
|
||||
issuer: *const openssl_sys::X509,
|
||||
akid: *const openssl_sys::AUTHORITY_KEYID,
|
||||
) -> ::libc::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = openssl_sys::AUTHORITY_KEYID;
|
||||
fn drop = openssl_sys::AUTHORITY_KEYID_free;
|
||||
|
||||
/// An `Authority Key Identifier`.
|
||||
pub struct Akid;
|
||||
/// Reference to `Akid`
|
||||
pub struct AkidRef;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub struct AkidCheckResult(c_int);
|
||||
|
||||
impl fmt::Debug for AkidCheckResult {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt.debug_struct("AkidCheckResult")
|
||||
.field("code", &self.0)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl AkidCheckResult {
|
||||
/// Creates an `AkidCheckResult` from a raw error number.
|
||||
unsafe fn from_raw(err: c_int) -> AkidCheckResult {
|
||||
AkidCheckResult(err)
|
||||
}
|
||||
|
||||
pub const OK: AkidCheckResult = AkidCheckResult(openssl_sys::X509_V_OK);
|
||||
pub const ERR_AKID_ISSUER_SERIAL_MISMATCH: AkidCheckResult =
|
||||
AkidCheckResult(openssl_sys::X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH);
|
||||
pub const ERR_AKID_SKID_MISMATCH: AkidCheckResult =
|
||||
AkidCheckResult(openssl_sys::X509_V_ERR_AKID_SKID_MISMATCH);
|
||||
}
|
||||
|
||||
impl AkidRef {
|
||||
///Check if the `Akid` matches the issuer
|
||||
///
|
||||
pub fn check(&self, issuer: &X509Ref) -> AkidCheckResult {
|
||||
unsafe {
|
||||
let res = ffi::X509_check_akid(issuer.as_ptr(), self.as_ptr());
|
||||
AkidCheckResult::from_raw(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AkidExtension {
|
||||
fn akid(&self) -> Option<Akid>;
|
||||
}
|
||||
|
||||
impl AkidExtension for X509Ref {
|
||||
fn akid(&self) -> Option<Akid> {
|
||||
unsafe {
|
||||
let ptr = openssl_sys::X509_get_ext_d2i(
|
||||
self.as_ptr(),
|
||||
openssl_sys::NID_authority_key_identifier,
|
||||
std::ptr::null_mut(),
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Akid::from_ptr(ptr as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AkidExtension for X509CrlRef {
|
||||
fn akid(&self) -> Option<Akid> {
|
||||
unsafe {
|
||||
let ptr = openssl_sys::X509_CRL_get_ext_d2i(
|
||||
self.as_ptr(),
|
||||
openssl_sys::NID_authority_key_identifier,
|
||||
std::ptr::null_mut(),
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Akid::from_ptr(ptr as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::test_utils::load_gen_cert;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn akid() {
|
||||
let cert = load_gen_cert("ibm.crt");
|
||||
let ca = load_gen_cert("root_ca.crt");
|
||||
|
||||
let akid = cert.akid().unwrap();
|
||||
let res = akid.check(&ca);
|
||||
assert_eq!(res, AkidCheckResult::OK);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
pub use crate::stackable_crl::*;
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use openssl::{
|
||||
error::ErrorStack,
|
||||
stack::{Stack, StackRef},
|
||||
x509::{
|
||||
store::{X509StoreBuilderRef, X509StoreRef},
|
||||
X509CrlRef, X509NameRef, X509Ref, X509StoreContextRef, X509,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn opt_to_ptr<T: ForeignTypeRef>(o: Option<&T>) -> *mut T::CType {
|
||||
match o {
|
||||
None => std::ptr::null_mut(),
|
||||
Some(p) => p.as_ptr(),
|
||||
}
|
||||
}
|
||||
|
||||
mod ffi {
|
||||
extern "C" {
|
||||
#[cfg(ossl110)]
|
||||
pub fn X509_STORE_CTX_get1_crls(
|
||||
ctx: *mut openssl_sys::X509_STORE_CTX,
|
||||
nm: *mut openssl_sys::X509_NAME,
|
||||
) -> *mut openssl_sys::stack_st_X509_CRL;
|
||||
pub fn X509_STORE_add_crl(
|
||||
xs: *mut openssl_sys::X509_STORE,
|
||||
x: *mut openssl_sys::X509_CRL,
|
||||
) -> libc::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait X509StoreExtension {
|
||||
fn add_crl(&mut self, crl: &X509CrlRef) -> Result<(), ErrorStack>;
|
||||
}
|
||||
|
||||
impl X509StoreExtension for X509StoreBuilderRef {
|
||||
fn add_crl(&mut self, crl: &X509CrlRef) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
{
|
||||
let r = ffi::X509_STORE_add_crl(self.as_ptr(), crl.as_ptr());
|
||||
if r <= 0 {
|
||||
Err(ErrorStack::get())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait X509StoreContextExtension {
|
||||
fn init_opt<F, T>(
|
||||
&mut self,
|
||||
trust: &X509StoreRef,
|
||||
cert: Option<&X509Ref>,
|
||||
cert_chain: Option<&StackRef<X509>>,
|
||||
with_context: F,
|
||||
) -> Result<T, ErrorStack>
|
||||
where
|
||||
F: FnOnce(&mut X509StoreContextRef) -> std::result::Result<T, ErrorStack>;
|
||||
fn crls(
|
||||
&mut self,
|
||||
subj: &X509NameRef,
|
||||
) -> std::result::Result<Stack<StackableX509Crl>, ErrorStack>;
|
||||
}
|
||||
|
||||
impl X509StoreContextExtension for X509StoreContextRef {
|
||||
fn init_opt<F, T>(
|
||||
&mut self,
|
||||
trust: &X509StoreRef,
|
||||
cert: Option<&X509Ref>,
|
||||
cert_chain: Option<&StackRef<X509>>,
|
||||
with_context: F,
|
||||
) -> Result<T, ErrorStack>
|
||||
where
|
||||
F: FnOnce(&mut X509StoreContextRef) -> std::result::Result<T, ErrorStack>,
|
||||
{
|
||||
struct Cleanup<'a>(&'a mut X509StoreContextRef);
|
||||
|
||||
impl<'a> Drop for Cleanup<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
openssl_sys::X509_STORE_CTX_cleanup(self.0.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
{
|
||||
let r = openssl_sys::X509_STORE_CTX_init(
|
||||
self.as_ptr(),
|
||||
trust.as_ptr(),
|
||||
opt_to_ptr(cert),
|
||||
opt_to_ptr(cert_chain),
|
||||
);
|
||||
if r <= 0 {
|
||||
Err(ErrorStack::get())
|
||||
} else {
|
||||
Ok(r)
|
||||
}
|
||||
}?;
|
||||
}
|
||||
let cleanup = Cleanup(self);
|
||||
with_context(cleanup.0)
|
||||
}
|
||||
/// Get all Certificate Revocation Lists with the subject currently stored
|
||||
#[cfg(ossl110)]
|
||||
fn crls(
|
||||
&mut self,
|
||||
subj: &X509NameRef,
|
||||
) -> std::result::Result<Stack<StackableX509Crl>, ErrorStack> {
|
||||
unsafe {
|
||||
{
|
||||
let r = ffi::X509_STORE_CTX_get1_crls(self.as_ptr(), subj.as_ptr());
|
||||
if r.is_null() {
|
||||
Err(ErrorStack::get())
|
||||
} else {
|
||||
Ok(Stack::from_ptr(r))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
#![doc(hidden)]
|
||||
|
||||
/// Extensions to the rust-openssl crate, that are not upstream yet
|
||||
/// Upstreaming mostly work in progress
|
||||
pub mod akid;
|
||||
pub mod crl;
|
||||
mod stackable_crl;
|
||||
|
||||
/// Test if two CRLs are equal.
|
||||
///
|
||||
/// relates to X509_CRL_match
|
||||
/// (Upstream is missing that functionality)
|
||||
pub fn x509_crl_eq(a: &openssl::x509::X509CrlRef, b: &openssl::x509::X509CrlRef) -> bool {
|
||||
use foreign_types::ForeignTypeRef;
|
||||
let cmp = unsafe { openssl_sys::X509_CRL_match(a.as_ptr(), b.as_ptr()) };
|
||||
cmp == 0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod test_utils {
|
||||
include!("../../src/test_utils.rs");
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use std::{marker::PhantomData, ptr};
|
||||
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use libc::c_int;
|
||||
use openssl::{
|
||||
error::ErrorStack,
|
||||
stack::Stackable,
|
||||
x509::{X509Crl, X509CrlRef},
|
||||
};
|
||||
use openssl_sys::BIO_new_mem_buf;
|
||||
|
||||
pub struct StackableX509Crl(*mut openssl_sys::X509_CRL);
|
||||
|
||||
impl ForeignType for StackableX509Crl {
|
||||
type CType = openssl_sys::X509_CRL;
|
||||
type Ref = X509CrlRef;
|
||||
unsafe fn from_ptr(ptr: *mut openssl_sys::X509_CRL) -> StackableX509Crl {
|
||||
StackableX509Crl(ptr)
|
||||
}
|
||||
fn as_ptr(&self) -> *mut openssl_sys::X509_CRL {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl Drop for StackableX509Crl {
|
||||
fn drop(&mut self) {
|
||||
unsafe { (openssl_sys::X509_CRL_free)(self.0) }
|
||||
}
|
||||
}
|
||||
impl ::std::ops::Deref for StackableX509Crl {
|
||||
type Target = X509CrlRef;
|
||||
fn deref(&self) -> &X509CrlRef {
|
||||
unsafe { ForeignTypeRef::from_ptr(self.0) }
|
||||
}
|
||||
}
|
||||
impl ::std::ops::DerefMut for StackableX509Crl {
|
||||
fn deref_mut(&mut self) -> &mut X509CrlRef {
|
||||
unsafe { ForeignTypeRef::from_ptr_mut(self.0) }
|
||||
}
|
||||
}
|
||||
#[allow(clippy::explicit_auto_deref)]
|
||||
impl ::std::borrow::Borrow<X509CrlRef> for StackableX509Crl {
|
||||
fn borrow(&self) -> &X509CrlRef {
|
||||
&**self
|
||||
}
|
||||
}
|
||||
#[allow(clippy::explicit_auto_deref)]
|
||||
impl ::std::convert::AsRef<X509CrlRef> for StackableX509Crl {
|
||||
fn as_ref(&self) -> &X509CrlRef {
|
||||
&**self
|
||||
}
|
||||
}
|
||||
|
||||
impl Stackable for StackableX509Crl {
|
||||
type StackType = openssl_sys::stack_st_X509_CRL;
|
||||
}
|
||||
|
||||
pub struct MemBioSlice<'a>(*mut openssl_sys::BIO, PhantomData<&'a [u8]>);
|
||||
impl<'a> Drop for MemBioSlice<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
openssl_sys::BIO_free_all(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MemBioSlice<'a> {
|
||||
pub fn new(buf: &'a [u8]) -> Result<MemBioSlice<'a>, ErrorStack> {
|
||||
openssl_sys::init();
|
||||
|
||||
assert!(buf.len() <= c_int::max_value() as usize);
|
||||
let bio = unsafe {
|
||||
{
|
||||
let r = BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int);
|
||||
if r.is_null() {
|
||||
Err(ErrorStack::get())
|
||||
} else {
|
||||
Ok(r)
|
||||
}
|
||||
}?
|
||||
};
|
||||
|
||||
Ok(MemBioSlice(bio, PhantomData))
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut openssl_sys::BIO {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl StackableX509Crl {
|
||||
pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509Crl>, ErrorStack> {
|
||||
unsafe {
|
||||
openssl_sys::init();
|
||||
let bio = MemBioSlice::new(pem)?;
|
||||
|
||||
let mut crls = vec![];
|
||||
loop {
|
||||
let r = openssl_sys::PEM_read_bio_X509_CRL(
|
||||
bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
if r.is_null() {
|
||||
let err = openssl_sys::ERR_peek_last_error();
|
||||
if openssl_sys::ERR_GET_LIB(err) as c_int == openssl_sys::ERR_LIB_PEM
|
||||
&& openssl_sys::ERR_GET_REASON(err) == openssl_sys::PEM_R_NO_START_LINE
|
||||
{
|
||||
openssl_sys::ERR_clear_error();
|
||||
break;
|
||||
}
|
||||
|
||||
return Err(ErrorStack::get());
|
||||
} else {
|
||||
crls.push(X509Crl::from_ptr(r));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(crls)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<X509Crl> for StackableX509Crl {
|
||||
fn from(value: X509Crl) -> Self {
|
||||
unsafe {
|
||||
openssl_sys::X509_CRL_up_ref(value.as_ptr());
|
||||
StackableX509Crl::from_ptr(value.as_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<StackableX509Crl> for X509Crl {
|
||||
fn from(value: StackableX509Crl) -> Self {
|
||||
unsafe {
|
||||
openssl_sys::X509_CRL_up_ref(value.as_ptr());
|
||||
X509Crl::from_ptr(value.as_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user