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