blob: 68ca3821a20d68846741ea5e4fb58b3cbeeecf74 [file] [log] [blame]
Alice Wang20b8ebc2023-11-17 09:54:47 +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//! Generation of certificates and attestation extensions.
16
17use alloc::vec;
18use der::{
19 asn1::{BitStringRef, ObjectIdentifier, UIntRef},
20 oid::AssociatedOid,
21 Decode, Sequence,
22};
23use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo};
24use x509_cert::{
25 certificate::{Certificate, TbsCertificate, Version},
26 ext::Extension,
27 name::Name,
28 time::Validity,
29};
30
31/// OID value for ECDSA with SHA-256, see RFC 5912 s6.
32const ECDSA_WITH_SHA_256: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.2");
33
34/// OID value for the protected VM remote attestation extension.
35///
36/// This OID value was added at cl/584542390.
37const AVF_ATTESTATION_EXTENSION_V1: ObjectIdentifier =
38 ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11129.2.1.29.1");
39
40/// Attestation extension contents
41///
42/// ```asn1
43/// AttestationDescription ::= SEQUENCE {
44/// attestationChallenge OCTET_STRING,
45/// }
46/// ```
47/// TODO(b/312448064): Add VM root of trust and payload information to the extension.
48#[derive(Debug, Clone, Sequence)]
49pub(crate) struct AttestationExtension<'a> {
50 #[asn1(type = "OCTET STRING")]
51 attestation_challenge: &'a [u8],
52}
53
54impl<'a> AssociatedOid for AttestationExtension<'a> {
55 const OID: ObjectIdentifier = AVF_ATTESTATION_EXTENSION_V1;
56}
57
58impl<'a> AttestationExtension<'a> {
59 pub(crate) fn new(challenge: &'a [u8]) -> Self {
60 Self { attestation_challenge: challenge }
61 }
62}
63
64/// Builds an X.509 `Certificate` as defined in RFC 5280 Section 4.1:
65///
66/// ```asn1
67/// Certificate ::= SEQUENCE {
68/// tbsCertificate TBSCertificate,
69/// signatureAlgorithm AlgorithmIdentifier,
70/// signature BIT STRING
71/// }
72/// ```
73pub(crate) fn build_certificate<'a>(
74 tbs_cert: TbsCertificate<'a>,
75 signature: &'a [u8],
76) -> der::Result<Certificate<'a>> {
77 Ok(Certificate {
78 signature_algorithm: tbs_cert.signature,
79 tbs_certificate: tbs_cert,
80 signature: BitStringRef::new(0, signature)?,
81 })
82}
83
84/// Builds an X.509 `TbsCertificate` as defined in RFC 5280 Section 4.1:
85///
86/// ```asn1
87/// TBSCertificate ::= SEQUENCE {
88/// version [0] EXPLICIT Version DEFAULT v1,
89/// serialNumber CertificateSerialNumber,
90/// signature AlgorithmIdentifier,
91/// issuer Name,
92/// validity Validity,
93/// subject Name,
94/// subjectPublicKeyInfo SubjectPublicKeyInfo,
95/// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
96/// -- If present, version MUST be v2 or v3
97/// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
98/// -- If present, version MUST be v2 or v3
99/// extensions [3] Extensions OPTIONAL
100/// -- If present, version MUST be v3 --
101/// }
102/// ```
103pub(crate) fn build_tbs_certificate<'a>(
104 serial_number: &'a [u8],
105 issuer: Name<'a>,
106 subject: Name<'a>,
107 validity: Validity,
108 subject_public_key_info: &'a [u8],
109 attestation_ext: &'a [u8],
110) -> der::Result<TbsCertificate<'a>> {
111 let signature = AlgorithmIdentifier { oid: ECDSA_WITH_SHA_256, parameters: None };
112 let subject_public_key_info = SubjectPublicKeyInfo::from_der(subject_public_key_info)?;
113 let extensions = vec![Extension {
114 extn_id: AttestationExtension::OID,
115 critical: false,
116 extn_value: attestation_ext,
117 }];
118 Ok(TbsCertificate {
119 version: Version::V3,
120 serial_number: UIntRef::new(serial_number)?,
121 signature,
122 issuer,
123 validity,
124 subject,
125 subject_public_key_info,
126 issuer_unique_id: None,
127 subject_unique_id: None,
128 extensions: Some(extensions),
129 })
130}