-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add
RawSigner
trait to c2pa-crypto
(derived from `c2pa::Sig…
…ner`) (#716)
- Loading branch information
1 parent
2a65756
commit 52124e5
Showing
53 changed files
with
2,117 additions
and
1,344 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// 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(dead_code)] // TEMPORARY while refactoring | ||
|
||
use openssl::x509::X509; | ||
|
||
// Verify the certificate chain order. | ||
// | ||
// Return `true` if each cert in the chain can be verified as issued by the next | ||
// issuer. | ||
pub(crate) fn check_chain_order(certs: &[X509]) -> bool { | ||
// IMPORTANT: ffi_mutex::acquire() should have been called by calling fn. Please | ||
// don't make this pub or pub(crate) without finding a way to ensure that | ||
// precondition. | ||
|
||
let mut iter = certs.iter().peekable(); | ||
|
||
while let Some(cert) = iter.next() { | ||
let Some(next) = iter.peek() else { | ||
break; | ||
}; | ||
|
||
let Ok(pkey) = next.public_key() else { | ||
return false; | ||
}; | ||
|
||
let Ok(verified) = cert.verify(&pkey) else { | ||
return false; | ||
}; | ||
|
||
if !verified { | ||
return false; | ||
} | ||
} | ||
|
||
true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
// 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::{ | ||
ec::EcKey, | ||
hash::MessageDigest, | ||
pkey::{PKey, Private}, | ||
sign::Signer, | ||
x509::X509, | ||
}; | ||
|
||
use crate::{ | ||
openssl::{cert_chain::check_chain_order, OpenSslMutex}, | ||
p1363::der_to_p1363, | ||
raw_signature::{RawSigner, RawSignerError}, | ||
time_stamp::TimeStampProvider, | ||
SigningAlg, | ||
}; | ||
|
||
enum EcdsaSigningAlg { | ||
Es256, | ||
Es384, | ||
Es512, | ||
} | ||
|
||
/// Implements `Signer` trait using OpenSSL's implementation of | ||
/// ECDSA encryption. | ||
pub struct EcdsaSigner { | ||
alg: EcdsaSigningAlg, | ||
|
||
cert_chain: Vec<X509>, | ||
cert_chain_len: usize, | ||
|
||
private_key: EcKey<Private>, | ||
|
||
time_stamp_service_url: Option<String>, | ||
time_stamp_size: usize, | ||
} | ||
|
||
impl EcdsaSigner { | ||
pub(crate) fn from_cert_chain_and_private_key( | ||
cert_chain: &[u8], | ||
private_key: &[u8], | ||
alg: SigningAlg, | ||
time_stamp_service_url: Option<String>, | ||
) -> Result<Self, RawSignerError> { | ||
let alg = match alg { | ||
SigningAlg::Es256 => EcdsaSigningAlg::Es256, | ||
SigningAlg::Es384 => EcdsaSigningAlg::Es384, | ||
SigningAlg::Es512 => EcdsaSigningAlg::Es512, | ||
_ => { | ||
return Err(RawSignerError::InternalError( | ||
"EcdsaSigner should be used only for SigningAlg::Es***".to_string(), | ||
)); | ||
} | ||
}; | ||
|
||
let _openssl = OpenSslMutex::acquire()?; | ||
|
||
let cert_chain = X509::stack_from_pem(cert_chain)?; | ||
let cert_chain_len = cert_chain.len(); | ||
|
||
if !check_chain_order(&cert_chain) { | ||
return Err(RawSignerError::InvalidSigningCredentials( | ||
"certificate chain in incorrect order".to_string(), | ||
)); | ||
} | ||
|
||
let private_key = EcKey::private_key_from_pem(private_key)?; | ||
|
||
Ok(EcdsaSigner { | ||
alg, | ||
cert_chain, | ||
cert_chain_len, | ||
private_key, | ||
time_stamp_service_url, | ||
time_stamp_size: 10000, | ||
// TO DO: Call out to time stamp service to get actual time stamp and use that size? | ||
}) | ||
} | ||
} | ||
|
||
impl RawSigner for EcdsaSigner { | ||
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, RawSignerError> { | ||
let _openssl = OpenSslMutex::acquire()?; | ||
|
||
let private_key = PKey::from_ec_key(self.private_key.clone())?; | ||
|
||
let mut signer = match self.alg { | ||
EcdsaSigningAlg::Es256 => Signer::new(MessageDigest::sha256(), &private_key)?, | ||
EcdsaSigningAlg::Es384 => Signer::new(MessageDigest::sha384(), &private_key)?, | ||
EcdsaSigningAlg::Es512 => Signer::new(MessageDigest::sha512(), &private_key)?, | ||
}; | ||
|
||
signer.update(data)?; | ||
|
||
let der_sig = signer.sign_to_vec()?; | ||
der_to_p1363(&der_sig, self.alg()) | ||
} | ||
|
||
fn alg(&self) -> SigningAlg { | ||
match self.alg { | ||
EcdsaSigningAlg::Es256 => SigningAlg::Es256, | ||
EcdsaSigningAlg::Es384 => SigningAlg::Es384, | ||
EcdsaSigningAlg::Es512 => SigningAlg::Es512, | ||
} | ||
} | ||
|
||
fn reserve_size(&self) -> usize { | ||
1024 + self.cert_chain_len + self.time_stamp_size | ||
} | ||
|
||
fn cert_chain(&self) -> Result<Vec<Vec<u8>>, RawSignerError> { | ||
let _openssl = OpenSslMutex::acquire()?; | ||
|
||
self.cert_chain | ||
.iter() | ||
.map(|cert| { | ||
cert.to_der() | ||
.map_err(|e| RawSignerError::OpenSslError(e.to_string())) | ||
}) | ||
.collect() | ||
} | ||
} | ||
|
||
impl TimeStampProvider for EcdsaSigner { | ||
fn time_stamp_service_url(&self) -> Option<String> { | ||
self.time_stamp_service_url.clone() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// 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, Private}, | ||
sign::Signer, | ||
x509::X509, | ||
}; | ||
|
||
use crate::{ | ||
openssl::{cert_chain::check_chain_order, OpenSslMutex}, | ||
raw_signature::{RawSigner, RawSignerError}, | ||
time_stamp::TimeStampProvider, | ||
SigningAlg, | ||
}; | ||
|
||
/// Implements `RawSigner` trait using OpenSSL's implementation of | ||
/// Edwards Curve encryption. | ||
pub struct Ed25519Signer { | ||
cert_chain: Vec<X509>, | ||
cert_chain_len: usize, | ||
|
||
private_key: PKey<Private>, | ||
|
||
time_stamp_service_url: Option<String>, | ||
time_stamp_size: usize, | ||
} | ||
|
||
impl Ed25519Signer { | ||
pub(crate) fn from_cert_chain_and_private_key( | ||
cert_chain: &[u8], | ||
private_key: &[u8], | ||
time_stamp_service_url: Option<String>, | ||
) -> Result<Self, RawSignerError> { | ||
let _openssl = OpenSslMutex::acquire()?; | ||
|
||
let cert_chain = X509::stack_from_pem(cert_chain)?; | ||
let cert_chain_len = cert_chain.len(); | ||
|
||
if !check_chain_order(&cert_chain) { | ||
return Err(RawSignerError::InvalidSigningCredentials( | ||
"certificate chain in incorrect order".to_string(), | ||
)); | ||
} | ||
|
||
let private_key = PKey::private_key_from_pem(private_key)?; | ||
|
||
Ok(Ed25519Signer { | ||
cert_chain, | ||
cert_chain_len, | ||
|
||
private_key, | ||
|
||
time_stamp_service_url, | ||
time_stamp_size: 10000, | ||
// TO DO: Call out to time stamp service to get actual time stamp and use that size? | ||
}) | ||
} | ||
} | ||
|
||
impl RawSigner for Ed25519Signer { | ||
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, RawSignerError> { | ||
let _openssl = OpenSslMutex::acquire()?; | ||
|
||
let mut signer = Signer::new_without_digest(&self.private_key)?; | ||
|
||
Ok(signer.sign_oneshot_to_vec(data)?) | ||
} | ||
|
||
fn alg(&self) -> SigningAlg { | ||
SigningAlg::Ed25519 | ||
} | ||
|
||
fn reserve_size(&self) -> usize { | ||
1024 + self.cert_chain_len + self.time_stamp_size | ||
} | ||
|
||
fn cert_chain(&self) -> Result<Vec<Vec<u8>>, RawSignerError> { | ||
let _openssl = OpenSslMutex::acquire()?; | ||
|
||
self.cert_chain | ||
.iter() | ||
.map(|cert| { | ||
cert.to_der() | ||
.map_err(|e| RawSignerError::OpenSslError(e.to_string())) | ||
}) | ||
.collect() | ||
} | ||
} | ||
|
||
impl TimeStampProvider for Ed25519Signer { | ||
fn time_stamp_service_url(&self) -> Option<String> { | ||
self.time_stamp_service_url.clone() | ||
} | ||
} |
Oops, something went wrong.