blob: e913bb51e040b73ed843becef70d6784288fc82f [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};
22
23/// Represents a CSR sent from the client VM to the service VM for attestation.
Alice Wang9aeb4062023-10-30 14:19:38 +000024///
25/// See client_vm_csr.cddl for the definition of the CSR.
Alice Wang4e3015d2023-10-10 09:35:37 +000026#[derive(Clone, Debug, Eq, PartialEq)]
27pub struct Csr {
28 /// The DICE certificate chain of the client VM.
29 pub dice_cert_chain: Vec<u8>,
30
31 /// The signed CSR payload in COSE_Sign structure, which includes two signatures:
32 /// - one by CDI_Leaf_Priv of the client VM's DICE chain,
33 /// - another by the private key corresponding to the public key.
34 pub signed_csr_payload: Vec<u8>,
35}
36
37impl Csr {
38 /// Serializes this object to a CBOR-encoded vector.
39 pub fn into_cbor_vec(self) -> coset::Result<Vec<u8>> {
40 let value = Value::Array(vec![
41 Value::Bytes(self.dice_cert_chain),
42 Value::Bytes(self.signed_csr_payload),
43 ]);
44 value.to_vec()
45 }
46
47 /// Creates an object instance from the provided CBOR-encoded slice.
48 pub fn from_cbor_slice(data: &[u8]) -> coset::Result<Self> {
49 let value = Value::from_slice(data)?;
50 let Value::Array(mut arr) = value else {
51 return Err(CoseError::UnexpectedItem(cbor_value_type(&value), "array"));
52 };
53 if arr.len() != 2 {
54 return Err(CoseError::UnexpectedItem("array", "array with 2 items"));
55 }
56 Ok(Self {
57 signed_csr_payload: try_as_bytes(arr.remove(1))?,
58 dice_cert_chain: try_as_bytes(arr.remove(0))?,
59 })
60 }
61}
62
63/// Represents the data to be signed and sent from the client VM to the service VM
64/// for attestation.
65///
66/// It will be signed by both CDI_Leaf_Priv of the client VM's DICE chain and
67/// the private key corresponding to the public key to be attested.
68#[derive(Clone, Debug, Eq, PartialEq)]
69pub struct CsrPayload {
70 /// COSE_Key encoded EC P-256 public key to be attested.
71 pub public_key: Vec<u8>,
72
73 /// A random array with a length between 0 and 64.
74 /// It will be included in the certificate chain in the attestation result,
75 /// serving as proof of the freshness of the result.
76 pub challenge: Vec<u8>,
77}
78
79impl CsrPayload {
80 /// Serializes this object to a CBOR-encoded vector.
81 pub fn into_cbor_vec(self) -> coset::Result<Vec<u8>> {
82 let value = Value::Array(vec![Value::Bytes(self.public_key), Value::Bytes(self.challenge)]);
83 value.to_vec()
84 }
85
86 /// Creates an object instance from the provided CBOR-encoded slice.
87 pub fn from_cbor_slice(data: &[u8]) -> coset::Result<Self> {
88 let value = Value::from_slice(data)?;
89 let Value::Array(mut arr) = value else {
90 return Err(CoseError::UnexpectedItem(cbor_value_type(&value), "array"));
91 };
92 if arr.len() != 2 {
93 return Err(CoseError::UnexpectedItem("array", "array with 2 items"));
94 }
95 Ok(Self {
96 challenge: try_as_bytes(arr.remove(1))?,
97 public_key: try_as_bytes(arr.remove(0))?,
98 })
99 }
100}
101
102fn try_as_bytes(v: Value) -> coset::Result<Vec<u8>> {
103 if let Value::Bytes(data) = v {
104 Ok(data)
105 } else {
106 Err(CoseError::UnexpectedItem(cbor_value_type(&v), "bytes"))
107 }
108}
109
110fn cbor_value_type(v: &Value) -> &'static str {
111 match v {
112 Value::Integer(_) => "int",
113 Value::Bytes(_) => "bstr",
114 Value::Float(_) => "float",
115 Value::Text(_) => "tstr",
116 Value::Bool(_) => "bool",
117 Value::Null => "nul",
118 Value::Tag(_, _) => "tag",
119 Value::Array(_) => "array",
120 Value::Map(_) => "map",
121 _ => "other",
122 }
123}