blob: f14787fcfc57e604f0274163835a9d3351ab3c1f [file] [log] [blame]
Alice Wang4e3015d2023-10-10 09:35:37 +00001// 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
18use alloc::vec;
19use alloc::vec::Vec;
20use ciborium::Value;
21use coset::{self, CborSerializable, CoseError};
Alice Wang6b21a662023-11-09 14:04:35 +000022use log::error;
Alice Wang4e3015d2023-10-10 09:35:37 +000023
24/// Represents a CSR sent from the client VM to the service VM for attestation.
Alice Wang9aeb4062023-10-30 14:19:38 +000025///
26/// See client_vm_csr.cddl for the definition of the CSR.
Alice Wang4e3015d2023-10-10 09:35:37 +000027#[derive(Clone, Debug, Eq, PartialEq)]
28pub 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
38impl Csr {
39 /// Serializes this object to a CBOR-encoded vector.
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.
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 {
Alice Wanga95dae52023-12-06 09:30:22 +000058 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")?,
Alice Wang4e3015d2023-10-10 09:35:37 +000060 })
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)]
70pub 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
80impl CsrPayload {
81 /// Serializes this object to a CBOR-encoded vector.
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.
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 {
Alice Wanga95dae52023-12-06 09:30:22 +000097 challenge: value_to_bytes(arr.remove(1), "challenge")?,
98 public_key: value_to_bytes(arr.remove(0), "public_key")?,
Alice Wang4e3015d2023-10-10 09:35:37 +000099 })
100 }
101}
102
Alice Wanga95dae52023-12-06 09:30:22 +0000103/// Converts the provided value `v` to bytes array.
104pub fn value_to_bytes(v: Value, context: &'static str) -> coset::Result<Vec<u8>> {
105 v.into_bytes().map_err(|e| to_unexpected_item_error(&e, "bstr", context))
106}
107
108/// Builds a `CoseError::UnexpectedItem` error when the provided value `v` is not of the expected
109/// type `expected_type` and logs the error message with the provided `context`.
110pub fn to_unexpected_item_error(
111 v: &Value,
112 expected_type: &'static str,
113 context: &'static str,
114) -> CoseError {
115 let v_type = cbor_value_type(v);
116 assert!(v_type != expected_type);
117 error!("The provided value type '{v_type}' is not of type '{expected_type}': {context}");
118 CoseError::UnexpectedItem(v_type, expected_type)
Alice Wang4e3015d2023-10-10 09:35:37 +0000119}
120
Alice Wangd3a96402023-11-24 15:37:39 +0000121/// Reads the type of the provided value `v`.
122pub fn cbor_value_type(v: &Value) -> &'static str {
Alice Wang4e3015d2023-10-10 09:35:37 +0000123 match v {
124 Value::Integer(_) => "int",
125 Value::Bytes(_) => "bstr",
126 Value::Float(_) => "float",
127 Value::Text(_) => "tstr",
128 Value::Bool(_) => "bool",
129 Value::Null => "nul",
130 Value::Tag(_, _) => "tag",
131 Value::Array(_) => "array",
132 Value::Map(_) => "map",
133 _ => "other",
134 }
135}