CloverBootloader/Library/OpensslLib/configure.py

417 lines
14 KiB
Python
Executable File

#!/usr/bin/python3
# SPDX-License-Identifier: BSD-2-Clause-Patent
import os
import sys
import json
import shutil
import pprint
import argparse
import subprocess
def openssl_configure(openssldir, target, ec = True):
""" Run openssl Configure script. """
cmdline = [
'perl',
'Configure',
'--config=../UefiAsm.conf',
'--api=1.1.1',
'--with-rand-seed=none',
target,
'no-afalgeng',
'no-aria',
'no-async',
'no-autoerrinit',
'no-autoload-config',
'no-bf',
'no-blake2',
'no-camellia',
'no-capieng',
'no-cast',
'no-chacha',
'no-cmac',
'no-cmp',
'no-cms',
'no-ct',
'no-deprecated',
'no-des',
'no-dgram',
'no-dsa',
'no-dso',
'no-dtls',
'no-dtls1-method',
'no-dtls1_2-method',
'no-dynamic-engine',
'no-ec2m',
'no-engine',
'no-err',
'no-filenames',
'no-gost',
'no-hw',
'no-idea',
'no-ktls',
'no-makedepend',
'no-module',
'no-md4',
'no-mdc2',
'no-multiblock',
'no-nextprotoneg',
'no-pic',
'no-psk',
'no-ocb',
'no-ocsp',
'no-padlockeng',
'no-poly1305',
'no-posix-io',
'no-rc2',
'no-rc4',
'no-rc5',
'no-rfc3779',
'no-rmd160',
'no-scrypt',
'no-seed',
'no-shared',
'no-siphash',
'no-siv',
'no-sm2',
'no-sm4',
'no-sock',
'no-srp',
'no-srtp',
'no-ssl',
'no-ssl3-method',
'no-ssl-trace',
'no-static-engine',
'no-stdio',
'no-threads',
'no-tls1_3',
'no-ts',
'no-ui-console',
'no-whirlpool',
'disable-legacy',
]
if not ec:
cmdline += [ 'no-ec', ]
print('')
print(f'# -*- configure openssl for {target} (ec={ec}) -*-')
rc = subprocess.run(cmdline, cwd = openssldir,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
if rc.returncode:
print(rc.stdout)
print(rc.stderr)
sys.exit(rc.returncode)
def openssl_run_make(openssldir, target):
"""
Run make utility to generate files or cleanup.
Target can be either a string or a list of strings.
"""
cmdline = [ 'make', '--silent' ]
if isinstance(target, list):
cmdline += target
else:
cmdline += [ target, ]
rc = subprocess.run(cmdline, cwd = openssldir)
rc.check_returncode()
def get_configdata(openssldir):
"""
Slurp openssl config data as JSON,
using a little perl helper script.
"""
cmdline = [
'perl',
'perl2json.pl',
openssldir,
]
rc = subprocess.run(cmdline, stdout = subprocess.PIPE)
rc.check_returncode()
return json.loads(rc.stdout)
def is_asm(filename):
""" Check whenevr the passed file is an assembler file """
if filename.endswith('.s') or filename.endswith('.S'):
return True
return False
def copy_generated_file(src, dst):
src_file = []
with open(src, 'r') as fsrc:
src_file = fsrc.readlines()
with open(dst, 'w') as fdst:
for lines in range(len(src_file)):
s = src_file[lines]
s = s.rstrip() + "\r\n"
fdst.write(s.expandtabs())
def generate_files(openssldir, opensslgendir, asm, filelist):
"""
Generate files, using make, and copy over the results to the
directory tree for generated openssl files. Creates
subdirectories as needed.
"""
openssl_run_make(openssldir, filelist)
for filename in filelist:
src = os.path.join(openssldir, filename)
if is_asm(filename):
""" rename MSFT asm files to .nasm """
if 'IA32-MSFT' in asm:
filename = filename.replace('.S', '.nasm')
elif 'X64-MSFT' in asm:
filename = filename.replace('.s', '.nasm')
dst = os.path.join(opensslgendir, asm, filename)
else:
dst = os.path.join(opensslgendir, filename)
os.makedirs(os.path.dirname(dst), exist_ok = True)
copy_generated_file(src, dst)
def generate_include_files(openssldir, opensslgendir, asm, cfg):
""" Generate openssl include files """
print('# generate include files')
filelist = cfg['unified_info']['generate'].keys()
filelist = list(filter(lambda f: 'include' in f, filelist))
generate_files(openssldir, opensslgendir, asm, filelist)
def generate_library_files(openssldir, opensslgendir, asm, cfg, obj):
"""
Generate openssl source files for a given library. Handles
mostly assembler files, but a few C sources are generated too.
"""
filelist = get_source_list(cfg, obj, True)
if filelist:
print(f'# generate source files for {obj}')
generate_files(openssldir, opensslgendir, asm, filelist)
def generate_all_files(openssldir, opensslgendir, asm, cfg):
""" Generate all files needed. """
generate_include_files(openssldir, opensslgendir, asm, cfg)
generate_library_files(openssldir, opensslgendir, asm, cfg, 'libcrypto')
generate_library_files(openssldir, opensslgendir, asm, cfg, 'providers/libcommon.a')
generate_library_files(openssldir, opensslgendir, asm, cfg, 'libssl')
def get_source_list(cfg, obj, gen):
"""
Gets the list of source files needed to create a specific object.
* If 'gen' is True the function returns the list of generated
files.
* If 'gen' is False the function returns the list of files not
generated (which are used from the submodule directly).
Note: Will call itself recursively to resolve nested dependencies.
"""
sources = cfg['unified_info']['sources']
generate = cfg['unified_info']['generate']
srclist = []
if sources.get(obj):
for item in sources.get(obj):
srclist += get_source_list(cfg, item, gen)
else:
is_generated = generate.get(obj) is not None
if is_generated == gen:
srclist += [ obj, ]
return srclist
def asm_filter_fn(filename):
"""
Filter asm source and define lists. Drops files we don't want include.
"""
exclude = [
'/bn/',
'OPENSSL_BN_ASM',
'OPENSSL_IA32_SSE2',
'/ec/',
'ECP_NISTZ256_ASM',
'X25519_ASM',
]
for item in exclude:
if item in filename:
return False
return True
def get_sources(cfg, obj, asm):
"""
Get the list of all sources files. Will fetch both generated
and not generated file lists and update the paths accordingly, so
the openssl submodule or the sub-tree for generated files is
referenced as needed.
"""
srclist = get_source_list(cfg, obj, False)
genlist = get_source_list(cfg, obj, True)
srclist = list(map(lambda x: f'$(OPENSSL_PATH)/{x}', srclist))
c_list = list(map(lambda x: f'$(OPENSSL_GEN_PATH)/{x}',
filter(lambda x: not is_asm(x), genlist)))
asm_list = list(map(lambda x: f'$(OPENSSL_GEN_PATH)/{asm}/{x}',
filter(is_asm, genlist)))
asm_list = list(filter(asm_filter_fn, asm_list))
return srclist + c_list + asm_list
def sources_filter_fn(filename):
"""
Filter source lists. Drops files we don't want include or
need replace with our own uefi-specific version.
"""
exclude = [
'randfile.c',
'/store/',
'/storemgmt/',
'/encode_decode/encode',
'/pkcs12/',
'statem_srvr.c',
'extensions_srvr.c',
'defltprov.c',
'baseprov.c',
'provider_predefined.c',
'ecp_nistz256.c',
'x86_64-gcc.c',
]
for item in exclude:
if item in filename:
return False
return True
def libcrypto_sources(cfg, asm = None):
""" Get source file list for libcrypto """
files = get_sources(cfg, 'libcrypto', asm)
files += get_sources(cfg, 'providers/libcommon.a', asm)
files = list(filter(sources_filter_fn, files))
return files
def libssl_sources(cfg, asm = None):
""" Get source file list for libssl """
files = get_sources(cfg, 'libssl', asm)
files = list(filter(sources_filter_fn, files))
return files
def update_inf(filename, sources, arch = None, defines = []):
"""
Update inf file, replace source file list and build flags.
"""
head = ''
tail = ''
state = 0
if arch:
section = f'Sources.{arch}'
flags = f'OPENSSL_FLAGS_{arch}'
else:
section = None
flags = f'OPENSSL_FLAGS_NOASM'
state = 1
# read and parse file
with open(filename, 'r') as f:
while True:
line = f.readline()
if line == '':
break
if state in [0, 1]:
if flags in line:
(keep, replace) = line.split('=')
args = map(lambda x: f'-D{x}', defines)
head += keep + '= ' + ' '.join(args)
head = head.rstrip() + '\r\n'
else:
head += line.rstrip() + '\r\n'
if state == 0 and section in line:
state = 1
if state == 1 and 'Autogenerated files list starts here' in line:
state = 2
if state == 2 and 'Autogenerated files list ends here' in line:
state = 3
if state == 3:
tail += line.rstrip() + '\r\n'
# write updated file
with open(filename, 'w') as f:
f.write(head)
for src in sources:
f.write(f' {src}\r\n')
f.write(tail)
def update_MSFT_asm_format(asm, filelist):
""" rename MSFT asm files to .nasm """
if 'IA32-MSFT' in asm:
for file_index in range(len(filelist)):
filelist[file_index] = filelist[file_index].replace('.S', '.nasm')
elif 'X64-MSFT' in asm:
for file_index in range(len(filelist)):
filelist[file_index] = filelist[file_index].replace('.s', '.nasm')
def main():
# prepare
os.chdir(os.path.dirname(os.path.abspath(__file__)))
openssldir = os.path.join(os.getcwd(), 'openssl')
opensslgendir = os.path.join(os.getcwd(), 'OpensslGen')
# asm accel configs (see UefiAsm.conf)
for ec in [True, False]:
if ec:
inf = 'OpensslLibFullAccel.inf'
hdr = 'configuration-ec.h'
else:
inf = 'OpensslLibAccel.inf'
hdr = 'configuration-noec.h'
sources = {}
defines = {}
for asm in [ 'UEFI-IA32-MSFT', 'UEFI-IA32-GCC',
'UEFI-X64-MSFT', 'UEFI-X64-GCC']:
(uefi, arch, cc) = asm.split('-')
archcc = f'{arch}-{cc}'
openssl_configure(openssldir, asm, ec = ec);
cfg = get_configdata(openssldir)
generate_all_files(openssldir, opensslgendir, archcc, cfg)
shutil.move(os.path.join(opensslgendir, 'include', 'openssl', 'configuration.h'),
os.path.join(opensslgendir, 'include', 'openssl', hdr))
openssl_run_make(openssldir, 'distclean')
srclist = libcrypto_sources(cfg, archcc) + libssl_sources(cfg, archcc)
sources[archcc] = list(map(lambda x: f'{x} | {cc}', filter(is_asm, srclist)))
update_MSFT_asm_format(archcc, sources[archcc])
sources[arch] = list(filter(lambda x: not is_asm(x), srclist))
defines[arch] = cfg['unified_info']['defines']['libcrypto']
defines[arch] = list(filter(asm_filter_fn, defines[arch]))
ia32accel = sources['IA32'] + sources['IA32-MSFT'] + sources['IA32-GCC']
x64accel = sources['X64'] + sources['X64-MSFT'] + sources['X64-GCC']
update_inf(inf, ia32accel, 'IA32', defines['IA32'])
update_inf(inf, x64accel, 'X64', defines['X64'])
# noaccel - ec enabled
openssl_configure(openssldir, 'UEFI', ec = True);
cfg = get_configdata(openssldir)
generate_all_files(openssldir, opensslgendir, None, cfg)
openssl_run_make(openssldir, 'distclean')
defines = []
if 'libcrypto' in cfg['unified_info']['defines']:
defines = cfg['unified_info']['defines']['libcrypto']
update_inf('OpensslLibFull.inf',
libcrypto_sources(cfg) + libssl_sources(cfg),
defines)
# noaccel - ec disabled
openssl_configure(openssldir, 'UEFI', ec = False);
cfg = get_configdata(openssldir)
generate_all_files(openssldir, opensslgendir, None, cfg)
openssl_run_make(openssldir, 'distclean')
update_inf('OpensslLibCrypto.inf',
libcrypto_sources(cfg),
None, defines)
update_inf('OpensslLib.inf',
libcrypto_sources(cfg) + libssl_sources(cfg),
None, defines)
# wrap header file
confighdr = os.path.join(opensslgendir, 'include', 'openssl', 'configuration.h')
with open(confighdr, 'w') as f:
f.write('#ifdef EDK2_OPENSSL_NOEC\r\n'
'# include "configuration-noec.h"\r\n'
'#else\r\n'
'# include "configuration-ec.h"\r\n'
'#endif\r\n')
if __name__ == '__main__':
sys.exit(main())