signer.rs (8371B)
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 use crate::{Result, SigningAlg}; 14 /// The `Signer` trait generates a cryptographic signature over a byte array. 15 /// 16 /// This trait exists to allow the signature mechanism to be extended. 17 pub trait Signer { 18 /// Returns a new byte array which is a signature over the original. 19 fn sign(&self, data: &[u8]) -> Result<Vec<u8>>; 20 21 /// Returns the algorithm of the Signer. 22 fn alg(&self) -> SigningAlg; 23 24 /// Returns the certificates as a Vec containing a Vec of DER bytes for each certificate. 25 fn certs(&self) -> Result<Vec<Vec<u8>>>; 26 27 /// Returns the size in bytes of the largest possible expected signature. 28 /// Signing will fail if the result of the `sign` function is larger 29 /// than this value. 30 fn reserve_size(&self) -> usize; 31 32 /// URL for time authority to time stamp the signature 33 fn time_authority_url(&self) -> Option<String> { 34 None 35 } 36 37 /// Additional request headers to pass to the time stamp authority. 38 /// 39 /// IMPORTANT: You should not include the "Content-type" header here. 40 /// That is provided by default. 41 fn timestamp_request_headers(&self) -> Option<Vec<(String, String)>> { 42 None 43 } 44 45 fn timestamp_request_body(&self, message: &[u8]) -> Result<Vec<u8>> { 46 crate::time_stamp::default_rfc3161_message(message) 47 } 48 49 /// Request RFC 3161 timestamp to be included in the manifest data 50 /// structure. 51 /// 52 /// `message` is a preliminary hash of the claim 53 /// 54 /// The default implementation will send the request to the URL 55 /// provided by [`Self::time_authority_url()`], if any. 56 #[cfg(not(target_arch = "wasm32"))] 57 fn send_timestamp_request(&self, message: &[u8]) -> Option<Result<Vec<u8>>> { 58 if let Some(url) = self.time_authority_url() { 59 if let Ok(body) = self.timestamp_request_body(message) { 60 let headers: Option<Vec<(String, String)>> = self.timestamp_request_headers(); 61 return Some(crate::time_stamp::default_rfc3161_request( 62 &url, headers, &body, message, 63 )); 64 } 65 } 66 None 67 } 68 #[cfg(target_arch = "wasm32")] 69 fn send_timestamp_request(&self, _message: &[u8]) -> Option<Result<Vec<u8>>> { 70 None 71 } 72 73 /// OCSP response for the signing cert if available 74 /// This is the only C2PA supported cert revocation method. 75 /// By pre-querying the value for a your signing cert the value can 76 /// be cached taking pressure off of the CA (recommended by C2PA spec) 77 fn ocsp_val(&self) -> Option<Vec<u8>> { 78 None 79 } 80 81 /// If this returns true the sign function is responsible for for direct handling of the COSE structure. 82 /// 83 /// This is useful for cases where the signer needs to handle the COSE structure directly. 84 /// Not recommended for general use. 85 fn direct_cose_handling(&self) -> bool { 86 false 87 } 88 } 89 90 /// Trait to allow loading of signing credential from external sources 91 #[allow(dead_code)] // this here for wasm builds to pass clippy (todo: remove) 92 pub(crate) trait ConfigurableSigner: Signer + Sized { 93 /// Create signer form credential files 94 #[cfg(feature = "file_io")] 95 fn from_files<P: AsRef<std::path::Path>>( 96 signcert_path: P, 97 pkey_path: P, 98 alg: SigningAlg, 99 tsa_url: Option<String>, 100 ) -> Result<Self> { 101 use crate::Error; 102 103 let signcert = std::fs::read(signcert_path).map_err(Error::IoError)?; 104 let pkey = std::fs::read(pkey_path).map_err(Error::IoError)?; 105 106 Self::from_signcert_and_pkey(&signcert, &pkey, alg, tsa_url) 107 } 108 109 /// Create signer from credentials data 110 fn from_signcert_and_pkey( 111 signcert: &[u8], 112 pkey: &[u8], 113 alg: SigningAlg, 114 tsa_url: Option<String>, 115 ) -> Result<Self>; 116 } 117 118 use async_trait::async_trait; 119 120 /// The `AsyncSigner` trait generates a cryptographic signature over a byte array. 121 /// 122 /// This trait exists to allow the signature mechanism to be extended. 123 /// 124 /// Use this when the implementation is asynchronous. 125 #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] 126 #[cfg_attr(not(target_arch = "wasm32"), async_trait)] 127 pub trait AsyncSigner: Sync { 128 /// Returns a new byte array which is a signature over the original. 129 async fn sign(&self, data: Vec<u8>) -> Result<Vec<u8>>; 130 131 /// Returns the algorithm of the Signer. 132 fn alg(&self) -> SigningAlg; 133 134 /// Returns the certificates as a Vec containing a Vec of DER bytes for each certificate. 135 fn certs(&self) -> Result<Vec<Vec<u8>>>; 136 137 /// Returns the size in bytes of the largest possible expected signature. 138 /// Signing will fail if the result of the `sign` function is larger 139 /// than this value. 140 fn reserve_size(&self) -> usize; 141 142 /// URL for time authority to time stamp the signature 143 fn time_authority_url(&self) -> Option<String> { 144 None 145 } 146 147 /// Additional request headers to pass to the time stamp authority. 148 /// 149 /// IMPORTANT: You should not include the "Content-type" header here. 150 /// That is provided by default. 151 fn timestamp_request_headers(&self) -> Option<Vec<(String, String)>> { 152 None 153 } 154 155 fn timestamp_request_body(&self, message: &[u8]) -> Result<Vec<u8>> { 156 crate::time_stamp::default_rfc3161_message(message) 157 } 158 159 /// Request RFC 3161 timestamp to be included in the manifest data 160 /// structure. 161 /// 162 /// `message` is a preliminary hash of the claim 163 /// 164 /// The default implementation will send the request to the URL 165 /// provided by [`Self::time_authority_url()`], if any. 166 #[cfg(not(target_arch = "wasm32"))] 167 async fn send_timestamp_request(&self, message: &[u8]) -> Option<Result<Vec<u8>>> { 168 // NOTE: This is currently synchronous, but may become 169 // async in the future. 170 if let Some(url) = self.time_authority_url() { 171 if let Ok(body) = self.timestamp_request_body(message) { 172 let headers: Option<Vec<(String, String)>> = self.timestamp_request_headers(); 173 return Some(crate::time_stamp::default_rfc3161_request( 174 &url, headers, &body, message, 175 )); 176 } 177 } 178 None 179 } 180 #[cfg(target_arch = "wasm32")] 181 async fn send_timestamp_request(&self, message: &[u8]) -> Option<Result<Vec<u8>>>; 182 183 /// OCSP response for the signing cert if available 184 /// This is the only C2PA supported cert revocation method. 185 /// By pre-querying the value for a your signing cert the value can 186 /// be cached taking pressure off of the CA (recommended by C2PA spec) 187 async fn ocsp_val(&self) -> Option<Vec<u8>> { 188 None 189 } 190 191 /// If this returns true the sign function is responsible for for direct handling of the COSE structure. 192 /// 193 /// This is useful for cases where the signer needs to handle the COSE structure directly. 194 /// Not recommended for general use. 195 fn direct_cose_handling(&self) -> bool { 196 false 197 } 198 } 199 200 #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] 201 #[cfg_attr(not(target_arch = "wasm32"), async_trait)] 202 pub trait RemoteSigner: Sync { 203 /// Returns the `CoseSign1` bytes signed by the [`RemoteSigner`]. 204 /// 205 /// The size of returned `Vec` must match the value returned by `reserve_size`. 206 /// This data will be embedded in the JUMBF `c2pa.signature` box of the manifest. 207 /// `data` are the bytes of the claim to be remotely signed. 208 async fn sign_remote(&self, data: &[u8]) -> Result<Vec<u8>>; 209 210 /// Returns the size in bytes of the largest possible expected signature. 211 /// 212 /// Signing will fail if the result of the `sign` function is larger 213 /// than this value. 214 fn reserve_size(&self) -> usize; 215 }