parsec_service/back/
backend_handler.rs

1// Copyright 2019 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! Convert requests to calls to the underlying provider
4//!
5//! The backend handler embodies the last processing step from external request
6//! to internal function call - parsing of the request body and conversion to a
7//! native operation which is then passed to the provider.
8use crate::authenticators::Application;
9use crate::providers::Provide;
10use derivative::Derivative;
11use log::{error, trace, warn};
12use parsec_interface::operations::Convert;
13use parsec_interface::operations::{NativeOperation, NativeResult};
14use parsec_interface::requests::{
15    request::RequestHeader, Request, Response, ResponseStatus, Result,
16};
17use parsec_interface::requests::{BodyType, ProviderId};
18use std::io::{Error, ErrorKind};
19use std::sync::Arc;
20
21/// Back end handler component
22///
23/// Component responsible for unmarshalling requests, passing the operation
24/// to the provider and marshalling the result.
25///
26/// It also provides assessment capabilities, letting the dispatcher know if
27/// it can process a request.
28#[derive(Derivative)]
29#[derivative(Debug)]
30pub struct BackEndHandler {
31    // Send and Sync are required for Arc<FrontEndHandler> to be Send.
32    #[derivative(Debug = "ignore")]
33    provider: Arc<dyn Provide + Send + Sync>,
34    #[derivative(Debug = "ignore")]
35    converter: Box<dyn Convert + Send + Sync>,
36    provider_id: ProviderId,
37    content_type: BodyType,
38    accept_type: BodyType,
39}
40
41impl BackEndHandler {
42    /// Convert a request into a response, given the result of the operation.
43    fn result_to_response(&self, result: NativeResult, request_hdr: RequestHeader) -> Response {
44        let mut response = Response::from_request_header(request_hdr, ResponseStatus::Success);
45        match self.converter.result_to_body(result) {
46            Ok(body) => response.body = body,
47            Err(status) => response.header.status = status,
48        };
49        response
50    }
51
52    /// Assess whether the backend handler-provider pair is capable of handling
53    /// the request.
54    ///
55    /// # Errors
56    /// - if the provider ID can not perform the type of operation, returns
57    /// `ResponseStatus::PsaErrorNotSupported`
58    /// - if the provider ID does not match, returns `ResponseStatus::WrongProviderId`
59    /// - if the content type does not match, returns `ResponseStatus::ContentTypeNotSupported`
60    /// - if the accept type does not match, returns `ResponseStatus::AcceptTypeNotSupported`
61    pub fn is_capable(&self, request: &Request) -> Result<()> {
62        let header = &request.header;
63
64        if (self.provider_id == ProviderId::Core) != header.opcode.is_core() {
65            error!("The request's operation is not compatible with the provider targeted.");
66            return Err(ResponseStatus::PsaErrorNotSupported);
67        }
68
69        if header.provider != self.provider_id {
70            Err(ResponseStatus::WrongProviderId)
71        } else if header.content_type != self.content_type {
72            Err(ResponseStatus::ContentTypeNotSupported)
73        } else if header.accept_type != self.accept_type {
74            Err(ResponseStatus::AcceptTypeNotSupported)
75        } else {
76            Ok(())
77        }
78    }
79
80    /// Unmarshall the request body, pass the operation to the provider and marshall
81    /// the result back.
82    ///
83    /// If any of the steps fails, a response containing an appropriate status code is
84    /// returned.
85    pub fn execute_request(&self, request: Request, app: Option<Application>) -> Response {
86        trace!("execute_request ingress");
87        let opcode = request.header.opcode;
88        let header = request.header;
89
90        macro_rules! unwrap_or_else_return {
91            ($result:expr) => {
92                match $result {
93                    Ok(value) => value,
94                    Err(status) => return Response::from_request_header(header, status),
95                }
96            };
97        }
98
99        if opcode.is_admin() {
100            let app = unwrap_or_else_return!(app.as_ref().ok_or(ResponseStatus::NotAuthenticated));
101
102            if !app.is_admin() {
103                warn!(
104                    "Application name \"{}\" tried to perform an admin operation ({:?}).",
105                    app.identity().name(),
106                    opcode
107                );
108                return Response::from_request_header(header, ResponseStatus::AdminOperation);
109            }
110        }
111
112        match unwrap_or_else_return!(self.converter.body_to_operation(request.body, opcode)) {
113            NativeOperation::ListProviders(op_list_providers) => {
114                let result =
115                    unwrap_or_else_return!(self.provider.list_providers(op_list_providers));
116                trace!("list_providers egress");
117                self.result_to_response(NativeResult::ListProviders(result), header)
118            }
119            NativeOperation::ListOpcodes(op_list_opcodes) => {
120                let result = unwrap_or_else_return!(self.provider.list_opcodes(op_list_opcodes));
121                trace!("list_opcodes egress");
122                self.result_to_response(NativeResult::ListOpcodes(result), header)
123            }
124            NativeOperation::Ping(op_ping) => {
125                let result = unwrap_or_else_return!(self.provider.ping(op_ping));
126                trace!("ping egress");
127                self.result_to_response(NativeResult::Ping(result), header)
128            }
129            NativeOperation::PsaGenerateKey(op_generate_key) => {
130                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
131                let result = unwrap_or_else_return!(self
132                    .provider
133                    .psa_generate_key(app.identity(), op_generate_key));
134                trace!("psa_generate_key egress");
135                self.result_to_response(NativeResult::PsaGenerateKey(result), header)
136            }
137            NativeOperation::PsaImportKey(op_import_key) => {
138                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
139                let result = unwrap_or_else_return!(self
140                    .provider
141                    .psa_import_key(app.identity(), op_import_key));
142                trace!("psa_import_key egress");
143                self.result_to_response(NativeResult::PsaImportKey(result), header)
144            }
145            NativeOperation::PsaExportPublicKey(op_export_public_key) => {
146                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
147                let result = unwrap_or_else_return!(self
148                    .provider
149                    .psa_export_public_key(app.identity(), op_export_public_key));
150                trace!("psa_export_public_key egress");
151                self.result_to_response(NativeResult::PsaExportPublicKey(result), header)
152            }
153            NativeOperation::PsaExportKey(op_export_key) => {
154                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
155                let result = unwrap_or_else_return!(self
156                    .provider
157                    .psa_export_key(app.identity(), op_export_key));
158                trace!("psa_export_key egress");
159                self.result_to_response(NativeResult::PsaExportKey(result), header)
160            }
161            NativeOperation::PsaDestroyKey(op_destroy_key) => {
162                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
163                let result = unwrap_or_else_return!(self
164                    .provider
165                    .psa_destroy_key(app.identity(), op_destroy_key));
166                trace!("psa_destroy_key egress");
167                self.result_to_response(NativeResult::PsaDestroyKey(result), header)
168            }
169            NativeOperation::PsaSignHash(op_sign_hash) => {
170                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
171                let result = unwrap_or_else_return!(self
172                    .provider
173                    .psa_sign_hash(app.identity(), op_sign_hash));
174                trace!("psa_sign_hash egress");
175                self.result_to_response(NativeResult::PsaSignHash(result), header)
176            }
177            NativeOperation::PsaVerifyHash(op_verify_hash) => {
178                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
179                let result = unwrap_or_else_return!(self
180                    .provider
181                    .psa_verify_hash(app.identity(), op_verify_hash));
182                trace!("psa_verify_hash egress");
183                self.result_to_response(NativeResult::PsaVerifyHash(result), header)
184            }
185            NativeOperation::PsaAsymmetricEncrypt(op_asymmetric_encrypt) => {
186                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
187                let result = unwrap_or_else_return!(self
188                    .provider
189                    .psa_asymmetric_encrypt(app.identity(), op_asymmetric_encrypt));
190                trace!("psa_asymmetric_encrypt egress");
191                self.result_to_response(NativeResult::PsaAsymmetricEncrypt(result), header)
192            }
193            NativeOperation::PsaAsymmetricDecrypt(op_asymmetric_decrypt) => {
194                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
195                let result = unwrap_or_else_return!(self
196                    .provider
197                    .psa_asymmetric_decrypt(app.identity(), op_asymmetric_decrypt));
198                trace!("psa_asymmetric_decrypt egress");
199                self.result_to_response(NativeResult::PsaAsymmetricDecrypt(result), header)
200            }
201            NativeOperation::PsaAeadEncrypt(op_aead_encrypt) => {
202                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
203                let result = unwrap_or_else_return!(self
204                    .provider
205                    .psa_aead_encrypt(app.identity(), op_aead_encrypt));
206                trace!("psa_aead_encrypt egress");
207                self.result_to_response(NativeResult::PsaAeadEncrypt(result), header)
208            }
209            NativeOperation::PsaAeadDecrypt(op_aead_decrypt) => {
210                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
211                let result = unwrap_or_else_return!(self
212                    .provider
213                    .psa_aead_decrypt(app.identity(), op_aead_decrypt));
214                trace!("psa_aead_decrypt egress");
215                self.result_to_response(NativeResult::PsaAeadDecrypt(result), header)
216            }
217            NativeOperation::ListAuthenticators(op_list_authenticators) => {
218                let result = unwrap_or_else_return!(self
219                    .provider
220                    .list_authenticators(op_list_authenticators));
221                trace!("list_authenticators egress");
222                self.result_to_response(NativeResult::ListAuthenticators(result), header)
223            }
224            NativeOperation::ListKeys(op_list_keys) => {
225                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
226                let result =
227                    unwrap_or_else_return!(self.provider.list_keys(app.identity(), op_list_keys));
228                trace!("list_keys egress");
229                self.result_to_response(NativeResult::ListKeys(result), header)
230            }
231            NativeOperation::ListClients(op_list_clients) => {
232                let result = unwrap_or_else_return!(self.provider.list_clients(op_list_clients));
233                trace!("list_clients egress");
234                self.result_to_response(NativeResult::ListClients(result), header)
235            }
236            NativeOperation::DeleteClient(op_delete_client) => {
237                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
238                let result = unwrap_or_else_return!(self
239                    .provider
240                    .delete_client(app.identity(), op_delete_client));
241                trace!("delete_client egress");
242                self.result_to_response(NativeResult::DeleteClient(result), header)
243            }
244            NativeOperation::PsaHashCompute(op_hash_compute) => {
245                let result =
246                    unwrap_or_else_return!(self.provider.psa_hash_compute(op_hash_compute));
247                trace!("psa_hash_compute egress");
248                self.result_to_response(NativeResult::PsaHashCompute(result), header)
249            }
250            NativeOperation::PsaHashCompare(op_hash_compare) => {
251                let result =
252                    unwrap_or_else_return!(self.provider.psa_hash_compare(op_hash_compare));
253                trace!("psa_hash_compare egress");
254                self.result_to_response(NativeResult::PsaHashCompare(result), header)
255            }
256            NativeOperation::PsaRawKeyAgreement(op_raw_key_agreement) => {
257                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
258                let result = unwrap_or_else_return!(self
259                    .provider
260                    .psa_raw_key_agreement(app.identity(), op_raw_key_agreement));
261                trace!("psa_raw_key_agreement egress");
262                self.result_to_response(NativeResult::PsaRawKeyAgreement(result), header)
263            }
264            NativeOperation::PsaGenerateRandom(op_generate_random) => {
265                let result =
266                    unwrap_or_else_return!(self.provider.psa_generate_random(op_generate_random));
267                trace!("psa_generate_random egress");
268                self.result_to_response(NativeResult::PsaGenerateRandom(result), header)
269            }
270            NativeOperation::PsaSignMessage(op_sign_message) => {
271                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
272                let result = unwrap_or_else_return!(self
273                    .provider
274                    .psa_sign_message(app.identity(), op_sign_message));
275                trace!("psa_sign_message egress");
276                self.result_to_response(NativeResult::PsaSignMessage(result), header)
277            }
278            NativeOperation::PsaVerifyMessage(op_verify_message) => {
279                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
280                let result = unwrap_or_else_return!(self
281                    .provider
282                    .psa_verify_message(app.identity(), op_verify_message));
283                trace!("psa_verify_message egress");
284                self.result_to_response(NativeResult::PsaVerifyMessage(result), header)
285            }
286            NativeOperation::PsaCipherEncrypt(op_cipher_encrypt) => {
287                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
288                let result = unwrap_or_else_return!(self
289                    .provider
290                    .psa_cipher_encrypt(app.identity(), op_cipher_encrypt));
291                trace!("op_cipher_encrypt egress");
292                self.result_to_response(NativeResult::PsaCipherEncrypt(result), header)
293            }
294            NativeOperation::PsaCipherDecrypt(op_cipher_decrypt) => {
295                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
296                let result = unwrap_or_else_return!(self
297                    .provider
298                    .psa_cipher_decrypt(app.identity(), op_cipher_decrypt));
299                trace!("psa_cipher_decrypt egress");
300                self.result_to_response(NativeResult::PsaCipherDecrypt(result), header)
301            }
302            NativeOperation::CanDoCrypto(op_can_do_crypto) => {
303                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
304                let result = unwrap_or_else_return!(self
305                    .provider
306                    .can_do_crypto(app.identity(), op_can_do_crypto));
307                trace!("can_do_crypto egress");
308                self.result_to_response(NativeResult::CanDoCrypto(result), header)
309            }
310            NativeOperation::PrepareKeyAttestation(op_prepare_key_attestation) => {
311                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
312                let result = unwrap_or_else_return!(self
313                    .provider
314                    .prepare_key_attestation(app.identity(), op_prepare_key_attestation));
315                trace!("prepare_key_attestation egress");
316                self.result_to_response(NativeResult::PrepareKeyAttestation(result), header)
317            }
318            NativeOperation::AttestKey(op_attest_key) => {
319                let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
320                let result =
321                    unwrap_or_else_return!(self.provider.attest_key(app.identity(), op_attest_key));
322                trace!("attest_key egress");
323                self.result_to_response(NativeResult::AttestKey(result), header)
324            }
325        }
326    }
327}
328
329/// Builder for `BackEndHandler`
330#[derive(Default, Derivative)]
331#[derivative(Debug)]
332pub struct BackEndHandlerBuilder {
333    #[derivative(Debug = "ignore")]
334    provider: Option<Arc<dyn Provide + Send + Sync>>,
335    #[derivative(Debug = "ignore")]
336    converter: Option<Box<dyn Convert + Send + Sync>>,
337    provider_id: Option<ProviderId>,
338    content_type: Option<BodyType>,
339    accept_type: Option<BodyType>,
340}
341
342impl BackEndHandlerBuilder {
343    /// Create a new BackEndHandler builder
344    pub fn new() -> BackEndHandlerBuilder {
345        BackEndHandlerBuilder {
346            provider: None,
347            converter: None,
348            provider_id: None,
349            content_type: None,
350            accept_type: None,
351        }
352    }
353
354    /// Add a provider to the builder
355    pub fn with_provider(mut self, provider: Arc<dyn Provide + Send + Sync>) -> Self {
356        self.provider = Some(provider);
357        self
358    }
359
360    /// Add a converter to the builder
361    pub fn with_converter(mut self, converter: Box<dyn Convert + Send + Sync>) -> Self {
362        self.converter = Some(converter);
363        self
364    }
365
366    /// Set the ID of the BackEndHandler
367    pub fn with_provider_id(mut self, provider_id: ProviderId) -> Self {
368        self.provider_id = Some(provider_id);
369        self
370    }
371
372    /// Set the content type that the BackEndHandler supports
373    pub fn with_content_type(mut self, content_type: BodyType) -> Self {
374        self.content_type = Some(content_type);
375        self
376    }
377
378    /// Set the accept type that the BackEndHandler supports
379    pub fn with_accept_type(mut self, accept_type: BodyType) -> Self {
380        self.accept_type = Some(accept_type);
381        self
382    }
383
384    /// Build into a BackEndHandler
385    pub fn build(self) -> std::io::Result<BackEndHandler> {
386        Ok(BackEndHandler {
387            provider: self
388                .provider
389                .ok_or_else(|| Error::new(ErrorKind::InvalidData, "provider is missing"))?,
390            converter: self
391                .converter
392                .ok_or_else(|| Error::new(ErrorKind::InvalidData, "converter is missing"))?,
393            provider_id: self
394                .provider_id
395                .ok_or_else(|| Error::new(ErrorKind::InvalidData, "provider_id is missing"))?,
396            content_type: self
397                .content_type
398                .ok_or_else(|| Error::new(ErrorKind::InvalidData, "content_type is missing"))?,
399            accept_type: self
400                .accept_type
401                .ok_or_else(|| Error::new(ErrorKind::InvalidData, "accept_type is missing"))?,
402        })
403    }
404}