callback_signer.rs (4924B)
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 #![deny(missing_docs)] 15 16 //! The `callback_signer` module provides a way to obtain a [`Signer`] or [`AsyncSigner`] 17 //! using a callback and public signing certificates. 18 19 use crate::{ 20 error::{Error, Result}, 21 AsyncSigner, Signer, SigningAlg, 22 }; 23 24 /// Defines a callback function interface for a [`CallbackSigner`]. 25 /// 26 /// The callback should return a signature for the given data. 27 /// The callback should return an error if the data cannot be signed. 28 pub type CallbackFunc = dyn Fn(*const (), &[u8]) -> std::result::Result<Vec<u8>, Error>; 29 30 /// Defines a signer that uses a callback to sign data. 31 /// 32 /// The private key should only be known by the callback. 33 pub struct CallbackSigner { 34 /// An opaque context for the signer, used to store any necessary state. 35 pub context: *const (), 36 37 /// The callback to use to sign data. 38 pub callback: Box<CallbackFunc>, 39 40 /// The signing algorithm to use. 41 pub alg: SigningAlg, 42 43 /// The public certificates to use in PEM format. 44 pub certs: Vec<u8>, 45 46 /// A max size to reserve for the signature. 47 pub reserve_size: usize, 48 49 /// The optional URL of a Time Stamping Authority. 50 pub tsa_url: Option<String>, 51 } 52 53 unsafe impl Send for CallbackSigner {} 54 55 unsafe impl Sync for CallbackSigner {} 56 57 impl CallbackSigner { 58 /// Create a new callback signer. 59 pub fn new<F, T>(callback: F, alg: SigningAlg, certs: T) -> Self 60 where 61 F: Fn(*const (), &[u8]) -> std::result::Result<Vec<u8>, Error> + 'static, 62 T: Into<Vec<u8>>, 63 { 64 let certs = certs.into(); 65 let reserve_size = 10000 + certs.len(); 66 Self { 67 context: std::ptr::null(), 68 callback: Box::new(callback), 69 alg, 70 certs, 71 reserve_size, 72 ..Default::default() 73 } 74 } 75 76 /// Set a time stamping authority URL to call when signing. 77 pub fn set_tsa_url<S: Into<String>>(mut self, url: S) -> Self { 78 self.tsa_url = Some(url.into()); 79 self 80 } 81 82 /// Set a context value for the signer. 83 /// 84 /// This can be used to store any necessary state for the callback. 85 /// Safety: The context must be valid for the lifetime of the signer. 86 /// There is no Rust memory management for the context since it may also come from FFI. 87 pub const fn set_context(mut self, context: *const ()) -> Self { 88 self.context = context; 89 self 90 } 91 } 92 93 // This default is only intended for struct completion, do not use on its own. 94 impl Default for CallbackSigner { 95 fn default() -> Self { 96 Self { 97 context: std::ptr::null(), 98 callback: Box::new(|_, _| Err(Error::UnsupportedType)), 99 alg: SigningAlg::Es256, 100 certs: Vec::new(), 101 reserve_size: 10000, 102 tsa_url: None, 103 } 104 } 105 } 106 107 impl Signer for CallbackSigner { 108 fn sign(&self, data: &[u8]) -> Result<Vec<u8>> { 109 (self.callback)(self.context, data) 110 } 111 112 fn alg(&self) -> SigningAlg { 113 self.alg 114 } 115 116 fn certs(&self) -> Result<Vec<Vec<u8>>> { 117 let pems = pem::parse_many(&self.certs).map_err(|e| Error::OtherError(Box::new(e)))?; 118 Ok(pems.into_iter().map(|p| p.into_contents()).collect()) 119 } 120 121 fn reserve_size(&self) -> usize { 122 self.reserve_size 123 } 124 125 fn time_authority_url(&self) -> Option<String> { 126 self.tsa_url.clone() 127 } 128 } 129 130 use async_trait::async_trait; 131 132 #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] 133 #[cfg_attr(not(target_arch = "wasm32"), async_trait)] 134 // I'm not sure if this is useful since the callback is still synchronous. 135 impl AsyncSigner for CallbackSigner { 136 async fn sign(&self, data: Vec<u8>) -> Result<Vec<u8>> { 137 (self.callback)(self.context, &data) 138 } 139 140 fn alg(&self) -> SigningAlg { 141 self.alg 142 } 143 144 fn certs(&self) -> Result<Vec<Vec<u8>>> { 145 let pems = pem::parse_many(&self.certs).map_err(|e| Error::OtherError(Box::new(e)))?; 146 Ok(pems.into_iter().map(|p| p.into_contents()).collect()) 147 } 148 149 fn reserve_size(&self) -> usize { 150 self.reserve_size 151 } 152 153 fn time_authority_url(&self) -> Option<String> { 154 self.tsa_url.clone() 155 } 156 157 #[cfg(target_arch = "wasm32")] 158 async fn send_timestamp_request(&self, _message: &[u8]) -> Option<Result<Vec<u8>>> { 159 None 160 } 161 }