-
Couldn't load subscription status.
- Fork 100
chore: Move c2pa::CoseValidator to c2pa_crypto::RawSignatureValidator
#683
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b11b39a
9c2fdd1
3640cce
095c75c
0e29d38
e32612c
53f0a1f
dce71ee
e7a0f24
e8f51a4
ed095cc
cb2af66
e121f4b
3410c19
2688f3d
fbed3bd
3cb30d0
825dab1
608227e
ec7b255
949fdc2
450b8d3
478fdbd
6852392
a078d0f
30bb623
5cae35d
df5f04c
a267e5c
c50e7b1
341a2d5
f213ab9
9ed67b7
7adf8c2
df219df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,3 +20,5 @@ | |
|
|
||
| mod ffi_mutex; | ||
| pub use ffi_mutex::{OpenSslMutex, OpenSslMutexUnavailable}; | ||
|
|
||
| pub mod validators; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| // 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. | ||
|
|
||
| use openssl::{ | ||
| bn::BigNum, ec::EcKey, ecdsa::EcdsaSig, hash::MessageDigest, pkey::PKey, sign::Verifier, | ||
| }; | ||
|
|
||
| use crate::{ | ||
| openssl::OpenSslMutex, | ||
| raw_signature::{RawSignatureValidationError, RawSignatureValidator}, | ||
| }; | ||
|
|
||
| /// An `EcdsaValidator` can validate raw signatures with one of the ECDSA | ||
| /// signature algorithms. | ||
| #[non_exhaustive] | ||
| pub enum EcdsaValidator { | ||
| /// ECDSA with SHA-256 | ||
| Es256, | ||
|
|
||
| /// ECDSA with SHA-384 | ||
| Es384, | ||
|
|
||
| /// ECDSA with SHA-512 | ||
| Es512, | ||
| } | ||
|
|
||
| impl RawSignatureValidator for EcdsaValidator { | ||
| fn validate( | ||
| &self, | ||
| sig: &[u8], | ||
| data: &[u8], | ||
| public_key: &[u8], | ||
| ) -> Result<(), RawSignatureValidationError> { | ||
| let _openssl = OpenSslMutex::acquire()?; | ||
|
|
||
| let public_key = EcKey::public_key_from_der(public_key)?; | ||
| let key = PKey::from_ec_key(public_key)?; | ||
|
|
||
| let mut verifier = match self { | ||
| Self::Es256 => Verifier::new(MessageDigest::sha256(), &key)?, | ||
| Self::Es384 => Verifier::new(MessageDigest::sha384(), &key)?, | ||
| Self::Es512 => Verifier::new(MessageDigest::sha512(), &key)?, | ||
| }; | ||
|
|
||
| // We may need to convert a P1363 signature to a DER signature if the signature | ||
| // matches one of the expected P1363 signature sizes. | ||
| let is_p1363 = match self { | ||
| Self::Es256 => sig.len() == 64, | ||
| Self::Es384 => sig.len() == 96, | ||
| Self::Es512 => sig.len() == 132, | ||
| }; | ||
|
|
||
| let sig_der = if is_p1363 { | ||
| // Convert P1363 signature to DER signature. | ||
| let sig_len = sig.len() / 2; | ||
|
|
||
| let r = BigNum::from_slice(&sig[0..sig_len])?; | ||
| let s = BigNum::from_slice(&sig[sig_len..])?; | ||
| EcdsaSig::from_private_components(r, s)?.to_der()? | ||
| } else { | ||
| sig.to_vec() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mauricefisher64 do you know of a case where the signature is not encoded as P1363? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OpenSSL/AWS KMS/X509 certs use DER. Web standards and Cose/C2PA use P1363 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So when we sign with OpenSSL or we are checking certificates the values are DER. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mauricefisher64 reason I'm asking is that the unit test framework isn't generating coverage for line 70 (the DER case) so I'm looking for sample data that would exercise that case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is you sign something with straight OpenSSL it will be a DER signature. You can't use a signature that came from Cose because it will be in the other format. |
||
| }; | ||
|
|
||
| verifier.update(data)?; | ||
|
|
||
| if verifier.verify(&sig_der)? { | ||
| Ok(()) | ||
| } else { | ||
| Err(RawSignatureValidationError::SignatureMismatch) | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| // 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. | ||
|
|
||
| use openssl::{pkey::PKey, sign::Verifier}; | ||
|
|
||
| use crate::{ | ||
| openssl::OpenSslMutex, | ||
| raw_signature::{RawSignatureValidationError, RawSignatureValidator}, | ||
| }; | ||
|
|
||
| /// An `Ed25519Validator` can validate raw signatures with the Ed25519 signature | ||
| /// algorithm. | ||
| pub struct Ed25519Validator {} | ||
|
|
||
| impl RawSignatureValidator for Ed25519Validator { | ||
| fn validate( | ||
| &self, | ||
| sig: &[u8], | ||
| data: &[u8], | ||
| public_key: &[u8], | ||
| ) -> Result<(), RawSignatureValidationError> { | ||
| let _openssl = OpenSslMutex::acquire()?; | ||
|
|
||
| let public_key = PKey::public_key_from_der(public_key)?; | ||
|
|
||
| if Verifier::new_without_digest(&public_key)?.verify_oneshot(sig, data)? { | ||
| Ok(()) | ||
| } else { | ||
| Err(RawSignatureValidationError::SignatureMismatch) | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| // Copyright 2024 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. | ||
|
|
||
| //! This module binds OpenSSL logic for validating raw signatures to this | ||
| //! crate's [`RawSignatureValidator`] trait. | ||
|
|
||
| use bcder::Oid; | ||
|
|
||
| use crate::{ | ||
| raw_signature::{oids::*, RawSignatureValidator}, | ||
| SigningAlg, | ||
| }; | ||
|
|
||
| mod ecdsa_validator; | ||
| pub use ecdsa_validator::EcdsaValidator; | ||
|
|
||
| mod ed25519_validator; | ||
| pub use ed25519_validator::Ed25519Validator; | ||
|
|
||
| mod rsa_legacy_validator; | ||
| pub(crate) use rsa_legacy_validator::RsaLegacyValidator; | ||
|
|
||
| mod rsa_validator; | ||
| pub use rsa_validator::RsaValidator; | ||
|
|
||
| /// Return a validator for the given signing algorithm. | ||
| pub fn validator_for_signing_alg(alg: SigningAlg) -> Option<Box<dyn RawSignatureValidator>> { | ||
| match alg { | ||
| SigningAlg::Es256 => Some(Box::new(EcdsaValidator::Es256)), | ||
| SigningAlg::Es384 => Some(Box::new(EcdsaValidator::Es384)), | ||
| SigningAlg::Es512 => Some(Box::new(EcdsaValidator::Es512)), | ||
| SigningAlg::Ed25519 => Some(Box::new(Ed25519Validator {})), | ||
| SigningAlg::Ps256 => Some(Box::new(RsaValidator::Ps256)), | ||
| SigningAlg::Ps384 => Some(Box::new(RsaValidator::Ps384)), | ||
| SigningAlg::Ps512 => Some(Box::new(RsaValidator::Ps512)), | ||
| } | ||
| } | ||
|
|
||
| pub(crate) fn validator_for_sig_and_hash_algs( | ||
| sig_alg: &Oid, | ||
| hash_alg: &Oid, | ||
| ) -> Option<Box<dyn RawSignatureValidator>> { | ||
| if sig_alg.as_ref() == RSA_OID.as_bytes() | ||
| || sig_alg.as_ref() == SHA256_WITH_RSAENCRYPTION_OID.as_bytes() | ||
| || sig_alg.as_ref() == SHA384_WITH_RSAENCRYPTION_OID.as_bytes() | ||
| || sig_alg.as_ref() == SHA512_WITH_RSAENCRYPTION_OID.as_bytes() | ||
| { | ||
| if hash_alg.as_ref() == SHA1_OID.as_bytes() { | ||
| return Some(Box::new(RsaLegacyValidator::Sha1)); | ||
| } else if hash_alg.as_ref() == SHA256_OID.as_bytes() { | ||
| return Some(Box::new(RsaLegacyValidator::Rsa256)); | ||
| } else if hash_alg.as_ref() == SHA384_OID.as_bytes() { | ||
| return Some(Box::new(RsaLegacyValidator::Rsa384)); | ||
| } else if hash_alg.as_ref() == SHA512_OID.as_bytes() { | ||
| return Some(Box::new(RsaLegacyValidator::Rsa512)); | ||
| } | ||
| } | ||
|
|
||
| None | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| // 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. | ||
|
|
||
| #![allow(missing_docs)] // REMOVE once this becomes `pub(crate)` | ||
|
|
||
| use openssl::{hash::MessageDigest, pkey::PKey, rsa::Rsa, sign::Verifier}; | ||
|
|
||
| use crate::{ | ||
| openssl::OpenSslMutex, | ||
| raw_signature::{RawSignatureValidationError, RawSignatureValidator}, | ||
| }; | ||
|
|
||
| /// An `RsaLegacyValidator` can validate raw signatures with an RSA signature | ||
| /// algorithm that is not supported directly by C2PA. (Some RFC 3161 time stamp | ||
| /// providers issue these signatures, which is why it's supported here.) | ||
| /// | ||
| /// TEMPORARILY public; will move to `pub(crate)` visibility later in the | ||
| /// refactoring. | ||
| pub enum RsaLegacyValidator { | ||
| Sha1, | ||
| Rsa256, | ||
| Rsa384, | ||
| Rsa512, | ||
| } | ||
|
|
||
| impl RawSignatureValidator for RsaLegacyValidator { | ||
| fn validate( | ||
| &self, | ||
| sig: &[u8], | ||
| data: &[u8], | ||
| pkey: &[u8], | ||
| ) -> Result<(), RawSignatureValidationError> { | ||
| let _openssl = OpenSslMutex::acquire()?; | ||
| let rsa = Rsa::public_key_from_der(pkey)?; | ||
|
|
||
| // Rebuild RSA keys to eliminate incompatible values. | ||
| let n = rsa.n().to_owned()?; | ||
| let e = rsa.e().to_owned()?; | ||
|
|
||
| let new_rsa = Rsa::from_public_components(n, e)?; | ||
| let public_key = PKey::from_rsa(new_rsa)?; | ||
|
|
||
| let mut verifier = match self { | ||
| Self::Sha1 => Verifier::new(MessageDigest::sha1(), &public_key)?, | ||
| Self::Rsa256 => Verifier::new(MessageDigest::sha256(), &public_key)?, | ||
| Self::Rsa384 => Verifier::new(MessageDigest::sha384(), &public_key)?, | ||
| Self::Rsa512 => Verifier::new(MessageDigest::sha512(), &public_key)?, | ||
| }; | ||
|
|
||
| if verifier.verify_oneshot(sig, data)? { | ||
| Ok(()) | ||
| } else { | ||
| Err(RawSignatureValidationError::SignatureMismatch) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wasm-bindgen, web-sys, web-time can not be included in the wasi target. I know this PR isn't really about adding WASI support, but there are other wasi targets in the Cargo.toml