commit 2cb7fd87f7dd223bfcf5760a556abad78f4a93a0
parent 40fc8df617d99f7ffb76e61333856dcbafe1f882
Author: Eric Scouten <scouten@adobe.com>
Date: Tue, 19 Jul 2022 09:09:27 -0700
(MINOR) Introduce a new `SigningAlg` enum (#76)
Diffstat:
24 files changed, 650 insertions(+), 505 deletions(-)
diff --git a/make_test_images/src/make_test_images.rs b/make_test_images/src/make_test_images.rs
@@ -15,6 +15,7 @@
use c2pa::{
assertions::{c2pa_action, Action, Actions, CreativeWork, SchemaDotOrgPerson},
create_signer, jumbf_io, Error, Ingredient, IngredientOptions, Manifest, ManifestStore, Signer,
+ SigningAlg,
};
use anyhow::{Context, Result};
@@ -36,6 +37,7 @@ fn get_signer_with_alg(alg: &str) -> c2pa::Result<Box<dyn Signer>> {
signcert_path.push(format!("../sdk/tests/fixtures/certs/{}.pub", alg));
let mut pkey_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
pkey_path.push(format!("../sdk/tests/fixtures/certs/{}.pem", alg));
+ let alg: SigningAlg = alg.parse().map_err(|_| c2pa::Error::UnsupportedType)?;
create_signer::from_files(signcert_path, pkey_path, alg, None)
}
diff --git a/sdk/examples/client/client.rs b/sdk/examples/client/client.rs
@@ -17,7 +17,7 @@ use anyhow::Result;
use c2pa::{
assertions::{c2pa_action, labels, Action, Actions, CreativeWork, SchemaDotOrgPerson},
- create_signer, Ingredient, Manifest, ManifestStore,
+ create_signer, Ingredient, Manifest, ManifestStore, SigningAlg,
};
use std::path::PathBuf;
@@ -111,7 +111,7 @@ pub fn main() -> Result<()> {
// sign and embed into the target file
let signcert_path = "../sdk/tests/fixtures/certs.ps256.pem";
let pkey_path = "../sdk/tests/fixtures/certs.ps256.pub";
- let signer = create_signer::from_files(signcert_path, pkey_path, "ps256", None)?;
+ let signer = create_signer::from_files(signcert_path, pkey_path, SigningAlg::Ps256, None)?;
manifest.embed(&source, &dest, &*signer)?;
diff --git a/sdk/src/cose_sign.rs b/sdk/src/cose_sign.rs
@@ -25,79 +25,8 @@ use crate::{
cose_validator::verify_cose,
status_tracker::OneShotStatusTracker,
time_stamp::{cose_timestamp_countersign, make_cose_timestamp},
- Error, Result, Signer,
+ Error, Result, Signer, SigningAlg,
};
-fn build_unprotected_header(
- data: &[u8],
- alg: &str,
- certs: Vec<Vec<u8>>,
- ta_url: Option<String>,
- ocsp_val: Option<Vec<u8>>,
-) -> Result<(Header, Header)> {
- let alg_id = match alg {
- "ps256" => HeaderBuilder::new()
- .algorithm(iana::Algorithm::PS256)
- .build(),
- "ps384" => HeaderBuilder::new()
- .algorithm(iana::Algorithm::PS384)
- .build(),
- "ps512" => HeaderBuilder::new()
- .algorithm(iana::Algorithm::PS512)
- .build(),
- "es256" => HeaderBuilder::new()
- .algorithm(iana::Algorithm::ES256)
- .build(),
- "es384" => HeaderBuilder::new()
- .algorithm(iana::Algorithm::ES384)
- .build(),
- "es512" => HeaderBuilder::new()
- .algorithm(iana::Algorithm::ES512)
- .build(),
- "ed25519" => HeaderBuilder::new()
- .algorithm(iana::Algorithm::EdDSA)
- .build(),
- _ => return Err(Error::UnsupportedType),
- };
-
- let sc_der_array_or_bytes = match certs.len() {
- 1 => Value::Bytes(certs[0].clone()), // single cert
- _ => {
- let mut sc_der_array: Vec<Value> = Vec::new();
- for cert in certs {
- sc_der_array.push(Value::Bytes(cert));
- }
- Value::Array(sc_der_array) // provide vec of certs when required
- }
- };
-
- let mut unprotected = if let Some(url) = ta_url {
- let cts = cose_timestamp_countersign(data, alg, &url)?;
- let sigtst_vec = serde_cbor::to_vec(&make_cose_timestamp(&cts))?;
- let sigtst_cbor = serde_cbor::from_slice(&sigtst_vec)?;
-
- HeaderBuilder::new()
- .text_value("x5chain".to_string(), sc_der_array_or_bytes)
- .text_value("sigTst".to_string(), sigtst_cbor)
- } else {
- HeaderBuilder::new().text_value("x5chain".to_string(), sc_der_array_or_bytes)
- };
-
- // set the ocsp responder response if available
- if let Some(ocsp) = ocsp_val {
- let mut ocsp_vec: Vec<Value> = Vec::new();
- let mut r_vals: Vec<(Value, Value)> = vec![];
-
- ocsp_vec.push(Value::Bytes(ocsp));
- r_vals.push((Value::Text("ocspVals".to_string()), Value::Array(ocsp_vec)));
-
- unprotected = unprotected.text_value("rVals".to_string(), Value::Map(r_vals));
- }
-
- // build complete header
- let unprotected_header = unprotected.build();
-
- Ok((alg_id, unprotected_header))
-}
/// Generate a COSE signature for a block of bytes which must be a valid C2PA
/// claim structure.
@@ -117,15 +46,15 @@ fn build_unprotected_header(
/// 3. Verifies that the signature is valid COSE. Will respond with an error
/// if unable to validate.
pub fn sign_claim(claim_bytes: &[u8], signer: &dyn Signer, box_size: usize) -> Result<Vec<u8>> {
- // must be a valid Claim
+ // Must be a valid claim.
let label = "dummy_label";
let _claim = Claim::from_data(label, claim_bytes)?;
- // generate and verify a CoseSign1 representation of the data
+ // Generate and verify a CoseSign1 representation of the data.
cose_sign(signer, claim_bytes, box_size).and_then(|sig| {
// Sanity check: Ensure that this signature is valid.
-
let mut cose_log = OneShotStatusTracker::new();
+
match verify_cose(&sig, claim_bytes, b"", false, &mut cose_log) {
Ok(_) => Ok(sig),
Err(err) => Err(err),
@@ -158,12 +87,12 @@ pub(crate) fn cose_sign(signer: &dyn Signer, data: &[u8], box_size: usize) -> Re
string.
*/
- let alg = signer.alg().ok_or(Error::UnsupportedType)?;
+ let alg = signer.alg();
// build complete header
let (alg_id, unprotected_header) = build_unprotected_header(
data,
- &alg,
+ alg,
signer.certs()?,
signer.time_authority_url(),
signer.ocsp_val(),
@@ -216,12 +145,12 @@ pub async fn cose_sign_async(
string.
*/
- let alg = signer.alg().ok_or(Error::UnsupportedType)?;
+ let alg = signer.alg();
// build complete header
let (alg_id, unprotected_header) = build_unprotected_header(
data,
- &alg,
+ alg,
signer.certs()?,
signer.time_authority_url(),
signer.ocsp_val(),
@@ -254,6 +183,77 @@ pub async fn cose_sign_async(
Ok(c2pa_sig_data)
}
+fn build_unprotected_header(
+ data: &[u8],
+ alg: SigningAlg,
+ certs: Vec<Vec<u8>>,
+ ta_url: Option<String>,
+ ocsp_val: Option<Vec<u8>>,
+) -> Result<(Header, Header)> {
+ let alg_id = match alg {
+ SigningAlg::Ps256 => HeaderBuilder::new()
+ .algorithm(iana::Algorithm::PS256)
+ .build(),
+ SigningAlg::Ps384 => HeaderBuilder::new()
+ .algorithm(iana::Algorithm::PS384)
+ .build(),
+ SigningAlg::Ps512 => HeaderBuilder::new()
+ .algorithm(iana::Algorithm::PS512)
+ .build(),
+ SigningAlg::Es256 => HeaderBuilder::new()
+ .algorithm(iana::Algorithm::ES256)
+ .build(),
+ SigningAlg::Es384 => HeaderBuilder::new()
+ .algorithm(iana::Algorithm::ES384)
+ .build(),
+ SigningAlg::Es512 => HeaderBuilder::new()
+ .algorithm(iana::Algorithm::ES512)
+ .build(),
+ SigningAlg::Ed25519 => HeaderBuilder::new()
+ .algorithm(iana::Algorithm::EdDSA)
+ .build(),
+ };
+
+ let sc_der_array_or_bytes = match certs.len() {
+ 1 => Value::Bytes(certs[0].clone()), // single cert
+ _ => {
+ let mut sc_der_array: Vec<Value> = Vec::new();
+ for cert in certs {
+ sc_der_array.push(Value::Bytes(cert));
+ }
+ Value::Array(sc_der_array) // provide vec of certs when required
+ }
+ };
+
+ let mut unprotected = if let Some(url) = ta_url {
+ let cts = cose_timestamp_countersign(data, alg, &url)?;
+ let sigtst_vec = serde_cbor::to_vec(&make_cose_timestamp(&cts))?;
+ let sigtst_cbor = serde_cbor::from_slice(&sigtst_vec)?;
+
+ HeaderBuilder::new()
+ .text_value("x5chain".to_string(), sc_der_array_or_bytes)
+ .text_value("sigTst".to_string(), sigtst_cbor)
+ } else {
+ HeaderBuilder::new().text_value("x5chain".to_string(), sc_der_array_or_bytes)
+ };
+
+ // set the ocsp responder response if available
+ if let Some(ocsp) = ocsp_val {
+ let mut ocsp_vec: Vec<Value> = Vec::new();
+ let mut r_vals: Vec<(Value, Value)> = vec![];
+
+ ocsp_vec.push(Value::Bytes(ocsp));
+ r_vals.push((Value::Text("ocspVals".to_string()), Value::Array(ocsp_vec)));
+
+ unprotected = unprotected.text_value("rVals".to_string(), Value::Map(r_vals));
+ }
+
+ // build complete header
+ let unprotected_header = unprotected.build();
+
+ Ok((alg_id, unprotected_header))
+}
+
const PAD: &str = "pad";
const PAD2: &str = "pad2";
const PAD_OFFSET: usize = 7;
diff --git a/sdk/src/cose_validator.rs b/sdk/src/cose_validator.rs
@@ -11,30 +11,31 @@
// specific language governing permissions and limitations under
// each license.
-use crate::error::{Error, Result};
-use crate::status_tracker::{log_item, StatusTracker};
-use crate::time_stamp::gt_to_datetime;
-use crate::validation_status;
-#[cfg(not(target_arch = "wasm32"))]
-use crate::validator::get_validator;
-#[cfg(not(target_arch = "wasm32"))]
-use crate::validator::CoseValidator;
-use crate::validator::ValidationInfo;
-
-#[cfg(target_arch = "wasm32")]
-use crate::wasm::webcrypto_validator::validate_async;
+use std::str::FromStr;
-use crate::asn1::rfc3161::TstInfo;
use ciborium::value::Value;
use conv::*;
use coset::{sig_structure_data, Label, TaggedCborSerializable};
-use std::str::FromStr;
+use x509_parser::{
+ der_parser::ber::parse_ber_sequence, der_parser::oid, oid_registry::Oid, prelude::*,
+};
+
+use crate::{
+ asn1::rfc3161::TstInfo,
+ error::{Error, Result},
+ status_tracker::{log_item, StatusTracker},
+ time_stamp::gt_to_datetime,
+ validation_status,
+ validator::ValidationInfo,
+ SigningAlg,
+};
+
+#[cfg(target_arch = "wasm32")]
+use crate::wasm::webcrypto_validator::validate_async;
-use x509_parser::der_parser::ber::parse_ber_sequence;
-use x509_parser::der_parser::oid;
-use x509_parser::oid_registry::Oid;
-use x509_parser::prelude::*;
+#[cfg(not(target_arch = "wasm32"))]
+use crate::validator::{get_validator, CoseValidator};
const RSA_OID: Oid<'static> = oid!(1.2.840 .113549 .1 .1 .1);
const EC_PUBLICKEY_OID: Oid<'static> = oid!(1.2.840 .10045 .2 .1);
@@ -93,7 +94,7 @@ fn get_cose_sign1(
}
}
fn check_cert(
- _alg: &str,
+ _alg: SigningAlg,
ca_der_bytes: &[u8],
validation_log: &mut impl StatusTracker,
_tst_info_opt: Option<&TstInfo>,
@@ -492,50 +493,46 @@ fn check_cert(
}
}
-pub(crate) fn get_validator_str(cs1: &coset::CoseSign1) -> Result<String> {
+pub(crate) fn get_signing_alg(cs1: &coset::CoseSign1) -> Result<SigningAlg> {
// find the supported handler for the algorithm
- let validator_str = match cs1.protected.header.alg {
+ match cs1.protected.header.alg {
Some(ref alg) => {
- let alg_str = match alg {
+ match alg {
coset::RegisteredLabelWithPrivate::PrivateUse(a) => match a {
- -39 => "ps512",
- -38 => "ps384",
- -37 => "ps256",
- -36 => "es512",
- -35 => "es384",
- -7 => "es256",
+ -39 => Ok(SigningAlg::Ps512),
+ -38 => Ok(SigningAlg::Ps384),
+ -37 => Ok(SigningAlg::Ps256),
+ -36 => Ok(SigningAlg::Es512),
+ -35 => Ok(SigningAlg::Es384),
+ -7 => Ok(SigningAlg::Es256),
// todo: deprecated figure out lecacy support for RS signatures
- -259 => "rs512",
- -258 => "rs384",
- -257 => "rs256",
-
- -8 => "ed25519",
- _ => "unknown",
+ // -259 => "rs512",
+ // -258 => "rs384",
+ // -257 => "rs256",
+ -8 => Ok(SigningAlg::Ed25519),
+ _ => Err(Error::CoseSignatureAlgorithmNotSupported),
},
coset::RegisteredLabelWithPrivate::Assigned(a) => match a {
- coset::iana::Algorithm::PS512 => "ps512",
- coset::iana::Algorithm::PS384 => "ps384",
- coset::iana::Algorithm::PS256 => "ps256",
- coset::iana::Algorithm::ES512 => "es512",
- coset::iana::Algorithm::ES384 => "es384",
- coset::iana::Algorithm::ES256 => "es256",
+ coset::iana::Algorithm::PS512 => Ok(SigningAlg::Ps512),
+ coset::iana::Algorithm::PS384 => Ok(SigningAlg::Ps384),
+ coset::iana::Algorithm::PS256 => Ok(SigningAlg::Ps256),
+ coset::iana::Algorithm::ES512 => Ok(SigningAlg::Es512),
+ coset::iana::Algorithm::ES384 => Ok(SigningAlg::Es384),
+ coset::iana::Algorithm::ES256 => Ok(SigningAlg::Es256),
// todo: deprecated figure out lecacy support for RS signatures
- coset::iana::Algorithm::RS512 => "rs512",
- coset::iana::Algorithm::RS384 => "rs384",
- coset::iana::Algorithm::RS256 => "rs256",
- coset::iana::Algorithm::EdDSA => "ed25519",
- _ => "unknown",
+ // coset::iana::Algorithm::RS512 => "rs512",
+ // coset::iana::Algorithm::RS384 => "rs384",
+ // coset::iana::Algorithm::RS256 => "rs256",
+ coset::iana::Algorithm::EdDSA => Ok(SigningAlg::Ed25519),
+ _ => Err(Error::CoseSignatureAlgorithmNotSupported),
},
- coset::RegisteredLabelWithPrivate::Text(a) => a,
- };
-
- Some(alg_str.to_owned())
+ coset::RegisteredLabelWithPrivate::Text(a) => a
+ .parse()
+ .map_err(|_| Error::CoseSignatureAlgorithmNotSupported),
+ }
}
- None => None,
+ None => Err(Error::CoseSignatureAlgorithmNotSupported),
}
- .ok_or(Error::CoseSignatureAlgorithmNotSupported)?;
-
- Ok(validator_str)
}
fn get_sign_cert(sign1: &coset::CoseSign1) -> Result<Vec<u8>> {
@@ -638,9 +635,9 @@ fn get_timestamp_info(sign1: &coset::CoseSign1, data: &[u8]) -> Result<TstInfo>
}
})
{
- let alg = get_validator_str(sign1)?;
+ let alg = get_signing_alg(sign1)?;
let time_cbor = serde_cbor::to_vec(t)?;
- let tst_infos = crate::time_stamp::cose_sigtst_to_tstinfos(&time_cbor, data, &alg)?;
+ let tst_infos = crate::time_stamp::cose_sigtst_to_tstinfos(&time_cbor, data, alg)?;
// there should only be one but consider handling more in the future since it is technically ok
if !tst_infos.is_empty() {
@@ -674,8 +671,8 @@ pub async fn verify_cose_async(
) -> Result<ValidationInfo> {
let mut sign1 = get_cose_sign1(&cose_bytes, &data, validation_log)?;
- let validator_str = match get_validator_str(&sign1) {
- Ok(s) => s,
+ let alg = match get_signing_alg(&sign1) {
+ Ok(a) => a,
Err(_) => {
let log_item = log_item!(
"Cose_Sign1",
@@ -701,15 +698,11 @@ pub async fn verify_cose_async(
if !signature_only {
// verify certs
match get_timestamp_info(&sign1, &data) {
- Ok(tst_info) => {
- check_cert(&validator_str, &der_bytes, validation_log, Some(&tst_info))?
- }
+ Ok(tst_info) => check_cert(alg, &der_bytes, validation_log, Some(&tst_info))?,
Err(e) => {
// log timestamp errors
match e {
- Error::NotFound => {
- check_cert(&validator_str, &der_bytes, validation_log, None)?
- }
+ Error::NotFound => check_cert(alg, &der_bytes, validation_log, None)?,
Error::CoseTimeStampMismatch => {
let log_item = log_item!(
"Cose_Sign1",
@@ -754,12 +747,10 @@ 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(&validator_str, &sign1.signature, &tbs, &der_bytes).await
- {
+ if let Ok(issuer) = validate_with_cert_async(alg, &sign1.signature, &tbs, &der_bytes).await {
result.issuer_org = Some(issuer);
result.validated = true;
- result.alg = validator_str.to_owned();
+ result.alg = Some(alg);
// parse the temp time for now util we have TA
result.date = get_signing_time(&sign1, &data, validation_log);
@@ -775,7 +766,7 @@ pub fn get_signing_info(
) -> ValidationInfo {
let mut date = None;
let mut issuer_org = None;
- let mut alg = "".to_string();
+ let mut alg: Option<SigningAlg> = None;
let _ = get_cose_sign1(cose_bytes, data, validation_log).and_then(|sign1| {
// get the public key der
@@ -784,8 +775,8 @@ pub fn get_signing_info(
let _ = X509Certificate::from_der(&der_bytes).map(|(_rem, signcert)| {
date = get_signing_time(&sign1, data, validation_log);
issuer_org = extract_subject_from_cert(&signcert).ok();
- if let Ok(a) = get_validator_str(&sign1) {
- alg = a;
+ if let Ok(a) = get_signing_alg(&sign1) {
+ alg = Some(a);
}
(_rem, signcert)
@@ -817,8 +808,8 @@ pub fn verify_cose(
) -> Result<ValidationInfo> {
let sign1 = get_cose_sign1(cose_bytes, data, validation_log)?;
- let validator_str = match get_validator_str(&sign1) {
- Ok(s) => s,
+ let alg = match get_signing_alg(&sign1) {
+ Ok(a) => a,
Err(_) => {
let log_item = log_item!(
"Cose_Sign1",
@@ -834,8 +825,7 @@ pub fn verify_cose(
}
};
- let validator =
- get_validator(&validator_str).ok_or(Error::CoseSignatureAlgorithmNotSupported)?;
+ let validator = get_validator(alg);
// build result structure
let mut result = ValidationInfo::default();
@@ -849,11 +839,11 @@ pub fn verify_cose(
if !signature_only {
// verify certs
match get_timestamp_info(&sign1, data) {
- Ok(tst_info) => check_cert(&validator_str, der_bytes, validation_log, Some(&tst_info))?,
+ Ok(tst_info) => check_cert(alg, der_bytes, validation_log, Some(&tst_info))?,
Err(e) => {
// log timestamp errors
match e {
- Error::NotFound => check_cert(&validator_str, der_bytes, validation_log, None)?,
+ Error::NotFound => check_cert(alg, der_bytes, validation_log, None)?,
Error::CoseTimeStampMismatch => {
let log_item = log_item!(
"Cose_Sign1",
@@ -890,7 +880,7 @@ pub fn verify_cose(
if let Ok(issuer) = validate_with_cert(validator, sig, verify_data, der_bytes) {
result.issuer_org = Some(issuer);
result.validated = true;
- result.alg = validator_str.to_string();
+ result.alg = Some(alg);
// parse the temp time for now util we have TA
result.date = get_signing_time(&sign1, data, validation_log);
@@ -935,7 +925,7 @@ fn validate_with_cert(
#[cfg(target_arch = "wasm32")]
async fn validate_with_cert_async(
- validator_str: &str,
+ signing_alg: SigningAlg,
sig: &[u8],
data: &[u8],
der_bytes: &[u8],
@@ -945,7 +935,7 @@ async fn validate_with_cert_async(
let pk = signcert.public_key();
let pk_der = pk.raw;
- if validate_async(validator_str, sig, data, pk_der).await? {
+ if validate_async(signing_alg, sig, data, pk_der).await? {
Ok(extract_subject_from_cert(&signcert)?)
} else {
Err(Error::CoseSignature)
@@ -954,7 +944,7 @@ async fn validate_with_cert_async(
#[cfg(not(target_arch = "wasm32"))]
async fn validate_with_cert_async(
- validator_str: &str,
+ signing_alg: SigningAlg,
sig: &[u8],
data: &[u8],
der_bytes: &[u8],
@@ -965,8 +955,7 @@ async fn validate_with_cert_async(
let pk = signcert.public_key();
let pk_der = pk.raw;
- let validator =
- get_validator(validator_str).ok_or(Error::CoseSignatureAlgorithmNotSupported)?;
+ let validator = get_validator(signing_alg);
if validator.validate(sig, data, pk_der)? {
Ok(extract_subject_from_cert(&signcert)?)
@@ -980,11 +969,11 @@ async fn validate_with_cert_async(
pub mod tests {
#![allow(clippy::unwrap_used)]
- use sha2::digest::generic_array::sequence::Shorten;
+ use super::*;
- use crate::status_tracker::DetailedStatusTracker;
+ use sha2::digest::generic_array::sequence::Shorten;
- use super::*;
+ use crate::{status_tracker::DetailedStatusTracker, SigningAlg};
#[test]
#[cfg(feature = "file_io")]
@@ -998,7 +987,7 @@ pub mod tests {
if let Ok(signcert) = openssl::x509::X509::from_pem(&expired_cert) {
let der_bytes = signcert.to_der().unwrap();
- assert!(check_cert("ps256", &der_bytes, &mut validation_log, None).is_err());
+ assert!(check_cert(SigningAlg::Ps256, &der_bytes, &mut validation_log, None).is_err());
assert!(!validation_log.get_log().is_empty());
@@ -1011,7 +1000,7 @@ pub mod tests {
#[test]
fn test_verify_cose_good() {
- let validator = get_validator("ps256").unwrap();
+ let validator = get_validator(SigningAlg::Ps256);
let sig_bytes = include_bytes!("../tests/fixtures/sig_ps256.data");
let data_bytes = include_bytes!("../tests/fixtures/data_ps256.data");
@@ -1025,7 +1014,7 @@ pub mod tests {
#[test]
fn test_verify_ec_good() {
// EC signatures
- let mut validator = get_validator("es384").unwrap();
+ let mut validator = get_validator(SigningAlg::Es384);
let sig_es384_bytes = include_bytes!("../tests/fixtures/sig_es384.data");
let data_es384_bytes = include_bytes!("../tests/fixtures/data_es384.data");
@@ -1035,7 +1024,7 @@ pub mod tests {
.validate(sig_es384_bytes, data_es384_bytes, key_es384_bytes)
.unwrap());
- validator = get_validator("es512").unwrap();
+ validator = get_validator(SigningAlg::Es512);
let sig_es512_bytes = include_bytes!("../tests/fixtures/sig_es512.data");
let data_es512_bytes = include_bytes!("../tests/fixtures/data_es512.data");
@@ -1048,7 +1037,7 @@ pub mod tests {
#[test]
fn test_verify_cose_bad() {
- let validator = get_validator("ps256").unwrap();
+ let validator = get_validator(SigningAlg::Ps256);
let sig_bytes = include_bytes!("../tests/fixtures/sig_ps256.data");
let data_bytes = include_bytes!("../tests/fixtures/data_ps256.data");
@@ -1074,36 +1063,36 @@ pub mod tests {
let mut validation_log = DetailedStatusTracker::new();
- let (_, cert_path) = temp_signer::get_ec_signer(&cert_dir, "es256", None);
+ let (_, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es256, None);
let es256_cert = std::fs::read(&cert_path).unwrap();
- let (_, cert_path) = temp_signer::get_ec_signer(&cert_dir, "es384", None);
+ let (_, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es384, None);
let es384_cert = std::fs::read(&cert_path).unwrap();
- let (_, cert_path) = temp_signer::get_ec_signer(&cert_dir, "es512", None);
+ let (_, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es512, None);
let es512_cert = std::fs::read(&cert_path).unwrap();
- let (_, cert_path) = temp_signer::get_rsa_signer(&cert_dir, "ps256", None);
+ let (_, cert_path) = temp_signer::get_rsa_signer(&cert_dir, SigningAlg::Ps256, None);
let rsa_pss256_cert = std::fs::read(&cert_path).unwrap();
if let Ok(signcert) = openssl::x509::X509::from_pem(&es256_cert) {
let der_bytes = signcert.to_der().unwrap();
- assert!(check_cert("es256", &der_bytes, &mut validation_log, None).is_ok());
+ assert!(check_cert(SigningAlg::Es256, &der_bytes, &mut validation_log, None).is_ok());
}
if let Ok(signcert) = openssl::x509::X509::from_pem(&es384_cert) {
let der_bytes = signcert.to_der().unwrap();
- assert!(check_cert("es384", &der_bytes, &mut validation_log, None).is_ok());
+ assert!(check_cert(SigningAlg::Es384, &der_bytes, &mut validation_log, None).is_ok());
}
if let Ok(signcert) = openssl::x509::X509::from_pem(&es512_cert) {
let der_bytes = signcert.to_der().unwrap();
- assert!(check_cert("es512", &der_bytes, &mut validation_log, None).is_ok());
+ assert!(check_cert(SigningAlg::Es512, &der_bytes, &mut validation_log, None).is_ok());
}
if let Ok(signcert) = openssl::x509::X509::from_pem(&rsa_pss256_cert) {
let der_bytes = signcert.to_der().unwrap();
- assert!(check_cert("ps256", &der_bytes, &mut validation_log, None).is_ok());
+ assert!(check_cert(SigningAlg::Ps256, &der_bytes, &mut validation_log, None).is_ok());
}
}
}
diff --git a/sdk/src/create_signer.rs b/sdk/src/create_signer.rs
@@ -19,10 +19,10 @@
use std::path::Path;
use crate::{
- error::{Error, Result},
+ error::Result,
openssl::{EcSigner, EdSigner, RsaSigner},
signer::ConfigurableSigner,
- Signer,
+ Signer, SigningAlg,
};
/// Creates a [`Signer`] instance using signing certificate and private key
@@ -35,36 +35,24 @@ use crate::{
///
/// * `signcert` - Signing certificate
/// * `pkey` - Private key
-/// * `alg` - Format for signing. Must be one of the supported
-/// formats (`rs256`, `rs384`, `rs512`, `ps256`, `ps384`, `ps512`,
-/// `es256`, `es384`, `es512`, or `ed25519`).
+/// * `alg` - Format for signing
/// * `tsa_url` - Optional URL for a timestamp authority
pub fn from_keys(
signcert: &[u8],
pkey: &[u8],
- alg: &str,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> Result<Box<dyn Signer>> {
Ok(match alg {
- "ps256" | "ps384" | "ps512" => Box::new(RsaSigner::from_signcert_and_pkey(
- signcert,
- pkey,
- alg.to_owned(),
- tsa_url,
- )?),
- "es256" | "es384" | "es512" => Box::new(EcSigner::from_signcert_and_pkey(
- signcert,
- pkey,
- alg.to_owned(),
- tsa_url,
+ SigningAlg::Ps256 | SigningAlg::Ps384 | SigningAlg::Ps512 => Box::new(
+ RsaSigner::from_signcert_and_pkey(signcert, pkey, alg, tsa_url)?,
+ ),
+ SigningAlg::Es256 | SigningAlg::Es384 | SigningAlg::Es512 => Box::new(
+ EcSigner::from_signcert_and_pkey(signcert, pkey, alg, tsa_url)?,
+ ),
+ SigningAlg::Ed25519 => Box::new(EdSigner::from_signcert_and_pkey(
+ signcert, pkey, alg, tsa_url,
)?),
- "ed25519" => Box::new(EdSigner::from_signcert_and_pkey(
- signcert,
- pkey,
- alg.to_owned(),
- tsa_url,
- )?),
- _ => return Err(Error::BadParam(alg.to_owned())),
})
}
@@ -75,35 +63,26 @@ pub fn from_keys(
///
/// * `signcert_path` - Path to the signing certificate file
/// * `pkey_path` - Path to the private key file
-/// * `alg` - Format for signing. Must be one of the supported
-/// formats (`rs256`, `rs384`, `rs512`, `ps256`, `ps384`, `ps512`,
-/// `es256`, `es384`, `es512`, or `ed25519`).
+/// * `alg` - Format for signing
/// * `tsa_url` - Optional URL for a timestamp authority
pub fn from_files<P: AsRef<Path>>(
signcert_path: P,
pkey_path: P,
- alg: &str,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> Result<Box<dyn Signer>> {
Ok(match alg {
- "ps256" | "ps384" | "ps512" => Box::new(RsaSigner::from_files(
- &signcert_path,
- &pkey_path,
- alg.to_owned(),
- tsa_url,
- )?),
- "es256" | "es384" | "es512" => Box::new(EcSigner::from_files(
- &signcert_path,
- &pkey_path,
- alg.to_owned(),
- tsa_url,
- )?),
- "ed25519" => Box::new(EdSigner::from_files(
+ SigningAlg::Ps256 | SigningAlg::Ps384 | SigningAlg::Ps512 => Box::new(
+ RsaSigner::from_files(&signcert_path, &pkey_path, alg, tsa_url)?,
+ ),
+ SigningAlg::Es256 | SigningAlg::Es384 | SigningAlg::Es512 => Box::new(
+ EcSigner::from_files(&signcert_path, &pkey_path, alg, tsa_url)?,
+ ),
+ SigningAlg::Ed25519 => Box::new(EdSigner::from_files(
&signcert_path,
&pkey_path,
- alg.to_owned(),
+ alg,
tsa_url,
)?),
- _ => return Err(Error::BadParam(alg.to_owned())),
})
}
diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs
@@ -47,7 +47,8 @@
//! use c2pa::{
//! assertions::User,
//! create_signer,
-//! Manifest
+//! Manifest,
+//! SigningAlg,
//! };
//!
//! use std::path::PathBuf;
@@ -64,7 +65,7 @@
//! // Create a ps256 signer using certs and key files
//! let signcert_path = "tests/fixtures/certs/ps256.pub";
//! let pkey_path = "tests/fixtures/certs/ps256.pem";
-//! let signer = create_signer::from_files(signcert_path, pkey_path, "ps256", None)?;
+//! let signer = create_signer::from_files(signcert_path, pkey_path, SigningAlg::Ps256, None)?;
//!
//! // embed a manifest using the signer
//! manifest.embed(&source, &dest, &*signer)?;
@@ -97,6 +98,9 @@ pub use manifest_store::ManifestStore;
mod manifest_store_report;
pub use manifest_store_report::ManifestStoreReport;
+mod signing_alg;
+pub use signing_alg::{SigningAlg, UnknownAlgorithmError};
+
#[cfg(feature = "file_io")]
pub(crate) mod ocsp_utils;
#[cfg(feature = "file_io")]
diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs
@@ -568,7 +568,8 @@ impl Manifest {
/// use c2pa::{
/// assertions::User,
/// create_signer,
- /// Manifest
+ /// Manifest,
+ /// SigningAlg,
/// };
/// # fn main() -> Result<()> {
/// let mut manifest = Manifest::new("my_app".to_owned());
@@ -580,7 +581,7 @@ impl Manifest {
/// // Create a PS256 signer using certs and public key files.
/// let signcert_path = "tests/fixtures/certs/ps256.pub";
/// let pkey_path = "tests/fixtures/certs/ps256.pem";
- /// let signer = create_signer::from_files(signcert_path, pkey_path, "ps256", None)?;
+ /// let signer = create_signer::from_files(signcert_path, pkey_path, SigningAlg::Ps256, None)?;
///
/// // Embed a manifest using the signer.
/// manifest.embed(&source, &dest, &*signer)?;
diff --git a/sdk/src/manifest_store_report.rs b/sdk/src/manifest_store_report.rs
@@ -150,7 +150,7 @@ impl ManifestReport {
let signature = match claim.signature_info() {
Some(info) => SignatureReport {
- alg: info.alg,
+ alg: info.alg.map_or_else(String::new, |a| a.to_string()),
issuer: info.issuer_org,
time: info.date.map(|d| d.to_rfc3339()),
},
diff --git a/sdk/src/openssl/ec_signer.rs b/sdk/src/openssl/ec_signer.rs
@@ -16,7 +16,7 @@ use std::{fs, path::Path};
use crate::{
error::{wrap_io_err, wrap_openssl_err, Error, Result},
signer::ConfigurableSigner,
- Signer,
+ Signer, SigningAlg,
};
use openssl::hash::MessageDigest;
use openssl::pkey::PKey;
@@ -37,7 +37,7 @@ pub struct EcSigner {
certs_size: usize,
timestamp_size: usize,
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
}
@@ -45,7 +45,7 @@ impl ConfigurableSigner for EcSigner {
fn from_files<P: AsRef<Path>>(
signcert_path: P,
pkey_path: P,
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> Result<Self> {
let signcert = fs::read(signcert_path).map_err(wrap_io_err)?;
@@ -57,7 +57,7 @@ impl ConfigurableSigner for EcSigner {
fn from_signcert_and_pkey(
signcert: &[u8],
pkey: &[u8],
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> Result<Self> {
let certs_size = signcert.len();
@@ -86,21 +86,21 @@ impl Signer for EcSigner {
fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
let key = PKey::from_ec_key(self.pkey.clone()).map_err(wrap_openssl_err)?;
- let mut signer = match self.alg.as_ref() {
- "es256" => openssl::sign::Signer::new(MessageDigest::sha256(), &key)?,
- "es384" => openssl::sign::Signer::new(MessageDigest::sha384(), &key)?,
- "es512" => openssl::sign::Signer::new(MessageDigest::sha512(), &key)?,
+ let mut signer = match self.alg {
+ SigningAlg::Es256 => openssl::sign::Signer::new(MessageDigest::sha256(), &key)?,
+ SigningAlg::Es384 => openssl::sign::Signer::new(MessageDigest::sha384(), &key)?,
+ SigningAlg::Es512 => openssl::sign::Signer::new(MessageDigest::sha512(), &key)?,
_ => return Err(Error::UnsupportedType),
};
signer.update(data).map_err(wrap_openssl_err)?;
let der_sig = signer.sign_to_vec().map_err(wrap_openssl_err)?;
- der_to_p1363(&der_sig, &self.alg)
+ der_to_p1363(&der_sig, self.alg)
}
- fn alg(&self) -> Option<String> {
- Some(self.alg.to_owned())
+ fn alg(&self) -> SigningAlg {
+ self.alg
}
fn certs(&self) -> Result<Vec<Vec<u8>>> {
@@ -145,7 +145,7 @@ fn parse_ec_sig(data: &[u8]) -> der_parser::error::BerResult<ECSigComps> {
})(data)
}
-fn der_to_p1363(data: &[u8], alg: &str) -> Result<Vec<u8>> {
+fn der_to_p1363(data: &[u8], alg: SigningAlg) -> Result<Vec<u8>> {
// P1363 format: r | s
let (_, p) = parse_ec_sig(data).map_err(|_err| Error::InvalidEcdsaSignature)?;
@@ -154,9 +154,9 @@ fn der_to_p1363(data: &[u8], alg: &str) -> Result<Vec<u8>> {
let mut s = extfmt::Hexlify(p.s).to_string();
let sig_len: usize = match alg {
- "es256" => 64,
- "es384" => 96,
- "es512" => 132,
+ SigningAlg::Es256 => 64,
+ SigningAlg::Es384 => 96,
+ SigningAlg::Es512 => 132,
_ => return Err(Error::UnsupportedType),
};
@@ -208,12 +208,13 @@ mod tests {
use super::*;
- use crate::{openssl::temp_signer, utils::test::fixture_path};
+ use crate::{openssl::temp_signer, utils::test::fixture_path, SigningAlg};
+
#[test]
fn es256_signer() {
let cert_dir = fixture_path("certs");
- let (signer, _) = temp_signer::get_ec_signer(&cert_dir, "es256", None);
+ let (signer, _) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es256, None);
let data = b"some sample content to sign";
println!("data len = {}", data.len());
@@ -228,7 +229,7 @@ mod tests {
fn es384_signer() {
let cert_dir = fixture_path("certs");
- let (signer, _) = temp_signer::get_ec_signer(&cert_dir, "es384", None);
+ let (signer, _) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es384, None);
let data = b"some sample content to sign";
println!("data len = {}", data.len());
@@ -243,7 +244,7 @@ mod tests {
fn es512_signer() {
let cert_dir = fixture_path("certs");
- let (signer, _) = temp_signer::get_ec_signer(&cert_dir, "es512", None);
+ let (signer, _) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es512, None);
let data = b"some sample content to sign";
println!("data len = {}", data.len());
diff --git a/sdk/src/openssl/ec_validator.rs b/sdk/src/openssl/ec_validator.rs
@@ -11,20 +11,18 @@
// specific language governing permissions and limitations under
// each license.
-use crate::{validator::CoseValidator, Error, Result};
+use crate::{validator::CoseValidator, Error, Result, SigningAlg};
use openssl::ec::EcKey;
use openssl::hash::MessageDigest;
use openssl::pkey::PKey;
pub struct EcValidator {
- alg: String,
+ alg: SigningAlg,
}
impl EcValidator {
- pub fn new(alg: &str) -> Self {
- EcValidator {
- alg: alg.to_owned(),
- }
+ pub fn new(alg: SigningAlg) -> Self {
+ EcValidator { alg }
}
}
@@ -33,19 +31,19 @@ impl CoseValidator for EcValidator {
let public_key = EcKey::public_key_from_der(pkey).map_err(|_err| Error::CoseSignature)?;
let key = PKey::from_ec_key(public_key).map_err(wrap_openssl_err)?;
- let mut verifier = match self.alg.as_ref() {
- "es256" => openssl::sign::Verifier::new(MessageDigest::sha256(), &key)?,
- "es384" => openssl::sign::Verifier::new(MessageDigest::sha384(), &key)?,
- "es512" => openssl::sign::Verifier::new(MessageDigest::sha512(), &key)?,
+ let mut verifier = match self.alg {
+ SigningAlg::Es256 => openssl::sign::Verifier::new(MessageDigest::sha256(), &key)?,
+ SigningAlg::Es384 => openssl::sign::Verifier::new(MessageDigest::sha384(), &key)?,
+ SigningAlg::Es512 => openssl::sign::Verifier::new(MessageDigest::sha512(), &key)?,
_ => return Err(Error::UnsupportedType),
};
// is this an expected P1363 sig size
if sig.len()
- != match self.alg.as_ref() {
- "es256" => 64,
- "es384" => 96,
- "es512" => 132,
+ != match self.alg {
+ SigningAlg::Es256 => 64,
+ SigningAlg::Es384 => 96,
+ SigningAlg::Es512 => 132,
_ => return Err(Error::UnsupportedType),
}
{
@@ -79,13 +77,13 @@ mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
- use crate::{openssl::temp_signer, utils::test::fixture_path, Signer};
+ use crate::{openssl::temp_signer, utils::test::fixture_path, Signer, SigningAlg};
#[test]
fn sign_and_validate_es256() {
let cert_dir = fixture_path("certs");
- let (signer, cert_path) = temp_signer::get_ec_signer(&cert_dir, "es256", None);
+ let (signer, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es256, None);
let data = b"some sample content to sign";
println!("data len = {}", data.len());
@@ -100,7 +98,7 @@ mod tests {
let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
- let validator = EcValidator::new("es256");
+ let validator = EcValidator::new(SigningAlg::Es256);
assert!(validator.validate(&signature, data, &pub_key).unwrap());
}
@@ -108,7 +106,7 @@ mod tests {
fn sign_and_validate_es384() {
let cert_dir = fixture_path("certs");
- let (signer, cert_path) = temp_signer::get_ec_signer(&cert_dir, "es384", None);
+ let (signer, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es384, None);
let data = b"some sample content to sign";
println!("data len = {}", data.len());
@@ -123,7 +121,7 @@ mod tests {
let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
- let validator = EcValidator::new("es384");
+ let validator = EcValidator::new(SigningAlg::Es384);
assert!(validator.validate(&signature, data, &pub_key).unwrap());
}
@@ -131,7 +129,7 @@ mod tests {
fn sign_and_validate_es512() {
let cert_dir = fixture_path("certs");
- let (signer, cert_path) = temp_signer::get_ec_signer(&cert_dir, "es512", None);
+ let (signer, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es512, None);
let data = b"some sample content to sign";
println!("data len = {}", data.len());
@@ -146,7 +144,7 @@ mod tests {
let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
- let validator = EcValidator::new("es512");
+ let validator = EcValidator::new(SigningAlg::Es512);
assert!(validator.validate(&signature, data, &pub_key).unwrap());
}
@@ -154,7 +152,7 @@ mod tests {
fn bad_sig_es256() {
let cert_dir = fixture_path("certs");
- let (signer, cert_path) = temp_signer::get_ec_signer(&cert_dir, "es256", None);
+ let (signer, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es256, None);
let data = b"some sample content to sign";
println!("data len = {}", data.len());
@@ -166,7 +164,7 @@ mod tests {
let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
- let validator = EcValidator::new("es256");
+ let validator = EcValidator::new(SigningAlg::Es256);
let validated = validator.validate(&signature, data, &pub_key);
assert!(validated.is_err());
}
@@ -175,7 +173,7 @@ mod tests {
fn bad_data_es256() {
let cert_dir = fixture_path("certs");
- let (signer, cert_path) = temp_signer::get_ec_signer(&cert_dir, "es256", None);
+ let (signer, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es256, None);
let mut data = b"some sample content to sign".to_vec();
println!("data len = {}", data.len());
@@ -188,7 +186,7 @@ mod tests {
let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
- let validator = EcValidator::new("es256");
+ let validator = EcValidator::new(SigningAlg::Es256);
assert!(!validator.validate(&signature, &data, &pub_key).unwrap());
}
}
diff --git a/sdk/src/openssl/ed_signer.rs b/sdk/src/openssl/ed_signer.rs
@@ -13,13 +13,13 @@
use std::{fs, path::Path};
-use crate::{signer::ConfigurableSigner, Error, Result, Signer};
-
use openssl::{
pkey::{PKey, Private},
x509::X509,
};
+use crate::{signer::ConfigurableSigner, Error, Result, Signer, SigningAlg};
+
use super::check_chain_order;
/// Implements `Signer` trait using OpenSSL's implementation of
@@ -31,7 +31,7 @@ pub struct EdSigner {
certs_size: usize,
timestamp_size: usize,
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
}
@@ -39,7 +39,7 @@ impl ConfigurableSigner for EdSigner {
fn from_files<P: AsRef<Path>>(
signcert_path: P,
pkey_path: P,
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> Result<Self> {
let signcert = fs::read(signcert_path).map_err(wrap_io_err)?;
@@ -51,14 +51,14 @@ impl ConfigurableSigner for EdSigner {
fn from_signcert_and_pkey(
signcert: &[u8],
pkey: &[u8],
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> Result<Self> {
let certs_size = signcert.len();
let signcerts = X509::stack_from_pem(signcert).map_err(wrap_openssl_err)?;
let pkey = PKey::private_key_from_pem(pkey).map_err(wrap_openssl_err)?;
- if alg.to_lowercase() != "ed25519" {
+ if alg != SigningAlg::Ed25519 {
return Err(Error::UnsupportedType); // only ed25519 is supported by C2PA
}
@@ -74,7 +74,7 @@ impl ConfigurableSigner for EdSigner {
pkey,
certs_size,
timestamp_size: 10000, // todo: call out to TSA to get actual timestamp and use that size
- alg: "ed25519".to_string(),
+ alg,
tsa_url,
})
}
@@ -90,8 +90,8 @@ impl Signer for EdSigner {
Ok(signed_data)
}
- fn alg(&self) -> Option<String> {
- Some(self.alg.to_owned())
+ fn alg(&self) -> SigningAlg {
+ self.alg
}
fn certs(&self) -> Result<Vec<Vec<u8>>> {
@@ -127,13 +127,13 @@ mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
- use crate::{openssl::temp_signer, utils::test::fixture_path};
+ use crate::{openssl::temp_signer, utils::test::fixture_path, SigningAlg};
#[test]
fn ed25519_signer() {
let cert_dir = fixture_path("certs");
- let (signer, _) = temp_signer::get_ed_signer(&cert_dir, "ed25519", None);
+ let (signer, _) = temp_signer::get_ed_signer(&cert_dir, SigningAlg::Ed25519, None);
let data = b"some sample content to sign";
println!("data len = {}", data.len());
diff --git a/sdk/src/openssl/ed_validator.rs b/sdk/src/openssl/ed_validator.rs
@@ -13,17 +13,15 @@
use openssl::pkey::PKey;
-use crate::{validator::CoseValidator, Error, Result};
+use crate::{validator::CoseValidator, Error, Result, SigningAlg};
pub struct EdValidator {
- _alg: String,
+ _alg: SigningAlg,
}
impl EdValidator {
- pub fn new(alg: &str) -> Self {
- EdValidator {
- _alg: alg.to_owned(),
- }
+ pub fn new(alg: SigningAlg) -> Self {
+ EdValidator { _alg: alg }
}
}
@@ -46,13 +44,13 @@ mod tests {
use super::*;
- use crate::{openssl::temp_signer, utils::test::fixture_path, Signer};
+ use crate::{openssl::temp_signer, utils::test::fixture_path, Signer, SigningAlg};
#[test]
fn sign_and_validate() {
let cert_dir = fixture_path("certs");
- let (signer, cert_path) = temp_signer::get_ed_signer(&cert_dir, "ed25519", None);
+ let (signer, cert_path) = temp_signer::get_ed_signer(&cert_dir, SigningAlg::Ed25519, None);
let data = b"some sample content to sign";
println!("data len = {}", data.len());
@@ -66,7 +64,7 @@ mod tests {
let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
- let validator = EdValidator::new("ed25519");
+ let validator = EdValidator::new(SigningAlg::Ed25519);
assert!(validator.validate(&signature, data, &pub_key).unwrap());
}
@@ -74,7 +72,7 @@ mod tests {
fn bad_data() {
let cert_dir = fixture_path("certs");
- let (signer, cert_path) = temp_signer::get_ed_signer(&cert_dir, "ed25519", None);
+ let (signer, cert_path) = temp_signer::get_ed_signer(&cert_dir, SigningAlg::Ed25519, None);
let mut data = b"some sample content to sign".to_vec();
println!("data len = {}", data.len());
@@ -87,7 +85,7 @@ mod tests {
let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
- let validator = EdValidator::new("es256");
+ let validator = EdValidator::new(SigningAlg::Es256);
// ^^ REVIEW with @mfisher: Is this correct? Shouldn't it be ed25519?
assert!(!validator.validate(&signature, &data, &pub_key).unwrap());
diff --git a/sdk/src/openssl/rsa_signer.rs b/sdk/src/openssl/rsa_signer.rs
@@ -14,7 +14,7 @@
use crate::{
ocsp_utils::{get_ocsp_response, OcspData},
signer::ConfigurableSigner,
- Error, Result, Signer,
+ Error, Result, Signer, SigningAlg,
};
use std::{cell::Cell, fs, path::Path};
@@ -38,7 +38,7 @@ pub struct RsaSigner {
timestamp_size: usize,
ocsp_size: Cell<usize>,
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
ocsp_rsp: Cell<OcspData>,
}
@@ -69,7 +69,7 @@ impl ConfigurableSigner for RsaSigner {
fn from_files<P: AsRef<Path>>(
signcert_path: P,
pkey_path: P,
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> Result<Self> {
let signcert = fs::read(signcert_path).map_err(wrap_io_err)?;
@@ -81,7 +81,7 @@ impl ConfigurableSigner for RsaSigner {
fn from_signcert_and_pkey(
signcert: &[u8],
pkey: &[u8],
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> Result<Self> {
let signcerts = X509::stack_from_pem(signcert).map_err(wrap_openssl_err)?;
@@ -115,8 +115,8 @@ impl ConfigurableSigner for RsaSigner {
impl Signer for RsaSigner {
fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
- let mut signer = match self.alg.as_str() {
- "ps256" => {
+ let mut signer = match self.alg {
+ SigningAlg::Ps256 => {
let mut signer = openssl::sign::Signer::new(MessageDigest::sha256(), &self.pkey)
.map_err(wrap_openssl_err)?;
@@ -125,7 +125,7 @@ impl Signer for RsaSigner {
signer.set_rsa_pss_saltlen(openssl::sign::RsaPssSaltlen::DIGEST_LENGTH)?;
signer
}
- "ps384" => {
+ SigningAlg::Ps384 => {
let mut signer = openssl::sign::Signer::new(MessageDigest::sha384(), &self.pkey)
.map_err(wrap_openssl_err)?;
@@ -134,7 +134,7 @@ impl Signer for RsaSigner {
signer.set_rsa_pss_saltlen(openssl::sign::RsaPssSaltlen::DIGEST_LENGTH)?;
signer
}
- "ps512" => {
+ SigningAlg::Ps512 => {
let mut signer = openssl::sign::Signer::new(MessageDigest::sha512(), &self.pkey)
.map_err(wrap_openssl_err)?;
@@ -143,12 +143,12 @@ impl Signer for RsaSigner {
signer.set_rsa_pss_saltlen(openssl::sign::RsaPssSaltlen::DIGEST_LENGTH)?;
signer
}
- "rs256" => openssl::sign::Signer::new(MessageDigest::sha256(), &self.pkey)
- .map_err(wrap_openssl_err)?,
- "rs384" => openssl::sign::Signer::new(MessageDigest::sha384(), &self.pkey)
- .map_err(wrap_openssl_err)?,
- "rs512" => openssl::sign::Signer::new(MessageDigest::sha512(), &self.pkey)
- .map_err(wrap_openssl_err)?,
+ // "rs256" => openssl::sign::Signer::new(MessageDigest::sha256(), &self.pkey)
+ // .map_err(wrap_openssl_err)?,
+ // "rs384" => openssl::sign::Signer::new(MessageDigest::sha384(), &self.pkey)
+ // .map_err(wrap_openssl_err)?,
+ // "rs512" => openssl::sign::Signer::new(MessageDigest::sha512(), &self.pkey)
+ // .map_err(wrap_openssl_err)?,
_ => return Err(Error::UnsupportedType),
};
@@ -174,8 +174,8 @@ impl Signer for RsaSigner {
Ok(certs)
}
- fn alg(&self) -> Option<String> {
- Some(self.alg.to_owned())
+ fn alg(&self) -> SigningAlg {
+ self.alg
}
fn time_authority_url(&self) -> Option<String> {
@@ -214,7 +214,7 @@ mod tests {
use crate::{
utils::test::{fixture_path, temp_signer},
- Signer,
+ Signer, SigningAlg,
};
#[test]
@@ -233,7 +233,7 @@ mod tests {
let key_bytes = include_bytes!("../../tests/fixtures/temp_priv_key.data");
let signer =
- RsaSigner::from_signcert_and_pkey(cert_bytes, key_bytes, "ps256".to_string(), None)
+ RsaSigner::from_signcert_and_pkey(cert_bytes, key_bytes, SigningAlg::Ps256, None)
.unwrap();
let data = b"some sample content to sign";
@@ -243,19 +243,19 @@ mod tests {
assert!(signature.len() <= signer.reserve_size());
}
- #[test]
- fn sign_rs256() {
- let cert_bytes = include_bytes!("../../tests/fixtures/temp_cert.data");
- let key_bytes = include_bytes!("../../tests/fixtures/temp_priv_key.data");
+ // #[test]
+ // fn sign_rs256() {
+ // let cert_bytes = include_bytes!("../../tests/fixtures/temp_cert.data");
+ // let key_bytes = include_bytes!("../../tests/fixtures/temp_priv_key.data");
- let signer =
- RsaSigner::from_signcert_and_pkey(cert_bytes, key_bytes, "rs256".to_string(), None)
- .unwrap();
+ // let signer =
+ // RsaSigner::from_signcert_and_pkey(cert_bytes, key_bytes, "rs256".to_string(), None)
+ // .unwrap();
- let data = b"some sample content to sign";
+ // let data = b"some sample content to sign";
- let signature = signer.sign(data).unwrap();
- println!("signature len = {}", signature.len());
- assert!(signature.len() <= signer.reserve_size());
- }
+ // let signature = signer.sign(data).unwrap();
+ // println!("signature len = {}", signature.len());
+ // assert!(signature.len() <= signer.reserve_size());
+ // }
}
diff --git a/sdk/src/openssl/rsa_validator.rs b/sdk/src/openssl/rsa_validator.rs
@@ -11,18 +11,16 @@
// specific language governing permissions and limitations under
// each license.
-use crate::{validator::CoseValidator, Error, Result};
+use crate::{validator::CoseValidator, Error, Result, SigningAlg};
use openssl::{hash::MessageDigest, pkey::PKey, rsa::Rsa};
pub struct RsaValidator {
- alg: String,
+ alg: SigningAlg,
}
impl RsaValidator {
- pub fn new(alg: &str) -> Self {
- RsaValidator {
- alg: alg.to_owned(),
- }
+ pub fn new(alg: SigningAlg) -> Self {
+ RsaValidator { alg }
}
}
@@ -31,28 +29,28 @@ impl CoseValidator for RsaValidator {
let rsa = Rsa::public_key_from_der(pkey)?;
let pkey = PKey::from_rsa(rsa)?;
- let mut verifier = match self.alg.as_str() {
- "ps256" => {
+ let mut verifier = match self.alg {
+ SigningAlg::Ps256 => {
let mut verifier = openssl::sign::Verifier::new(MessageDigest::sha256(), &pkey)?;
verifier.set_rsa_padding(openssl::rsa::Padding::PKCS1_PSS)?; // use C2PA recommended padding
verifier.set_rsa_mgf1_md(MessageDigest::sha256())?;
verifier
}
- "ps384" => {
+ SigningAlg::Ps384 => {
let mut verifier = openssl::sign::Verifier::new(MessageDigest::sha384(), &pkey)?;
verifier.set_rsa_padding(openssl::rsa::Padding::PKCS1_PSS)?; // use C2PA recommended padding
verifier.set_rsa_mgf1_md(MessageDigest::sha384())?;
verifier
}
- "ps512" => {
+ SigningAlg::Ps512 => {
let mut verifier = openssl::sign::Verifier::new(MessageDigest::sha512(), &pkey)?;
verifier.set_rsa_padding(openssl::rsa::Padding::PKCS1_PSS)?; // use C2PA recommended padding
verifier.set_rsa_mgf1_md(MessageDigest::sha512())?;
verifier
}
- "rs256" => openssl::sign::Verifier::new(MessageDigest::sha256(), &pkey)?,
- "rs384" => openssl::sign::Verifier::new(MessageDigest::sha384(), &pkey)?,
- "rs512" => openssl::sign::Verifier::new(MessageDigest::sha512(), &pkey)?,
+ // "rs256" => openssl::sign::Verifier::new(MessageDigest::sha256(), &pkey)?,
+ // "rs384" => openssl::sign::Verifier::new(MessageDigest::sha384(), &pkey)?,
+ // "rs512" => openssl::sign::Verifier::new(MessageDigest::sha512(), &pkey)?,
_ => return Err(Error::UnsupportedType),
};
@@ -68,7 +66,7 @@ mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
- use crate::{signer::ConfigurableSigner, Signer};
+ use crate::{signer::ConfigurableSigner, Signer, SigningAlg};
#[test]
fn verify_rsa_signatures() {
@@ -80,88 +78,88 @@ mod tests {
let data = b"some sample content to sign";
- println!("Test RS256");
- let mut signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
- cert_bytes,
- key_bytes,
- "rs256".to_string(),
- None,
- )
- .unwrap();
-
- let mut signature = signer.sign(data).unwrap();
- println!("signature len = {}", signature.len());
- let mut validator = RsaValidator::new("rs256");
- assert!(validator.validate(&signature, data, &pkey).unwrap());
-
- println!("Test RS384");
- signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
- cert_bytes,
- key_bytes,
- "rs384".to_string(),
- None,
- )
- .unwrap();
-
- signature = signer.sign(data).unwrap();
- println!("signature len = {}", signature.len());
- validator = RsaValidator::new("rs384");
- assert!(validator.validate(&signature, data, &pkey).unwrap());
-
- println!("Test RS512");
- signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
- cert_bytes,
- key_bytes,
- "rs512".to_string(),
- None,
- )
- .unwrap();
-
- signature = signer.sign(data).unwrap();
- println!("signature len = {}", signature.len());
- validator = RsaValidator::new("rs512");
- assert!(validator.validate(&signature, data, &pkey).unwrap());
+ // println!("Test RS256");
+ // let mut signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
+ // cert_bytes,
+ // key_bytes,
+ // "rs256".to_string(),
+ // None,
+ // )
+ // .unwrap();
+
+ // let mut signature = signer.sign(data).unwrap();
+ // println!("signature len = {}", signature.len());
+ // let mut validator = RsaValidator::new("rs256");
+ // assert!(validator.validate(&signature, data, &pkey).unwrap());
+
+ // println!("Test RS384");
+ // signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
+ // cert_bytes,
+ // key_bytes,
+ // "rs384".to_string(),
+ // None,
+ // )
+ // .unwrap();
+
+ // signature = signer.sign(data).unwrap();
+ // println!("signature len = {}", signature.len());
+ // validator = RsaValidator::new("rs384");
+ // assert!(validator.validate(&signature, data, &pkey).unwrap());
+
+ // println!("Test RS512");
+ // signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
+ // cert_bytes,
+ // key_bytes,
+ // "rs512".to_string(),
+ // None,
+ // )
+ // .unwrap();
+
+ // signature = signer.sign(data).unwrap();
+ // println!("signature len = {}", signature.len());
+ // validator = RsaValidator::new("rs512");
+ // assert!(validator.validate(&signature, data, &pkey).unwrap());
println!("Test PS256");
- signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
+ let mut signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
cert_bytes,
key_bytes,
- "ps256".to_string(),
+ SigningAlg::Ps256,
None,
)
.unwrap();
- signature = signer.sign(data).unwrap();
+ let mut signature = signer.sign(data).unwrap();
println!("signature len = {}", signature.len());
- validator = RsaValidator::new("ps256");
+ let mut validator = RsaValidator::new(SigningAlg::Ps256);
assert!(validator.validate(&signature, data, &pkey).unwrap());
println!("Test PS384");
signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
cert_bytes,
key_bytes,
- "ps384".to_string(),
+ SigningAlg::Ps384,
None,
)
.unwrap();
signature = signer.sign(data).unwrap();
println!("signature len = {}", signature.len());
- validator = RsaValidator::new("ps384");
+ validator = RsaValidator::new(SigningAlg::Ps384);
assert!(validator.validate(&signature, data, &pkey).unwrap());
println!("Test PS512");
signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
cert_bytes,
key_bytes,
- "ps512".to_string(),
+ SigningAlg::Ps512,
None,
)
.unwrap();
signature = signer.sign(data).unwrap();
println!("signature len = {}", signature.len());
- validator = RsaValidator::new("ps512");
+ validator = RsaValidator::new(SigningAlg::Ps512);
assert!(validator.validate(&signature, data, &pkey).unwrap());
}
}
diff --git a/sdk/src/openssl/temp_signer.rs b/sdk/src/openssl/temp_signer.rs
@@ -36,6 +36,7 @@ use std::path::{Path, PathBuf};
use crate::{
openssl::{EcSigner, EdSigner, RsaSigner},
signer::ConfigurableSigner,
+ SigningAlg,
};
/// Create an OpenSSL ES256 signer that can be used for testing purposes.
@@ -44,7 +45,7 @@ use crate::{
///
/// * `path` - A directory (which must already exist) to receive the temporary
/// private key / certificate pair.
-/// * `alg` - A format for signing. Must be one of (`es256`, `es384`, or `es512`).
+/// * `alg` - A format for signing. Must be one of the `SigningAlg::Es*` variants.
/// * `tsa_url` - Optional URL for a timestamp authority.
///
/// # Returns
@@ -58,26 +59,26 @@ use crate::{
/// Can panic if unable to invoke OpenSSL executable properly.
pub fn get_ec_signer<P: AsRef<Path>>(
path: P,
- alg: &str,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> (EcSigner, PathBuf) {
match alg {
- "es256" | "es384" | "es512" => (),
+ SigningAlg::Es256 | SigningAlg::Es384 | SigningAlg::Es512 => (),
_ => {
panic!("Unknown EC signer alg {:#?}", alg);
}
}
let mut sign_cert_path = path.as_ref().to_path_buf();
- sign_cert_path.push(alg);
+ sign_cert_path.push(alg.to_string());
sign_cert_path.set_extension("pub");
let mut pem_key_path = path.as_ref().to_path_buf();
- pem_key_path.push(alg);
+ pem_key_path.push(alg.to_string());
pem_key_path.set_extension("pem");
(
- EcSigner::from_files(&sign_cert_path, &pem_key_path, alg.to_string(), tsa_url).unwrap(),
+ EcSigner::from_files(&sign_cert_path, &pem_key_path, alg, tsa_url).unwrap(),
sign_cert_path,
)
}
@@ -102,23 +103,23 @@ pub fn get_ec_signer<P: AsRef<Path>>(
/// Can panic if unable to invoke OpenSSL executable properly.
pub fn get_ed_signer<P: AsRef<Path>>(
path: P,
- alg: &str,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> (EdSigner, PathBuf) {
- if alg != "ed25519" {
+ if alg != SigningAlg::Ed25519 {
panic!("Unknown ED signer alg {:#?}", alg);
}
let mut sign_cert_path = path.as_ref().to_path_buf();
- sign_cert_path.push(alg);
+ sign_cert_path.push(alg.to_string());
sign_cert_path.set_extension("pub");
let mut pem_key_path = path.as_ref().to_path_buf();
- pem_key_path.push(alg);
+ pem_key_path.push(alg.to_string());
pem_key_path.set_extension("pem");
(
- EdSigner::from_files(&sign_cert_path, &pem_key_path, alg.to_string(), tsa_url).unwrap(),
+ EdSigner::from_files(&sign_cert_path, &pem_key_path, alg, tsa_url).unwrap(),
sign_cert_path,
)
}
@@ -129,8 +130,7 @@ pub fn get_ed_signer<P: AsRef<Path>>(
///
/// * `path` - A directory (which must already exist) to receive the temporary
/// private key / certificate pair.
-/// * `alg` - A format for signing. Must be one of (`rs256`, `rs384`, `rs512`,
-/// `ps256`, `ps384`, or `ps512`).
+/// * `alg` - A format for signing. Must be one of the `SignerAlg::Ps*` options.
/// * `tsa_url` - Optional URL for a timestamp authority.
///
/// # Returns
@@ -144,22 +144,22 @@ pub fn get_ed_signer<P: AsRef<Path>>(
/// Can panic if unable to invoke OpenSSL executable properly.
pub fn get_rsa_signer<P: AsRef<Path>>(
path: P,
- alg: &str,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> (RsaSigner, PathBuf) {
match alg {
- "ps256" | "ps384" | "ps512" => (),
+ SigningAlg::Ps256 | SigningAlg::Ps384 | SigningAlg::Ps512 => (),
_ => {
panic!("Unknown RSA signer alg {:#?}", alg);
}
}
let mut sign_cert_path = path.as_ref().to_path_buf();
- sign_cert_path.push(alg);
+ sign_cert_path.push(alg.to_string());
sign_cert_path.set_extension("pub");
let mut pem_key_path = path.as_ref().to_path_buf();
- pem_key_path.push(alg);
+ pem_key_path.push(alg.to_string());
pem_key_path.set_extension("pem");
if !sign_cert_path.exists() || !pem_key_path.exists() {
@@ -171,7 +171,7 @@ pub fn get_rsa_signer<P: AsRef<Path>>(
}
(
- RsaSigner::from_files(&sign_cert_path, &pem_key_path, alg.to_string(), tsa_url).unwrap(),
+ RsaSigner::from_files(&sign_cert_path, &pem_key_path, alg, tsa_url).unwrap(),
sign_cert_path,
)
}
diff --git a/sdk/src/openssl/temp_signer_async.rs b/sdk/src/openssl/temp_signer_async.rs
@@ -19,33 +19,31 @@
//! the asynchronous signing of claims.
//! This module should be used only for testing purposes.
+use crate::SigningAlg;
+
#[cfg(feature = "async_signer")]
-fn get_local_signer(alg: &str) -> Box<dyn crate::Signer> {
+fn get_local_signer(alg: SigningAlg) -> Box<dyn crate::Signer> {
let cert_dir = crate::utils::test::fixture_path("certs");
match alg {
- "ps256" | "ps384" | "ps512" => {
+ SigningAlg::Ps256 | SigningAlg::Ps384 | SigningAlg::Ps512 => {
let (s, _k) = super::temp_signer::get_rsa_signer(&cert_dir, alg, None);
Box::new(s)
}
- "es256" | "es384" | "es512" => {
+ SigningAlg::Es256 | SigningAlg::Es384 | SigningAlg::Es512 => {
let (s, _k) = super::temp_signer::get_ec_signer(&cert_dir, alg, None);
Box::new(s)
}
- "ed25519" => {
+ SigningAlg::Ed25519 => {
let (s, _k) = super::temp_signer::get_ed_signer(&cert_dir, alg, None);
Box::new(s)
}
- _ => {
- let (s, _k) = super::temp_signer::get_rsa_signer(&cert_dir, "ps256", None);
- Box::new(s)
- }
}
}
#[cfg(feature = "async_signer")]
pub struct AsyncSignerAdapter {
- alg: String,
+ alg: SigningAlg,
certs: Vec<Vec<u8>>,
reserve_size: usize,
tsa_url: Option<String>,
@@ -54,8 +52,8 @@ pub struct AsyncSignerAdapter {
#[cfg(feature = "async_signer")]
impl AsyncSignerAdapter {
- pub fn new(alg: String) -> Self {
- let signer = get_local_signer(&alg);
+ pub fn new(alg: SigningAlg) -> Self {
+ let signer = get_local_signer(alg);
AsyncSignerAdapter {
alg,
@@ -72,12 +70,12 @@ impl AsyncSignerAdapter {
#[async_trait::async_trait]
impl crate::AsyncSigner for AsyncSignerAdapter {
async fn sign(&self, data: Vec<u8>) -> crate::error::Result<Vec<u8>> {
- let signer = get_local_signer(&self.alg);
+ let signer = get_local_signer(self.alg);
signer.sign(&data)
}
- fn alg(&self) -> Option<String> {
- Some(self.alg.clone())
+ fn alg(&self) -> SigningAlg {
+ self.alg
}
fn certs(&self) -> crate::Result<Vec<Vec<u8>>> {
diff --git a/sdk/src/signer.rs b/sdk/src/signer.rs
@@ -11,7 +11,7 @@
// specific language governing permissions and limitations under
// each license.
-use crate::Result;
+use crate::{Result, SigningAlg};
/// The `Signer` trait generates a cryptographic signature over a byte array.
///
@@ -21,7 +21,7 @@ pub trait Signer {
fn sign(&self, data: &[u8]) -> Result<Vec<u8>>;
/// Returns the algorithm of the Signer.
- fn alg(&self) -> Option<String>;
+ fn alg(&self) -> SigningAlg;
/// Returns the certificates as a Vec containing a Vec of DER bytes for each certificate.
fn certs(&self) -> Result<Vec<Vec<u8>>>;
@@ -51,7 +51,7 @@ pub(crate) trait ConfigurableSigner: Signer + Sized {
fn from_files<P: AsRef<std::path::Path>>(
signcert_path: P,
pkey_path: P,
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> Result<Self>;
@@ -59,7 +59,7 @@ pub(crate) trait ConfigurableSigner: Signer + Sized {
fn from_signcert_and_pkey(
signcert: &[u8],
pkey: &[u8],
- alg: String,
+ alg: SigningAlg,
tsa_url: Option<String>,
) -> Result<Self>;
}
@@ -79,7 +79,7 @@ pub trait AsyncSigner: Sync {
async fn sign(&self, data: Vec<u8>) -> Result<Vec<u8>>;
/// Returns the algorithm of the Signer.
- fn alg(&self) -> Option<String>;
+ fn alg(&self) -> SigningAlg;
/// Returns the certificates as a Vec containing a Vec of DER bytes for each certificate.
fn certs(&self) -> Result<Vec<Vec<u8>>>;
diff --git a/sdk/src/signing_alg.rs b/sdk/src/signing_alg.rs
@@ -0,0 +1,139 @@
+// Copyright 2022 Adobe. All rights reserved.
+// This file is licensed to you under the Apache License,
+// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+// or the MIT license (http://opensource.org/licenses/MIT),
+// at your option.
+
+// Unless required by applicable law or agreed to in writing,
+// this software is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
+// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
+// specific language governing permissions and limitations under
+// each license.
+
+#![deny(missing_docs)]
+
+use std::{fmt, str::FromStr};
+
+/// Describes the digital signature algorithms allowed by the C2PA spec.
+///
+/// Per <https://c2pa.org/specifications/specifications/1.0/specs/C2PA_Specification.html#_digital_signatures>:
+///
+/// > All digital signatures that are stored in a C2PA Manifest shall
+/// > be generated using one of the digital signature algorithms and
+/// > key types listed as described in this section.
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum SigningAlg {
+ /// ECDSA with SHA-256
+ Es256,
+
+ /// ECDSA with SHA-384
+ Es384,
+
+ /// ECDSA with SHA-512
+ Es512,
+
+ /// RSASSA-PSS using SHA-256 and MGF1 with SHA-256
+ Ps256,
+
+ /// RSASSA-PSS using SHA-384 and MGF1 with SHA-384
+ Ps384,
+
+ /// RSASSA-PSS using SHA-512 and MGF1 with SHA-512
+ Ps512,
+
+ /// Edwards-Curve DSA (Ed25519 instance only)
+ Ed25519,
+}
+
+impl FromStr for SigningAlg {
+ type Err = UnknownAlgorithmError;
+
+ fn from_str(alg: &str) -> Result<Self, Self::Err> {
+ match alg {
+ "es256" => Ok(Self::Es256),
+ "es384" => Ok(Self::Es384),
+ "es512" => Ok(Self::Es512),
+ "ps256" => Ok(Self::Ps256),
+ "ps384" => Ok(Self::Ps384),
+ "ps512" => Ok(Self::Ps512),
+ "ed25519" => Ok(Self::Ed25519),
+ _ => Err(UnknownAlgorithmError(alg.to_owned())),
+ }
+ }
+}
+
+impl fmt::Display for SigningAlg {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ write!(
+ f,
+ "{}",
+ match self {
+ Self::Es256 => "es256",
+ Self::Es384 => "es384",
+ Self::Es512 => "es512",
+ Self::Ps256 => "ps256",
+ Self::Ps384 => "ps384",
+ Self::Ps512 => "ps512",
+ Self::Ed25519 => "ed25519",
+ }
+ )
+ }
+}
+
+#[derive(Debug, PartialEq)]
+/// This error is thrown when converting from a string to [`SigningAlg`]
+/// if the algorithm string is unrecognized.
+///
+/// The string must be one of "es256", "es384", "es512", "ps256", "ps384",
+/// "ps512", or "ed25519".
+pub struct UnknownAlgorithmError(String);
+
+impl fmt::Display for UnknownAlgorithmError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ write!(f, "UnknownAlgorithmError({})", self.0)
+ }
+}
+
+impl std::error::Error for UnknownAlgorithmError {}
+
+#[cfg(test)]
+mod tests {
+ #![allow(clippy::expect_used)]
+ #![allow(clippy::unwrap_used)]
+
+ use super::*;
+
+ #[test]
+ fn alg_from_str() {
+ assert_eq!("es256".parse(), Ok(SigningAlg::Es256));
+ assert_eq!("es384".parse(), Ok(SigningAlg::Es384));
+ assert_eq!("es512".parse(), Ok(SigningAlg::Es512));
+ assert_eq!("ps256".parse(), Ok(SigningAlg::Ps256));
+ assert_eq!("ps384".parse(), Ok(SigningAlg::Ps384));
+ assert_eq!("ps512".parse(), Ok(SigningAlg::Ps512));
+ assert_eq!("ed25519".parse(), Ok(SigningAlg::Ed25519));
+
+ let r: Result<SigningAlg, UnknownAlgorithmError> = "bogus".parse();
+ assert_eq!(r, Err(UnknownAlgorithmError("bogus".to_string())));
+ }
+
+ #[test]
+ fn signing_alg_impl_display() {
+ assert_eq!(format!("{}", SigningAlg::Es256), "es256");
+ assert_eq!(format!("{}", SigningAlg::Es384), "es384");
+ assert_eq!(format!("{}", SigningAlg::Es512), "es512");
+ assert_eq!(format!("{}", SigningAlg::Ps256), "ps256");
+ assert_eq!(format!("{}", SigningAlg::Ps384), "ps384");
+ assert_eq!(format!("{}", SigningAlg::Ps512), "ps512");
+ assert_eq!(format!("{}", SigningAlg::Ed25519), "ed25519");
+ }
+
+ #[test]
+ fn err_impl_display() {
+ assert_eq!(
+ format!("{}", UnknownAlgorithmError("bogus".to_owned())),
+ "UnknownAlgorithmError(bogus)"
+ );
+ }
+}
diff --git a/sdk/src/store.rs b/sdk/src/store.rs
@@ -1928,6 +1928,7 @@ pub mod tests {
create_test_claim, fixture_path, temp_dir_path, temp_fixture_path, temp_signer,
},
},
+ SigningAlg,
};
fn create_editing_claim(claim: &mut Claim) -> Result<&mut Claim> {
@@ -2074,8 +2075,8 @@ pub mod tests {
Ok(b"not a valid signature".to_vec())
}
- fn alg(&self) -> Option<String> {
- None
+ fn alg(&self) -> SigningAlg {
+ SigningAlg::Ps256
}
fn certs(&self) -> Result<Vec<Vec<u8>>> {
@@ -2114,7 +2115,7 @@ pub mod tests {
#[test]
#[cfg(feature = "file_io")]
fn test_sign_with_expired_cert() {
- use crate::{openssl::RsaSigner, signer::ConfigurableSigner};
+ use crate::{openssl::RsaSigner, signer::ConfigurableSigner, SigningAlg};
// test adding to actual image
let ap = fixture_path("earth_apollo17.jpg");
@@ -2128,7 +2129,7 @@ pub mod tests {
let signcert_path = fixture_path("rsa-pss256_key-expired.pub");
let pkey_path = fixture_path("rsa-pss256-expired.pem");
let signer =
- RsaSigner::from_files(signcert_path, pkey_path, "ps256".to_string(), None).unwrap();
+ RsaSigner::from_files(signcert_path, pkey_path, SigningAlg::Ps256, None).unwrap();
store.commit_claim(claim).unwrap();
@@ -2176,8 +2177,7 @@ pub mod tests {
#[cfg(feature = "async_signer")]
#[actix::test]
async fn test_jumbf_generation_async() {
- let signer =
- crate::openssl::temp_signer_async::AsyncSignerAdapter::new("ps256".to_string());
+ let signer = crate::openssl::temp_signer_async::AsyncSignerAdapter::new(SigningAlg::Ps256);
// test adding to actual image
let ap = fixture_path("earth_apollo17.jpg");
diff --git a/sdk/src/time_stamp.rs b/sdk/src/time_stamp.rs
@@ -22,6 +22,7 @@ use crate::error::{Error, Result};
use crate::hash_utils::vec_compare;
use crate::asn1::rfc3161::{TimeStampResp, TstInfo, OID_CONTENT_TYPE_TST_INFO};
+use crate::SigningAlg;
use bcder::decode::Constructed;
use x509_certificate::DigestAlgorithm::{self};
@@ -29,32 +30,29 @@ use x509_certificate::DigestAlgorithm::{self};
use coset::{iana, sig_structure_data, HeaderBuilder, ProtectedHeader};
#[allow(dead_code)]
-pub(crate) fn cose_countersign_data(data: &[u8], alg: &str) -> Vec<u8> {
+pub(crate) fn cose_countersign_data(data: &[u8], alg: SigningAlg) -> Vec<u8> {
let alg_id = match alg {
- "ps256" => HeaderBuilder::new()
+ SigningAlg::Ps256 => HeaderBuilder::new()
.algorithm(iana::Algorithm::PS256)
.build(),
- "ps384" => HeaderBuilder::new()
+ SigningAlg::Ps384 => HeaderBuilder::new()
.algorithm(iana::Algorithm::PS384)
.build(),
- "ps512" => HeaderBuilder::new()
+ SigningAlg::Ps512 => HeaderBuilder::new()
.algorithm(iana::Algorithm::PS512)
.build(),
- "es256" => HeaderBuilder::new()
+ SigningAlg::Es256 => HeaderBuilder::new()
.algorithm(iana::Algorithm::ES256)
.build(),
- "es384" => HeaderBuilder::new()
+ SigningAlg::Es384 => HeaderBuilder::new()
.algorithm(iana::Algorithm::ES384)
.build(),
- "es512" => HeaderBuilder::new()
+ SigningAlg::Es512 => HeaderBuilder::new()
.algorithm(iana::Algorithm::ES512)
.build(),
- "ed25519" => HeaderBuilder::new()
+ SigningAlg::Ed25519 => HeaderBuilder::new()
.algorithm(iana::Algorithm::EdDSA)
.build(),
- _ => HeaderBuilder::new()
- .algorithm(iana::Algorithm::PS256)
- .build(),
};
let p_header = ProtectedHeader {
@@ -74,7 +72,11 @@ pub(crate) fn cose_countersign_data(data: &[u8], alg: &str) -> Vec<u8> {
}
#[allow(dead_code)]
-pub(crate) fn cose_timestamp_countersign(data: &[u8], alg: &str, tsa_url: &str) -> Result<Vec<u8>> {
+pub(crate) fn cose_timestamp_countersign(
+ data: &[u8],
+ alg: SigningAlg,
+ tsa_url: &str,
+) -> Result<Vec<u8>> {
// create countersignature with TimeStampReq parameters
// payload: data
// context "CounterSigner"
@@ -91,7 +93,7 @@ pub(crate) fn cose_timestamp_countersign(data: &[u8], alg: &str, tsa_url: &str)
pub(crate) fn cose_sigtst_to_tstinfos(
sigtst_cbor: &[u8],
data: &[u8],
- alg: &str,
+ alg: SigningAlg,
) -> Result<Vec<TstInfo>> {
let tst_container: TstContainer =
serde_cbor::from_slice(sigtst_cbor).map_err(|_err| Error::CoseTimeStampGeneration)?;
diff --git a/sdk/src/utils/test.rs b/sdk/src/utils/test.rs
@@ -26,6 +26,7 @@ use crate::{
create_signer,
openssl::RsaSigner,
signer::{ConfigurableSigner, Signer},
+ SigningAlg,
};
use std::path::PathBuf;
@@ -205,15 +206,12 @@ pub fn temp_signer() -> RsaSigner {
pem_key_path.push("ps256");
pem_key_path.set_extension("pem");
- RsaSigner::from_files(&sign_cert_path, &pem_key_path, "ps256".to_string(), None)
+ RsaSigner::from_files(&sign_cert_path, &pem_key_path, SigningAlg::Ps256, None)
.expect("get_temp_signer")
}
/// Create a [`Signer`] instance for a specific algorithm that can be used for testing purposes.
///
-/// # Parameters:
-/// alg: The algorithm to use
-///
/// # Returns
///
/// Returns a boxed [`Signer`] instance.
@@ -223,15 +221,15 @@ pub fn temp_signer() -> RsaSigner {
/// Can panic if the certs cannot be read. (This function should only
/// be used as part of testing infrastructure.)
#[cfg(feature = "file_io")]
-pub fn temp_signer_with_alg(alg: &str) -> Box<dyn Signer> {
+pub fn temp_signer_with_alg(alg: SigningAlg) -> Box<dyn Signer> {
#![allow(clippy::expect_used)]
// sign and embed into the target file
let mut sign_cert_path = fixture_path("certs");
- sign_cert_path.push(alg);
+ sign_cert_path.push(alg.to_string());
sign_cert_path.set_extension("pub");
let mut pem_key_path = fixture_path("certs");
- pem_key_path.push(alg);
+ pem_key_path.push(alg.to_string());
pem_key_path.set_extension("pem");
create_signer::from_files(sign_cert_path.clone(), pem_key_path, alg, None)
diff --git a/sdk/src/validator.rs b/sdk/src/validator.rs
@@ -13,29 +13,18 @@
#[cfg(feature = "file_io")]
use crate::openssl::{EcValidator, EdValidator, RsaValidator};
-use crate::Result;
+use crate::{Result, SigningAlg};
use chrono::{DateTime, Utc};
-#[derive(Debug)]
+#[derive(Debug, Default)]
pub struct ValidationInfo {
- pub alg: String, // validation algorithm
+ pub alg: Option<SigningAlg>, // validation algorithm
pub date: Option<DateTime<Utc>>,
pub issuer_org: Option<String>,
pub validated: bool, // claim signature is valid
}
-impl Default for ValidationInfo {
- fn default() -> Self {
- ValidationInfo {
- alg: "".to_owned(),
- date: None,
- issuer_org: None,
- validated: false,
- }
- }
-}
-
/// Trait to support validating a signature against the provided data
pub(crate) trait CoseValidator {
/// validate signature "sig" for given "data using provided public key"
@@ -64,19 +53,18 @@ impl CoseValidator for DummyValidator {
/// return validator for supported C2PA algorthms
#[cfg(feature = "file_io")]
-pub(crate) fn get_validator(alg: &str) -> Option<Box<dyn CoseValidator>> {
- match alg.to_lowercase().as_str() {
- "es256" => Some(Box::new(EcValidator::new("es256"))),
- "es384" => Some(Box::new(EcValidator::new("es384"))),
- "es512" => Some(Box::new(EcValidator::new("es512"))),
- "ps256" => Some(Box::new(RsaValidator::new("ps256"))),
- "ps384" => Some(Box::new(RsaValidator::new("ps384"))),
- "ps512" => Some(Box::new(RsaValidator::new("ps512"))),
- "rs256" => Some(Box::new(RsaValidator::new("rs256"))),
- "rs384" => Some(Box::new(RsaValidator::new("rs384"))),
- "rs512" => Some(Box::new(RsaValidator::new("rs512"))),
- "ed25519" => Some(Box::new(EdValidator::new("ed25519"))),
- _ => None,
+pub(crate) fn get_validator(alg: SigningAlg) -> Box<dyn CoseValidator> {
+ match alg {
+ SigningAlg::Es256 | SigningAlg::Es384 | SigningAlg::Es512 => {
+ Box::new(EcValidator::new(alg))
+ }
+ SigningAlg::Ps256 | SigningAlg::Ps384 | SigningAlg::Ps512 => {
+ Box::new(RsaValidator::new(alg))
+ }
+ // "rs256" => Some(Box::new(RsaValidator::new("rs256"))),
+ // "rs384" => Some(Box::new(RsaValidator::new("rs384"))),
+ // "rs512" => Some(Box::new(RsaValidator::new("rs512"))),
+ SigningAlg::Ed25519 => Box::new(EdValidator::new(alg)),
}
}
diff --git a/sdk/src/wasm/webcrypto_validator.rs b/sdk/src/wasm/webcrypto_validator.rs
@@ -11,18 +11,21 @@
// specific language governing permissions and limitations under
// each license.
-use crate::utils::hash_utils::hash_by_alg;
-use crate::wasm::context::WindowOrWorker;
-use crate::{Error, Result};
+use std::convert::TryFrom;
+
use js_sys::{Array, ArrayBuffer, Object, Reflect, Uint8Array};
use rsa::{BigUint, PaddingScheme, PublicKey, RsaPublicKey};
use sha2::{Sha256, Sha384, Sha512};
use spki::SubjectPublicKeyInfo;
-use std::convert::TryFrom;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::JsFuture;
use web_sys::{CryptoKey, SubtleCrypto};
use x509_parser::der_parser::ber::{parse_ber_sequence, BerObject};
+
+use crate::{
+ utils::hash_utils::hash_by_alg, wasm::context::WindowOrWorker, Error, Result, SigningAlg,
+};
+
pub struct EcKeyImportParams {
name: String,
named_curve: String,
@@ -204,14 +207,11 @@ async fn async_validate(
}
}
-pub async fn validate_async(alg: &str, sig: &[u8], data: &[u8], pkey: &[u8]) -> Result<bool> {
- web_sys::console::debug_2(
- &"Validating with algorithm".into(),
- &String::from(alg).into(),
- );
+pub async fn validate_async(alg: SigningAlg, sig: &[u8], data: &[u8], pkey: &[u8]) -> Result<bool> {
+ web_sys::console::debug_2(&"Validating with algorithm".into(), &alg.to_string().into());
match alg {
- "ps256" => {
+ SigningAlg::Ps256 => {
async_validate(
"RSA-PSS".to_string(),
"SHA-256".to_string(),
@@ -222,7 +222,7 @@ pub async fn validate_async(alg: &str, sig: &[u8], data: &[u8], pkey: &[u8]) ->
)
.await
}
- "ps384" => {
+ SigningAlg::Ps384 => {
async_validate(
"RSA-PSS".to_string(),
"SHA-384".to_string(),
@@ -233,7 +233,7 @@ pub async fn validate_async(alg: &str, sig: &[u8], data: &[u8], pkey: &[u8]) ->
)
.await
}
- "ps512" => {
+ SigningAlg::Ps512 => {
async_validate(
"RSA-PSS".to_string(),
"SHA-512".to_string(),
@@ -244,7 +244,40 @@ pub async fn validate_async(alg: &str, sig: &[u8], data: &[u8], pkey: &[u8]) ->
)
.await
}
- "es256" => {
+ // "rs256" => {
+ // async_validate(
+ // "RSASSA-PKCS1-v1_5".to_string(),
+ // "SHA-256".to_string(),
+ // 0,
+ // pkey.to_vec(),
+ // sig.to_vec(),
+ // data.to_vec(),
+ // )
+ // .await
+ // }
+ // "rs384" => {
+ // async_validate(
+ // "RSASSA-PKCS1-v1_5".to_string(),
+ // "SHA-384".to_string(),
+ // 0,
+ // pkey.to_vec(),
+ // sig.to_vec(),
+ // data.to_vec(),
+ // )
+ // .await
+ // }
+ // "rs512" => {
+ // async_validate(
+ // "RSASSA-PKCS1-v1_5".to_string(),
+ // "SHA-512".to_string(),
+ // 0,
+ // pkey.to_vec(),
+ // sig.to_vec(),
+ // data.to_vec(),
+ // )
+ // .await
+ // }
+ SigningAlg::Es256 => {
async_validate(
"ECDSA".to_string(),
"SHA-256".to_string(),
@@ -255,7 +288,7 @@ pub async fn validate_async(alg: &str, sig: &[u8], data: &[u8], pkey: &[u8]) ->
)
.await
}
- "es384" => {
+ SigningAlg::Es384 => {
async_validate(
"ECDSA".to_string(),
"SHA-384".to_string(),
@@ -266,7 +299,7 @@ pub async fn validate_async(alg: &str, sig: &[u8], data: &[u8], pkey: &[u8]) ->
)
.await
}
- "es512" => {
+ SigningAlg::Es512 => {
async_validate(
"ECDSA".to_string(),
"SHA-512".to_string(),
@@ -277,6 +310,7 @@ pub async fn validate_async(alg: &str, sig: &[u8], data: &[u8], pkey: &[u8]) ->
)
.await
}
+ // TODO: Can we cover Ed25519?
_ => return Err(Error::UnsupportedType),
}
}
@@ -287,6 +321,8 @@ pub mod tests {
use super::*;
+ use crate::SigningAlg;
+
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;
@@ -302,7 +338,7 @@ pub mod tests {
let data_bytes = include_bytes!("../../tests/fixtures/data_ps256.data");
let key_bytes = include_bytes!("../../tests/fixtures/key_ps256.data");
- let validated = validate_async("ps256", sig_bytes, data_bytes, key_bytes)
+ let validated = validate_async(SigningAlg::Ps256, sig_bytes, data_bytes, key_bytes)
.await
.unwrap();
@@ -318,10 +354,14 @@ pub mod tests {
let data_es384_bytes = include_bytes!("../../tests/fixtures/data_es384.data");
let key_es384_bytes = include_bytes!("../../tests/fixtures/key_es384.data");
- let mut validated =
- validate_async("es384", sig_es384_bytes, data_es384_bytes, key_es384_bytes)
- .await
- .unwrap();
+ let mut validated = validate_async(
+ SigningAlg::Es384,
+ sig_es384_bytes,
+ data_es384_bytes,
+ key_es384_bytes,
+ )
+ .await
+ .unwrap();
assert_eq!(validated, true);
@@ -329,9 +369,14 @@ pub mod tests {
let data_es512_bytes = include_bytes!("../../tests/fixtures/data_es512.data");
let key_es512_bytes = include_bytes!("../../tests/fixtures/key_es512.data");
- validated = validate_async("es512", sig_es512_bytes, data_es512_bytes, key_es512_bytes)
- .await
- .unwrap();
+ validated = validate_async(
+ SigningAlg::Es512,
+ sig_es512_bytes,
+ data_es512_bytes,
+ key_es512_bytes,
+ )
+ .await
+ .unwrap();
assert_eq!(validated, true);
@@ -339,9 +384,14 @@ pub mod tests {
let data_es256_bytes = include_bytes!("../../tests/fixtures/data_es256.data");
let key_es256_bytes = include_bytes!("../../tests/fixtures/key_es256.data");
- let validated = validate_async("es256", sig_es256_bytes, data_es256_bytes, key_es256_bytes)
- .await
- .unwrap();
+ let validated = validate_async(
+ SigningAlg::Es256,
+ sig_es256_bytes,
+ data_es256_bytes,
+ key_es256_bytes,
+ )
+ .await
+ .unwrap();
assert_eq!(validated, true);
}
@@ -361,7 +411,7 @@ pub mod tests {
bad_bytes[2] = b'p';
bad_bytes[3] = b'a';
- let validated = validate_async("ps256", sig_bytes, &bad_bytes, key_bytes)
+ let validated = validate_async(SigningAlg::Ps256, sig_bytes, &bad_bytes, key_bytes)
.await
.unwrap();
diff --git a/sdk/tests/integration.rs b/sdk/tests/integration.rs
@@ -18,7 +18,7 @@ mod integration_1 {
use c2pa::{
assertions::{c2pa_action, Action, Actions},
- create_signer, Ingredient, Manifest, ManifestStore, Result, Signer,
+ create_signer, Ingredient, Manifest, ManifestStore, Result, Signer, SigningAlg,
};
use std::path::PathBuf;
use tempfile::tempdir;
@@ -31,7 +31,7 @@ mod integration_1 {
signcert_path.push("tests/fixtures/certs/ps256.pub");
let mut pkey_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
pkey_path.push("tests/fixtures/certs/ps256.pem");
- create_signer::from_files(signcert_path, pkey_path, "ps256", None)
+ create_signer::from_files(signcert_path, pkey_path, SigningAlg::Ps256, None)
.expect("get_signer_from_files")
}