Initial drop
Change-Id: I987ee6af6960bf2552628ee094cd656bf9e5f2fa
Reviewed-on: https://pigweed-review.googlesource.com/c/open-dice/+/31966
Reviewed-by: Ali Zhang <alizhang@google.com>
diff --git a/generate_test_values.py b/generate_test_values.py
new file mode 100644
index 0000000..953ef82
--- /dev/null
+++ b/generate_test_values.py
@@ -0,0 +1,148 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+#
+# Lint as: python3
+"""Generates known_test_values.h from dumped test values.
+
+This program generates the known_test_values.h file used for unit tests. This is
+useful to correct the baseline test values based on dumps from the tests. Use
+this after fixing a bug in the code, not to 'fix' test breakage not well
+understood.
+
+Usage:
+ $ cd out
+ $ python ../generate_test_values.py > ../include/dice/known_test_values.h
+
+Prerequisites:
+ pip install absl-py
+"""
+
+from __future__ import print_function
+
+import re
+import subprocess
+import textwrap
+
+from absl import app
+from absl import flags
+
+FLAGS = flags.FLAGS
+
+_FILE_HEADER = textwrap.dedent("""\
+ // Copyright 2020 Google LLC
+ //
+ // Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ // use this file except in compliance with the License. You may obtain a copy of
+ // the License at
+ //
+ // https://www.apache.org/licenses/LICENSE-2.0
+ //
+ // Unless required by applicable law or agreed to in writing, software
+ // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ // License for the specific language governing permissions and limitations under
+ // the License.
+
+ // !!! GENERATED - DO NOT MODIFY !!!
+ // To update this file, use generate_test_values.py.
+
+ #ifndef DICE_KNOWN_TEST_VALUES_H_
+ #define DICE_KNOWN_TEST_VALUES_H_
+
+ #include <stdint.h>
+
+ namespace dice {
+ namespace test {
+
+ """)
+
+_FILE_FOOTER = textwrap.dedent("""\
+ } // namespace test
+ } // namespace dice
+
+ #endif // DICE_KNOWN_TEST_VALUES_H_
+ """)
+
+
+def _to_camel_case(s):
+ return ''.join(tmp.capitalize() for tmp in s.split('_'))
+
+
+def _read_file(name):
+ try:
+ with open(name, 'rb') as f:
+ return f.read()
+ except OSError:
+ return ''
+
+
+def _generate_array(name, data):
+ return 'constexpr uint8_t %s[%d] = {%s};\n\n' % (
+ name, len(data), ', '.join('0x%02x' % tmp for tmp in data))
+
+
+def _generate_cert_comment(data):
+ return re.sub('^',
+ '// ',
+ subprocess.run([
+ 'openssl', 'x509', '-inform', 'DER', '-noout', '-text',
+ '-certopt', 'ext_parse'
+ ],
+ input=data,
+ capture_output=True,
+ check=True).stdout.decode(),
+ flags=re.MULTILINE)[:-3]
+
+
+def _generate_c(name):
+ """Generates C declarations from dumps identified by |name|."""
+ content = ''
+ attest_cdi_data = _read_file('_attest_cdi_%s.bin' % name)
+ content += _generate_array('kExpectedCdiAttest_%s' % _to_camel_case(name),
+ attest_cdi_data)
+ seal_cdi_data = _read_file('_seal_cdi_%s.bin' % name)
+ content += _generate_array('kExpectedCdiSeal_%s' % _to_camel_case(name),
+ seal_cdi_data)
+ for cert_type in ('X509', 'CBOR'):
+ for key_type in ('Ed25519', 'P256'):
+ var_name = 'kExpected%s%sCert_%s' % (_to_camel_case(cert_type),
+ _to_camel_case(key_type),
+ _to_camel_case(name))
+ cert_data = _read_file('_%s_%s_cert_%s.cert' %
+ (cert_type, key_type, name))
+ if cert_type == 'X509':
+ content += (
+ '// $ openssl x509 -inform DER -noout -text -certopt '
+ 'ext_parse\n')
+ content += _generate_cert_comment(cert_data)
+ content += _generate_array(var_name, cert_data)
+ return content
+
+
+def main(argv):
+ if len(argv) > 1:
+ raise app.UsageError('Too many command-line arguments.')
+
+ content = _FILE_HEADER
+ content += _generate_c('zero_input')
+ content += _generate_c('hash_only_input')
+ content += _generate_c('descriptor_input')
+ content += _FILE_FOOTER
+ subprocess.run(['clang-format', '--style=file'],
+ input=content.encode(),
+ check=True)
+
+
+if __name__ == '__main__':
+ app.run(main)