xref: /aosp_15_r20/external/open-dice/generate_test_values.py (revision 60b67249c2e226f42f35cc6cfe66c6048e0bae6b)
1# Copyright 2020 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://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, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14#
15# Lint as: python3
16"""Generates known_test_values.h from dumped test values.
17
18This program generates the known_test_values.h file used for unit tests. This is
19useful to correct the baseline test values based on dumps from the tests. Use
20this after fixing a bug in the code, not to 'fix' test breakage not well
21understood.
22
23Usage:
24  $ cd out
25  $ python ../generate_test_values.py > ../include/dice/known_test_values.h
26
27Prerequisites:
28  pip install absl-py
29"""
30
31from __future__ import print_function
32
33import re
34import subprocess
35import textwrap
36
37from absl import app
38from absl import flags
39
40FLAGS = flags.FLAGS
41
42_FILE_HEADER = textwrap.dedent(
43    """\
44    // Copyright 2020 Google LLC
45    //
46    // Licensed under the Apache License, Version 2.0 (the "License"); you may not
47    // use this file except in compliance with the License. You may obtain a copy of
48    // the License at
49    //
50    //     https://www.apache.org/licenses/LICENSE-2.0
51    //
52    // Unless required by applicable law or agreed to in writing, software
53    // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
54    // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
55    // License for the specific language governing permissions and limitations under
56    // the License.
57
58    // !!! GENERATED - DO NOT MODIFY !!!
59    // To update this file, use generate_test_values.py.
60
61    #ifndef DICE_KNOWN_TEST_VALUES_H_
62    #define DICE_KNOWN_TEST_VALUES_H_
63
64    #include <stdint.h>
65
66    namespace dice {
67    namespace test {
68
69                               """
70)
71
72_FILE_FOOTER = textwrap.dedent(
73    """\
74    }  // namespace test
75    }  // namespace dice
76
77    #endif  // DICE_KNOWN_TEST_VALUES_H_
78                               """
79)
80
81
82def _to_camel_case(s):
83    return "".join(tmp.capitalize() for tmp in s.split("_"))
84
85
86def _read_file(name):
87    try:
88        with open(name, "rb") as f:
89            return f.read()
90    except OSError:
91        return ""
92
93
94def _generate_array(name, data):
95    return "constexpr uint8_t %s[%d] = {%s};\n\n" % (
96        name,
97        len(data),
98        ", ".join("0x%02x" % tmp for tmp in data),
99    )
100
101
102def _generate_cert_comment(data):
103    return re.sub(
104        "^",
105        "// ",
106        subprocess.run(
107            [
108                "openssl",
109                "x509",
110                "-inform",
111                "DER",
112                "-noout",
113                "-text",
114                "-certopt",
115                "ext_parse",
116            ],
117            input=data,
118            capture_output=True,
119            check=True,
120        ).stdout.decode(),
121        flags=re.MULTILINE,
122    )[:-3]
123
124
125def _generate_c(name):
126    """Generates C declarations from dumps identified by |name|."""
127    content = ""
128    attest_cdi_data = _read_file("_attest_cdi_%s.bin" % name)
129    content += _generate_array(
130        "kExpectedCdiAttest_%s" % _to_camel_case(name), attest_cdi_data
131    )
132    seal_cdi_data = _read_file("_seal_cdi_%s.bin" % name)
133    content += _generate_array(
134        "kExpectedCdiSeal_%s" % _to_camel_case(name), seal_cdi_data
135    )
136    for cert_type in ("X509", "CBOR"):
137        for key_type in ("Ed25519", "P256", "P384"):
138            var_name = "kExpected%s%sCert_%s" % (
139                _to_camel_case(cert_type),
140                _to_camel_case(key_type),
141                _to_camel_case(name),
142            )
143            cert_data = _read_file(
144                "_%s_%s_cert_%s.cert" % (cert_type, key_type, name)
145            )
146            if cert_type == "X509" and key_type != "P384":
147                content += (
148                    "// $ openssl x509 -inform DER -noout -text -certopt "
149                    "ext_parse\n"
150                )
151                content += _generate_cert_comment(cert_data)
152            content += _generate_array(var_name, cert_data)
153    return content
154
155
156def main(argv):
157    if len(argv) > 1:
158        raise app.UsageError("Too many command-line arguments.")
159
160    content = _FILE_HEADER
161    content += _generate_c("zero_input")
162    content += _generate_c("hash_only_input")
163    content += _generate_c("descriptor_input")
164    content += _FILE_FOOTER
165    subprocess.run(
166        ["clang-format", "--style=file"], input=content.encode(), check=True
167    )
168
169
170if __name__ == "__main__":
171    app.run(main)
172