commit 59a0636f6a7f4f87f3f13c35e4441c57687c0b17
parent 27aae35b0e4fde7f70b8c9d97ee8fcd572ca14d5
Author: Dylan ross <dylan.ssor@gmail.com>
Date: Mon, 12 Jun 2023 12:59:05 -0700
includes the cert serial number in the ValidationInfo output (#263)
creates CertInfo struct containing subject and serial_number of cert.
Co-authored-by: Dylan Ross <dyross@adobe.com>
Diffstat:
4 files changed, 74 insertions(+), 13 deletions(-)
diff --git a/sdk/src/claim.rs b/sdk/src/claim.rs
@@ -981,7 +981,7 @@ impl Claim {
}
}
- /// Return the signing date and time for this claim, if there is one.
+ /// Return the signing issuer for this claim, if there is one.
pub fn signing_issuer(&self) -> Option<String> {
if let Some(validation_data) = self.signature_info() {
validation_data.issuer_org
@@ -990,6 +990,13 @@ impl Claim {
}
}
+ /// Return the cert's serial number, if there is one.
+ pub fn signing_cert_serial(&self) -> Option<String> {
+ self.signature_info()
+ .and_then(|validation_info| validation_info.cert_serial_number)
+ .map(|serial| serial.to_string())
+ }
+
/// Return information about the signature
pub fn signature_info(&self) -> Option<ValidationInfo> {
let sig = self.signature_val();
diff --git a/sdk/src/cose_validator.rs b/sdk/src/cose_validator.rs
@@ -20,6 +20,7 @@ use coset::{
};
use x509_parser::{
der_parser::{ber::parse_ber_sequence, oid},
+ num_bigint::BigUint,
oid_registry::Oid,
prelude::*,
};
@@ -708,6 +709,14 @@ fn get_timestamp_info(sign1: &coset::CoseSign1, data: &[u8]) -> Result<TstInfo>
Err(Error::NotFound)
}
+/// A wrapper containing information of the signing cert.
+pub(crate) struct CertInfo {
+ /// The name of the identity the certificate is issued to.
+ pub subject: String,
+ /// The serial number of the cert. Will be unique to the CA.
+ pub serial_number: BigUint,
+}
+
fn extract_subject_from_cert(cert: &X509Certificate) -> Result<String> {
cert.subject()
.iter_organization()
@@ -718,6 +727,11 @@ fn extract_subject_from_cert(cert: &X509Certificate) -> Result<String> {
.map_err(|_e| Error::CoseX5ChainMissing)
}
+/// Returns the unique serial number from the provided cert.
+fn extract_serial_from_cert(cert: &X509Certificate) -> BigUint {
+ cert.serial.clone()
+}
+
/// Asynchronously validate a COSE_SIGN1 byte vector and verify against expected data
/// cose_bytes - byte array containing the raw COSE_SIGN1 data
/// data: data that was used to create the cose_bytes, these must match
@@ -808,8 +822,13 @@ pub async fn verify_cose_async(
sign1.payload.as_ref().unwrap_or(&vec![]),
); // get "to be signed" bytes
- if let Ok(issuer) = validate_with_cert_async(alg, &sign1.signature, &tbs, &der_bytes).await {
- result.issuer_org = Some(issuer);
+ if let Ok(CertInfo {
+ subject,
+ serial_number,
+ }) = validate_with_cert_async(alg, &sign1.signature, &tbs, &der_bytes).await
+ {
+ result.issuer_org = Some(subject);
+ result.cert_serial_number = Some(serial_number);
result.validated = true;
result.alg = Some(alg);
@@ -832,6 +851,7 @@ pub fn get_signing_info(
let mut date = None;
let mut issuer_org = None;
let mut alg: Option<SigningAlg> = None;
+ let mut cert_serial_number = None;
let sign1 = get_cose_sign1(cose_bytes, data, validation_log).and_then(|sign1| {
// get the public key der
@@ -840,6 +860,7 @@ pub fn get_signing_info(
let _ = X509Certificate::from_der(&der_bytes).map(|(_rem, signcert)| {
date = get_signing_time(&sign1, data);
issuer_org = extract_subject_from_cert(&signcert).ok();
+ cert_serial_number = Some(extract_serial_from_cert(&signcert));
if let Ok(a) = get_signing_alg(&sign1) {
alg = Some(a);
}
@@ -858,6 +879,7 @@ pub fn get_signing_info(
alg,
validated: false,
cert_chain: Vec::new(),
+ cert_serial_number,
}
}
#[cfg(not(target_arch = "wasm32"))]
@@ -876,6 +898,7 @@ pub fn get_signing_info(
alg,
validated: false,
cert_chain: certs,
+ cert_serial_number,
}
}
}
@@ -962,8 +985,13 @@ pub fn verify_cose(
// Check the signature, which needs to have the same `additional_data` provided, by
// providing a closure that can do the verify operation.
sign1.verify_signature(additional_data, |sig, verify_data| -> Result<()> {
- if let Ok(issuer) = validate_with_cert(validator, sig, verify_data, der_bytes) {
- result.issuer_org = Some(issuer);
+ if let Ok(CertInfo {
+ subject,
+ serial_number,
+ }) = validate_with_cert(validator, sig, verify_data, der_bytes)
+ {
+ result.issuer_org = Some(subject);
+ result.cert_serial_number = Some(serial_number);
result.validated = true;
result.alg = Some(alg);
@@ -997,7 +1025,7 @@ fn validate_with_cert(
sig: &[u8],
data: &[u8],
der_bytes: &[u8],
-) -> Result<String> {
+) -> Result<CertInfo> {
// get the cert in der format
let (_rem, signcert) =
X509Certificate::from_der(der_bytes).map_err(|_err| Error::CoseInvalidCert)?;
@@ -1005,7 +1033,10 @@ fn validate_with_cert(
let pk_der = pk.raw;
if validator.validate(sig, data, pk_der)? {
- Ok(extract_subject_from_cert(&signcert).unwrap_or_default())
+ Ok(CertInfo {
+ subject: extract_subject_from_cert(&signcert).unwrap_or_default(),
+ serial_number: extract_serial_from_cert(&signcert),
+ })
} else {
Err(Error::CoseSignature)
}
@@ -1017,14 +1048,17 @@ async fn validate_with_cert_async(
sig: &[u8],
data: &[u8],
der_bytes: &[u8],
-) -> Result<String> {
+) -> Result<CertInfo> {
let (_rem, signcert) =
X509Certificate::from_der(der_bytes).map_err(|_err| Error::CoseMissingKey)?;
let pk = signcert.public_key();
let pk_der = pk.raw;
if validate_async(signing_alg, sig, data, pk_der).await? {
- Ok(extract_subject_from_cert(&signcert).unwrap_or_default())
+ Ok(CertInfo {
+ subject: extract_subject_from_cert(&signcert).unwrap_or_default(),
+ serial_number: extract_serial_from_cert(&signcert),
+ })
} else {
Err(Error::CoseSignature)
}
@@ -1036,7 +1070,7 @@ async fn validate_with_cert_async(
sig: &[u8],
data: &[u8],
der_bytes: &[u8],
-) -> Result<String> {
+) -> Result<CertInfo> {
// get the cert in der format
let (_rem, signcert) =
X509Certificate::from_der(der_bytes).map_err(|_err| Error::CoseInvalidCert)?;
@@ -1046,7 +1080,10 @@ async fn validate_with_cert_async(
let validator = get_validator(signing_alg);
if validator.validate(sig, data, pk_der)? {
- Ok(extract_subject_from_cert(&signcert).unwrap_or_default())
+ Ok(CertInfo {
+ subject: extract_subject_from_cert(&signcert).unwrap_or_default(),
+ serial_number: extract_serial_from_cert(&signcert),
+ })
} else {
Err(Error::CoseSignature)
}
diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs
@@ -451,10 +451,16 @@ impl Manifest {
}
/// Sets the signature information for the report
- fn set_signature(&mut self, issuer: Option<&String>, time: Option<&String>) -> &mut Self {
+ fn set_signature(
+ &mut self,
+ issuer: Option<&String>,
+ time: Option<&String>,
+ cert_serial: Option<&String>,
+ ) -> &mut Self {
self.signature_info = Some(SignatureInfo {
issuer: issuer.cloned(),
time: time.cloned(),
+ cert_serial_number: cert_serial.cloned(),
});
self
}
@@ -675,7 +681,11 @@ impl Manifest {
"added signature issuer={:?} time={:?}",
issuer, signing_time
);
- manifest.set_signature(issuer.as_ref(), signing_time.as_ref());
+ manifest.set_signature(
+ issuer.as_ref(),
+ signing_time.as_ref(),
+ claim.signing_cert_serial().as_ref(),
+ );
}
Ok(manifest)
@@ -1158,6 +1168,11 @@ pub struct SignatureInfo {
/// human readable issuing authority for this signature
#[serde(skip_serializing_if = "Option::is_none")]
issuer: Option<String>,
+
+ /// The serial number of the certificate
+ #[serde(skip_serializing_if = "Option::is_none")]
+ cert_serial_number: Option<String>,
+
/// the time the signature was created
#[serde(skip_serializing_if = "Option::is_none")]
time: Option<String>,
diff --git a/sdk/src/validator.rs b/sdk/src/validator.rs
@@ -12,6 +12,7 @@
// each license.
use chrono::{DateTime, Utc};
+use x509_parser::num_bigint::BigUint;
#[cfg(feature = "openssl_sign")]
use crate::openssl::{EcValidator, EdValidator, RsaValidator};
@@ -21,6 +22,7 @@ use crate::{Result, SigningAlg};
pub struct ValidationInfo {
pub alg: Option<SigningAlg>, // validation algorithm
pub date: Option<DateTime<Utc>>,
+ pub cert_serial_number: Option<BigUint>,
pub issuer_org: Option<String>,
pub validated: bool, // claim signature is valid
pub cert_chain: Vec<u8>, // certificate chain used to validate signature