Skip to content

Commit e4755c9

Browse files
committed
Merge branch 'main' into move-cose-validator
# Conflicts: # internal/crypto/src/lib.rs
2 parents f07fd7f + d2e56f2 commit e4755c9

File tree

19 files changed

+193
-94
lines changed

19 files changed

+193
-94
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ The Rust library crate provides:
106106
* `fetch_remote_manifests` enables the verification step to retrieve externally referenced manifest stores. External manifests are only fetched if there is no embedded manifest store and no locally adjacent .c2pa manifest store file of the same name.
107107
* `json_schema` is used by `make schema` to produce a JSON schema document that represents the `ManifestStore` data structures.
108108
* `psxxx_ocsp_stapling_experimental` this is an demonstration feature that will attempt to fetch the OCSP data from the OCSP responders listed in the manifest signing certificate. The response becomes part of the manifest and is used to prove the certificate was not revoked at the time of signing. This is only implemented for PS256, PS384 and PS512 signatures and is intended as a demonstration.
109-
* `openssl_ffi_mutex` prevents multiple threads from accessing the C OpenSSL library simultaneously. (This library is not re-entrant.) In a multi-threaded process (such as Cargo's test runner), this can lead to unpredictable behavior.
110109

111110
## Example code
112111

internal/crypto/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ rustdoc-args = ["--cfg", "docsrs"]
2727

2828
[features]
2929
json_schema = ["dep:schemars"]
30+
openssl = ["dep:openssl"]
3031

3132
[dependencies]
3233
base64 = "0.22.1"
@@ -43,10 +44,14 @@ thiserror = "1.0.61"
4344
x509-certificate = "0.21.0"
4445

4546
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
47+
openssl = { version = "0.10.61", features = ["vendored"], optional = true }
4648
ureq = "2.4.0"
4749
url = "=2.5.2" # Can't advance to 2.5.3 until Unicode-3.0 license is reviewed.
4850
x509-parser = "0.16.0"
4951

52+
[package.metadata.cargo-udeps.ignore]
53+
normal = ["openssl"] # TEMPORARY: Remove after openssl transition complete.
54+
5055
[dependencies.chrono]
5156
version = "0.4.38"
5257
default-features = false

internal/crypto/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ pub(crate) mod internal;
2626

2727
pub mod ocsp;
2828

29+
#[cfg(all(feature = "openssl", not(target_arch = "wasm32")))]
30+
pub mod openssl;
31+
32+
#[cfg(all(feature = "openssl", target_arch = "wasm32"))]
33+
compile_error!("OpenSSL feature is not compatible with WASM platform");
34+
2935
mod raw_signature;
3036
pub use raw_signature::validator::{RawSignatureValidationError, RawSignatureValidator};
3137

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2024 Adobe. All rights reserved.
2+
// This file is licensed to you under the Apache License,
3+
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
4+
// or the MIT license (http://opensource.org/licenses/MIT),
5+
// at your option.
6+
7+
// Unless required by applicable law or agreed to in writing,
8+
// this software is distributed on an "AS IS" BASIS, WITHOUT
9+
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
10+
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
11+
// specific language governing permissions and limitations under
12+
// each license.
13+
14+
use std::{
15+
error::Error,
16+
fmt,
17+
sync::{Mutex, MutexGuard},
18+
};
19+
20+
static FFI_MUTEX: Mutex<()> = Mutex::new(());
21+
22+
/// This mutex must be used by all code that accesses OpenSSL native code since
23+
/// the OpenSSL native code library is not re-entrant.
24+
///
25+
/// Failure to do so has been observed to lead to unexpected behavior including
26+
/// process crashes.
27+
pub struct OpenSslMutex<'a> {
28+
// The dead code bypass is intentional. We don't need to read the () contents of this guard. We
29+
// only need to ensure that the guard is dropped when this struct is dropped.
30+
#[allow(dead_code)]
31+
guard: MutexGuard<'a, ()>,
32+
}
33+
34+
impl OpenSslMutex<'_> {
35+
/// Acquire a mutex on OpenSSL FFI code.
36+
///
37+
/// WARNING: Calling code MUST NOT PANIC inside this function or
38+
/// anything called by it, even in test code. This will poison the FFI mutex
39+
/// and leave OpenSSL unusable for the remainder of the process lifetime.
40+
pub fn acquire() -> Result<Self, OpenSslMutexUnavailable> {
41+
// Useful for debugging.
42+
// eprintln!(
43+
// "ACQUIRING FFI MUTEX at\n{}",
44+
// std::backtrace::Backtrace::force_capture()
45+
// );
46+
47+
match FFI_MUTEX.lock() {
48+
Ok(guard) => Ok(Self { guard }),
49+
Err(_) => Err(OpenSslMutexUnavailable {}),
50+
}
51+
}
52+
}
53+
54+
// Useful for debugging.
55+
// impl<'a> Drop for OpenSslMutex<'a> {
56+
// fn drop(&mut self) {
57+
// eprintln!("Releasing FFI mutex\n\n\n");
58+
// }
59+
// }
60+
61+
/// Error returned when unable to acquire the OpenSSL native code mutex.
62+
///
63+
/// If this occurs, it's likely that a prior invocation of OpenSSL code panicked
64+
/// while holding the mutex. When this happens, the OpenSSL native code mutex is
65+
/// considered poisoned for the remainder of the process lifetime.
66+
///
67+
/// See [Rustnomicon: Poisoning] for more information.
68+
///
69+
/// [Rustnomicon: Poisoning]: https://doc.rust-lang.org/nomicon/poisoning.html
70+
#[derive(Debug, Eq, PartialEq)]
71+
pub struct OpenSslMutexUnavailable;
72+
73+
impl fmt::Display for OpenSslMutexUnavailable {
74+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75+
write!(f, "Unable to acquire OpenSSL native code mutex")
76+
}
77+
}
78+
79+
impl Error for OpenSslMutexUnavailable {}

internal/crypto/src/openssl/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2022 Adobe. All rights reserved.
2+
// This file is licensed to you under the Apache License,
3+
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
4+
// or the MIT license (http://opensource.org/licenses/MIT),
5+
// at your option.
6+
7+
// Unless required by applicable law or agreed to in writing,
8+
// this software is distributed on an "AS IS" BASIS, WITHOUT
9+
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
10+
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
11+
// specific language governing permissions and limitations under
12+
// each license.
13+
14+
//! This module provides functions for working with the [`openssl` native code
15+
//! library].
16+
//!
17+
//! It is only available if the `openssl` feature is enabled.
18+
//!
19+
//! [`openssl` native code library]: https://crates.io/crates/openssl
20+
21+
mod ffi_mutex;
22+
pub use ffi_mutex::{OpenSslMutex, OpenSslMutexUnavailable};

internal/crypto/src/tests/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@ mod base64;
2525
mod hash;
2626
mod internal;
2727
mod ocsp;
28+
29+
#[cfg(all(feature = "openssl", not(target_arch = "wasm32")))]
30+
mod openssl;
31+
2832
mod signing_alg;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2024 Adobe. All rights reserved.
2+
// This file is licensed to you under the Apache License,
3+
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
4+
// or the MIT license (http://opensource.org/licenses/MIT),
5+
// at your option.
6+
7+
// Unless required by applicable law or agreed to in writing,
8+
// this software is distributed on an "AS IS" BASIS, WITHOUT
9+
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
10+
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
11+
// specific language governing permissions and limitations under
12+
// each license.
13+
14+
use crate::openssl::OpenSslMutexUnavailable;
15+
16+
#[test]
17+
fn impl_display() {
18+
let err = OpenSslMutexUnavailable {};
19+
assert_eq!(
20+
err.to_string(),
21+
"Unable to acquire OpenSSL native code mutex"
22+
);
23+
}
24+
25+
#[test]
26+
fn impl_debug() {
27+
let err = OpenSslMutexUnavailable {};
28+
assert_eq!(format!("{err:?}"), "OpenSslMutexUnavailable");
29+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2024 Adobe. All rights reserved.
2+
// This file is licensed to you under the Apache License,
3+
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
4+
// or the MIT license (http://opensource.org/licenses/MIT),
5+
// at your option.
6+
7+
// Unless required by applicable law or agreed to in writing,
8+
// this software is distributed on an "AS IS" BASIS, WITHOUT
9+
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
10+
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
11+
// specific language governing permissions and limitations under
12+
// each license.
13+
14+
mod ffi_mutex;

sdk/Cargo.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ file_io = ["openssl_sign"]
3333
serialize_thumbnails = []
3434
no_interleaved_io = ["file_io"]
3535
fetch_remote_manifests = []
36-
openssl_sign = ["openssl"]
36+
openssl = ["dep:openssl", "c2pa-crypto/openssl"]
37+
openssl_sign = ["openssl", "c2pa-crypto/openssl"]
3738
json_schema = ["dep:schemars"]
3839
pdf = ["dep:lopdf"]
3940
v1_api = []
4041
unstable_api = []
41-
openssl_ffi_mutex = []
4242

4343
# The diagnostics feature is unsupported and might be removed.
4444
# It enables some low-overhead timing features used in our development cycle.
@@ -60,7 +60,6 @@ required-features = ["unstable_api"]
6060
name = "v2api"
6161
required-features = ["unstable_api"]
6262

63-
6463
[lib]
6564
crate-type = ["lib"]
6665

@@ -171,7 +170,6 @@ c2pa = { path = ".", features = [
171170
glob = "0.3.1"
172171
jumbf = "0.4.0"
173172

174-
175173
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
176174
wasm-bindgen-test = "0.3.31"
177175

sdk/src/error.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,11 +281,12 @@ pub enum Error {
281281
#[error(transparent)]
282282
CborError(#[from] serde_cbor::Error),
283283

284+
#[cfg(feature = "openssl")]
284285
#[error("could not acquire OpenSSL FFI mutex")]
285286
OpenSslMutexError,
286287

287-
#[error(transparent)]
288288
#[cfg(feature = "openssl")]
289+
#[error(transparent)]
289290
OpenSslError(#[from] openssl::error::ErrorStack),
290291

291292
#[error(transparent)]
@@ -303,3 +304,10 @@ pub enum Error {
303304

304305
/// A specialized `Result` type for C2PA toolkit operations.
305306
pub type Result<T> = std::result::Result<T, Error>;
307+
308+
#[cfg(feature = "openssl")]
309+
impl From<c2pa_crypto::openssl::OpenSslMutexUnavailable> for Error {
310+
fn from(_err: c2pa_crypto::openssl::OpenSslMutexUnavailable) -> Self {
311+
Self::OpenSslMutexError
312+
}
313+
}

0 commit comments

Comments
 (0)