feat(mbedtls/esp_crt_bundle): Reduced RAM & stack use of cert bundle

Closes https://github.com/espressif/esp-idf/pull/13204

Signed-off-by: harshal.patil <harshal.patil@espressif.com>
This commit is contained in:
Hanno
2023-07-09 23:37:40 +02:00
committed by harshal.patil
parent 0be9d7d3f2
commit d8e31eb6d0
6 changed files with 264 additions and 132 deletions

View File

@@ -8,18 +8,16 @@
# The bundle will have the format: number of certificates; crt 1 subject name length; crt 1 public key length;
# crt 1 subject name; crt 1 public key; crt 2...
#
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
from __future__ import with_statement
import argparse
import csv
import os
import re
import struct
import sys
from io import open
DEFAULT_CERT_BUNDLE_MAX_CERTS = 200
try:
from cryptography import x509
@@ -54,9 +52,6 @@ class CertificateBundle:
self.certificates = []
self.compressed_crts = []
if os.path.isfile(ca_bundle_bin_file):
os.remove(ca_bundle_bin_file)
def add_from_path(self, crts_path):
found = False
@@ -116,11 +111,21 @@ class CertificateBundle:
self.certificates.append(x509.load_der_x509_certificate(crt_str, default_backend()))
status('Successfully added 1 certificate')
def create_bundle(self):
def create_bundle(self, max_certs=DEFAULT_CERT_BUNDLE_MAX_CERTS):
if max_certs < len(self.certificates):
critical(f'No. of certs in the certificate bundle = {len(self.certificates)} exceeds\n \
Max allowed certificates in the certificate bundle = {max_certs} \
Please update the menuconfig option with appropriate value')
raise ValueError
# Sort certificates in order to do binary search when looking up certificates
self.certificates = sorted(self.certificates, key=lambda cert: cert.subject.public_bytes(default_backend()))
bundle = struct.pack('>H', len(self.certificates))
# List of offsets in bytes from the start of the bundle to each certificate inside
offsets = []
len_offsets = 4 * len(self.certificates) # final size of the offsets list
bundle = b''
for crt in self.certificates:
""" Read the public key as DER format """
@@ -132,12 +137,18 @@ class CertificateBundle:
name_len = len(sub_name_der)
key_len = len(pub_key_der)
len_data = struct.pack('>HH', name_len, key_len)
len_data = struct.pack('<HH', name_len, key_len)
# Certificate starts at this position in the bundle
offsets.append(len_offsets + len(bundle))
bundle += len_data
bundle += sub_name_der
bundle += pub_key_der
# Output all offsets before the first certificate
bundle = struct.pack('<{0:d}L'.format(len(offsets)), *offsets) + bundle
return bundle
def add_with_filter(self, crts_path, filter_path):
@@ -182,6 +193,8 @@ def main():
help='Paths to the custom certificate folders or files to parse, parses all .pem or .der files')
parser.add_argument('--filter', '-f', help='Path to CSV-file where the second columns contains the name of the certificates \
that should be included from cacrt_all.pem')
parser.add_argument('--max-certs', '-m', help='Maximum number of certificates allowed in the certificate bundle',
type=int, default=DEFAULT_CERT_BUNDLE_MAX_CERTS)
args = parser.parse_args()
@@ -202,7 +215,7 @@ def main():
status('Successfully added %d certificates in total' % len(bundle.certificates))
crt_bundle = bundle.create_bundle()
crt_bundle = bundle.create_bundle(args.max_certs)
with open(ca_bundle_bin_file, 'wb') as f:
f.write(crt_bundle)