1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This module contains the structs related to the CSR (Certificate Signing Request)
16 //! sent from the client VM to the service VM for attestation.
17 
18 use alloc::vec;
19 use alloc::vec::Vec;
20 use cbor_util::{cbor_value_type, value_to_bytes};
21 use ciborium::Value;
22 use coset::{self, CborSerializable, CoseError};
23 
24 /// Represents a CSR sent from the client VM to the service VM for attestation.
25 ///
26 /// See client_vm_csr.cddl for the definition of the CSR.
27 #[derive(Clone, Debug, Eq, PartialEq)]
28 pub struct Csr {
29     /// The DICE certificate chain of the client VM.
30     pub dice_cert_chain: Vec<u8>,
31 
32     /// The signed CSR payload in COSE_Sign structure, which includes two signatures:
33     /// - one by CDI_Leaf_Priv of the client VM's DICE chain,
34     /// - another by the private key corresponding to the public key.
35     pub signed_csr_payload: Vec<u8>,
36 }
37 
38 impl Csr {
39     /// Serializes this object to a CBOR-encoded vector.
into_cbor_vec(self) -> coset::Result<Vec<u8>>40     pub fn into_cbor_vec(self) -> coset::Result<Vec<u8>> {
41         let value = Value::Array(vec![
42             Value::Bytes(self.dice_cert_chain),
43             Value::Bytes(self.signed_csr_payload),
44         ]);
45         value.to_vec()
46     }
47 
48     /// Creates an object instance from the provided CBOR-encoded slice.
from_cbor_slice(data: &[u8]) -> coset::Result<Self>49     pub fn from_cbor_slice(data: &[u8]) -> coset::Result<Self> {
50         let value = Value::from_slice(data)?;
51         let Value::Array(mut arr) = value else {
52             return Err(CoseError::UnexpectedItem(cbor_value_type(&value), "array"));
53         };
54         if arr.len() != 2 {
55             return Err(CoseError::UnexpectedItem("array", "array with 2 items"));
56         }
57         Ok(Self {
58             signed_csr_payload: value_to_bytes(arr.remove(1), "signed_csr_payload")?,
59             dice_cert_chain: value_to_bytes(arr.remove(0), "dice_cert_chain")?,
60         })
61     }
62 }
63 
64 /// Represents the data to be signed and sent from the client VM to the service VM
65 /// for attestation.
66 ///
67 /// It will be signed by both CDI_Leaf_Priv of the client VM's DICE chain and
68 /// the private key corresponding to the public key to be attested.
69 #[derive(Clone, Debug, Eq, PartialEq)]
70 pub struct CsrPayload {
71     /// COSE_Key encoded EC P-256 public key to be attested.
72     pub public_key: Vec<u8>,
73 
74     /// A random array with a length between 0 and 64.
75     /// It will be included in the certificate chain in the attestation result,
76     /// serving as proof of the freshness of the result.
77     pub challenge: Vec<u8>,
78 }
79 
80 impl CsrPayload {
81     /// Serializes this object to a CBOR-encoded vector.
into_cbor_vec(self) -> coset::Result<Vec<u8>>82     pub fn into_cbor_vec(self) -> coset::Result<Vec<u8>> {
83         let value = Value::Array(vec![Value::Bytes(self.public_key), Value::Bytes(self.challenge)]);
84         value.to_vec()
85     }
86 
87     /// Creates an object instance from the provided CBOR-encoded slice.
from_cbor_slice(data: &[u8]) -> coset::Result<Self>88     pub fn from_cbor_slice(data: &[u8]) -> coset::Result<Self> {
89         let value = Value::from_slice(data)?;
90         let Value::Array(mut arr) = value else {
91             return Err(CoseError::UnexpectedItem(cbor_value_type(&value), "array"));
92         };
93         if arr.len() != 2 {
94             return Err(CoseError::UnexpectedItem("array", "array with 2 items"));
95         }
96         Ok(Self {
97             challenge: value_to_bytes(arr.remove(1), "challenge")?,
98             public_key: value_to_bytes(arr.remove(0), "public_key")?,
99         })
100     }
101 }
102