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 // Copyright 2020 Google LLC 44 // 45 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 46 // use this file except in compliance with the License. You may obtain a copy of 47 // the License at 48 // 49 // https://www.apache.org/licenses/LICENSE-2.0 50 // 51 // Unless required by applicable law or agreed to in writing, software 52 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 53 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 54 // License for the specific language governing permissions and limitations under 55 // the License. 56 57 // !!! GENERATED - DO NOT MODIFY !!! 58 // To update this file, use generate_test_values.py. 59 60 #ifndef DICE_KNOWN_TEST_VALUES_H_ 61 #define DICE_KNOWN_TEST_VALUES_H_ 62 63 #include <stdint.h> 64 65 namespace dice { 66 namespace test { 67 68 """) 69 70_FILE_FOOTER = textwrap.dedent("""\ 71 } // namespace test 72 } // namespace dice 73 74 #endif // DICE_KNOWN_TEST_VALUES_H_ 75 """) 76 77 78def _to_camel_case(s): 79 return ''.join(tmp.capitalize() for tmp in s.split('_')) 80 81 82def _read_file(name): 83 try: 84 with open(name, 'rb') as f: 85 return f.read() 86 except OSError: 87 return '' 88 89 90def _generate_array(name, data): 91 return 'constexpr uint8_t %s[%d] = {%s};\n\n' % ( 92 name, len(data), ', '.join('0x%02x' % tmp for tmp in data)) 93 94 95def _generate_cert_comment(data): 96 return re.sub('^', 97 '// ', 98 subprocess.run([ 99 'openssl', 'x509', '-inform', 'DER', '-noout', '-text', 100 '-certopt', 'ext_parse' 101 ], 102 input=data, 103 capture_output=True, 104 check=True).stdout.decode(), 105 flags=re.MULTILINE)[:-3] 106 107 108def _generate_c(name): 109 """Generates C declarations from dumps identified by |name|.""" 110 content = '' 111 attest_cdi_data = _read_file('_attest_cdi_%s.bin' % name) 112 content += _generate_array('kExpectedCdiAttest_%s' % _to_camel_case(name), 113 attest_cdi_data) 114 seal_cdi_data = _read_file('_seal_cdi_%s.bin' % name) 115 content += _generate_array('kExpectedCdiSeal_%s' % _to_camel_case(name), 116 seal_cdi_data) 117 for cert_type in ('X509', 'CBOR'): 118 for key_type in ('Ed25519', 'P256'): 119 var_name = 'kExpected%s%sCert_%s' % (_to_camel_case(cert_type), 120 _to_camel_case(key_type), 121 _to_camel_case(name)) 122 cert_data = _read_file('_%s_%s_cert_%s.cert' % 123 (cert_type, key_type, name)) 124 if cert_type == 'X509': 125 content += ( 126 '// $ openssl x509 -inform DER -noout -text -certopt ' 127 'ext_parse\n') 128 content += _generate_cert_comment(cert_data) 129 content += _generate_array(var_name, cert_data) 130 return content 131 132 133def main(argv): 134 if len(argv) > 1: 135 raise app.UsageError('Too many command-line arguments.') 136 137 content = _FILE_HEADER 138 content += _generate_c('zero_input') 139 content += _generate_c('hash_only_input') 140 content += _generate_c('descriptor_input') 141 content += _FILE_FOOTER 142 subprocess.run(['clang-format', '--style=file'], 143 input=content.encode(), 144 check=True) 145 146 147if __name__ == '__main__': 148 app.run(main) 149