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