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)