#!/usr/bin/perl -w # # This script runs the OpenSSL Configure script, then processes the # resulting file list into our local OpensslLib[Crypto].inf and also # takes copies of opensslconf.h and dso_conf.h. # # This only needs to be done once by a developer when updating to a # new version of OpenSSL (or changing options, etc.). Normal users # do not need to do this, since the results are stored in the EDK2 # git repository for them. # # Due to the script wrapping required to process the OpenSSL # configuration data, each native architecture must be processed # individually by the maintainer (in addition to the standard version): # ./process_files.pl # ./process_files.pl X64 # ./process_files.pl [Arch] use strict; use Cwd; use File::Copy; use File::Basename; use File::Path qw(make_path remove_tree); use Text::Tabs; my $comment_character; # # OpenSSL perlasm generator script does not transfer the copyright header # sub copy_license_header { my @args = split / /, shift; #Separate args by spaces my $source = $args[1]; #Source file is second (after "perl") my $target = pop @args; #Target file is always last chop ($target); #Remove newline char my $temp_file_name = "license.tmp"; open (my $source_file, "<" . $source) || die $source; open (my $target_file, "<" . $target) || die $target; open (my $temp_file, ">" . $temp_file_name) || die $temp_file_name; #Add "generated file" warning $source =~ s/^..//; #Remove leading "./" print ($temp_file "$comment_character WARNING: do not edit!\r\n"); print ($temp_file "$comment_character Generated from $source\r\n"); print ($temp_file "$comment_character\r\n"); #Copy source file header to temp file while (my $line = <$source_file>) { next if ($line =~ /#!/); #Ignore shebang line $line =~ s/#/$comment_character/; #Fix comment character for assembly $line =~ s/\s+$/\r\n/; #Trim trailing whitepsace, fixup line endings print ($temp_file $line); last if ($line =~ /http/); #Last line of copyright header contains a web link } print ($temp_file "\r\n"); #Retrieve generated assembly contents while (my $line = <$target_file>) { $line =~ s/\s+$/\r\n/; #Trim trailing whitepsace, fixup line endings print ($temp_file expand ($line)); #expand() replaces tabs with spaces } close ($source_file); close ($target_file); close ($temp_file); move ($temp_file_name, $target) || die "Cannot replace \"" . $target . "\"!"; } # # Find the openssl directory name for use lib. We have to do this # inside of BEGIN. The variables we create here, however, don't seem # to be available to the main script, so we have to repeat the # exercise. # my $inf_file; my $OPENSSL_PATH; my $uefi_config; my $extension; my $arch; my @inf; # # Use PCD to conditionally enable certain openssl features. # $conditional_feature contains pcd_name:fetures_names pairs # of conditional features. # @conditional_feature_dir contains relative_path:pcd_name pairs # of conditional features in openssl, MUST correspond to the content # in $conditional_feature. # # Configure list [openssl_configuration : new_define_list : new_file_list : pcd] # 1. no-ec : {NO_EC, NO_ECDH, NO_ECDSA, NO_TLS1_3, NO_SM2} : {/ec/, /sm2/} : PcdOpensslEcEnabled # my %conditional_feature = ("PcdOpensslEcEnabled"=>["EC", "ECDH", "ECDSA", "TLS1_3", "SM2"]); my %conditional_feature_dir = ("/ec/"=>"PcdOpensslEcEnabled", "/sm2/"=>"PcdOpensslEcEnabled"); BEGIN { $inf_file = "OpensslLib.inf"; $uefi_config = "UEFI"; $arch = shift; if (defined $arch) { if (uc ($arch) eq "X64") { $arch = "X64"; $inf_file = "OpensslLibX64.inf"; $uefi_config = "UEFI-x86_64"; $extension = "nasm"; $comment_character = ";"; } elsif (uc ($arch) eq "X64GCC") { $arch = "X64Gcc"; $inf_file = "OpensslLibX64Gcc.inf"; $uefi_config = "UEFI-x86_64-GCC"; $extension = "S"; $comment_character = "#"; } else { die "Unsupported architecture \"" . $arch . "\"!"; } if ($extension eq "nasm") { if (`nasm -v 2>&1`) { #Presence of nasm executable will trigger inclusion of AVX instructions die "\nCannot run assembly generators with NASM in path!\n\n"; } } # Prepare assembly folder if (-d $arch) { opendir my $dir, $arch || die "Cannot open assembly folder \"" . $arch . "\"!"; while (defined (my $file = readdir $dir)) { if (-d "$arch/$file") { next if $file eq "."; next if $file eq ".."; remove_tree ("$arch/$file", {safe => 1}) || die "Cannot clean assembly folder \"" . "$arch/$file" . "\"!"; } } } else { mkdir $arch || die "Cannot create assembly folder \"" . $arch . "\"!"; } } # Read the contents of the inf file open( FD, "<" . $inf_file ) || die "Cannot open \"" . $inf_file . "\"!"; @inf = (); close(FD) || die "Cannot close \"" . $inf_file . "\"!"; foreach (@inf) { if (/DEFINE\s+OPENSSL_PATH\s*=\s*([a-z]+)/) { # We need to run Configure before we can include its result... $OPENSSL_PATH = $1; my $basedir = getcwd(); chdir($OPENSSL_PATH) || die "Cannot change to OpenSSL directory \"" . $OPENSSL_PATH . "\""; # Configure UEFI system( "./Configure", "--config=../UefiAsm.conf", "$uefi_config", "no-afalgeng", "no-async", "no-autoerrinit", "no-autoload-config", "no-bf", "no-blake2", "no-camellia", "no-capieng", "no-cast", "no-chacha", "no-cms", "no-ct", "no-deprecated", "no-des", "no-dgram", "no-dsa", "no-dynamic-engine", "no-ec2m", "no-engine", "no-err", "no-filenames", "no-gost", "no-hw", "no-idea", "no-md4", "no-mdc2", "no-pic", "no-ocb", "no-poly1305", "no-posix-io", "no-rc2", "no-rc4", "no-rfc3779", "no-rmd160", "no-scrypt", "no-seed", "no-sock", "no-srp", "no-ssl", "no-stdio", "no-threads", "no-ts", "no-ui", "no-whirlpool", # OpenSSL1_1_1b doesn't support default rand-seed-os for UEFI # UEFI only support --with-rand-seed=none "--with-rand-seed=none" ) == 0 || die "OpenSSL Configure failed!\n"; # Generate opensslconf.h per config data system( "perl -I. -Mconfigdata util/dofile.pl " . "include/openssl/opensslconf.h.in " . "> include/openssl/opensslconf.h" ) == 0 || die "Failed to generate opensslconf.h!\n"; # Generate dso_conf.h per config data system( "perl -I. -Mconfigdata util/dofile.pl " . "include/crypto/dso_conf.h.in " . "> include/crypto/dso_conf.h" ) == 0 || die "Failed to generate dso_conf.h!\n"; chdir($basedir) || die "Cannot change to base directory \"" . $basedir . "\""; push @INC, $1; last; } } } # # Retrieve file lists from OpenSSL configdata # use configdata qw/%unified_info/; use configdata qw/%config/; use configdata qw/%target/; # # Collect build flags from configdata # my $flags = ""; foreach my $f (@{$config{lib_defines}}) { $flags .= " -D$f"; } my @cryptofilelist = (); my @sslfilelist = (); my @asmfilelist = (); my @asmbuild = (); foreach my $product ((@{$unified_info{libraries}}, @{$unified_info{engines}})) { foreach my $o (@{$unified_info{sources}->{$product}}) { foreach my $s (@{$unified_info{sources}->{$o}}) { # No need to add unused files in UEFI. # So it can reduce porting time, compile time, library size. next if $s =~ "crypto/bio/b_print.c"; next if $s =~ "crypto/rand/randfile.c"; next if $s =~ "crypto/store/"; next if $s =~ "crypto/err/err_all.c"; next if $s =~ "crypto/aes/aes_ecb.c"; if ($unified_info{generate}->{$s}) { if (defined $arch) { my $buildstring = "perl"; foreach my $arg (@{$unified_info{generate}->{$s}}) { if ($arg =~ ".pl") { $buildstring .= " ./openssl/$arg"; } elsif ($arg =~ "PERLASM_SCHEME") { $buildstring .= " $target{perlasm_scheme}"; } elsif ($arg =~ "LIB_CFLAGS") { $buildstring .= "$flags"; } } ($s, my $path, undef) = fileparse($s, qr/\.[^.]*/); $buildstring .= " ./$arch/$path$s.$extension"; make_path ("./$arch/$path"); push @asmbuild, "$buildstring\n"; push @asmfilelist, " $arch/$path$s.$extension\r\n"; } next; } if ($product =~ "libssl") { push @sslfilelist, ' $(OPENSSL_PATH)/' . $s . "\r\n"; next; } push @cryptofilelist, ' $(OPENSSL_PATH)/' . $s; foreach (keys(%conditional_feature_dir)) { if ($s =~ $_) { push @cryptofilelist, ' |*|*|*|gEfiCryptoPkgTokenSpaceGuid.' . $conditional_feature_dir{$_}; } } push @cryptofilelist, "\r\n"; } } } # # Update the perl script to generate the missing header files # my @dir_list = (); for (sort keys %{$unified_info{dirinfo}}){ push @dir_list,$_; } my $dir = getcwd(); my @files = (); my @headers = (); chdir ("openssl"); foreach(@dir_list){ @files = glob($_."/*.h"); push @headers, @files; } chdir ($dir); foreach (@headers){ if(/ssl/){ push @sslfilelist, ' $(OPENSSL_PATH)/' . $_ . "\r\n"; next; } push @cryptofilelist, ' $(OPENSSL_PATH)/' . $_; foreach my $conditional_key (keys(%conditional_feature_dir)) { if ($_ =~ $conditional_key) { push @cryptofilelist, ' |*|*|*|gEfiCryptoPkgTokenSpaceGuid.' . $conditional_feature_dir{$conditional_key}; } } push @cryptofilelist, "\r\n"; } # # Generate assembly files # if (@asmbuild) { print "\n--> Generating assembly files ... "; foreach my $buildstring (@asmbuild) { system ("$buildstring"); copy_license_header ($buildstring); } print "Done!"; } # # Update OpensslLib.inf with autogenerated file list # my @new_inf = (); my $subbing = 0; print "\n--> Updating $inf_file ... "; foreach (@inf) { if ($_ =~ "DEFINE OPENSSL_FLAGS_CONFIG") { push @new_inf, " DEFINE OPENSSL_FLAGS_CONFIG =" . $flags . "\r\n"; next; } if ( $_ =~ "# Autogenerated files list starts here" ) { push @new_inf, $_, @asmfilelist, @cryptofilelist, @sslfilelist; $subbing = 1; next; } if ( $_ =~ "# Autogenerated files list ends here" ) { push @new_inf, $_; $subbing = 0; next; } push @new_inf, $_ unless ($subbing); } my $new_inf_file = $inf_file . ".new"; open( FD, ">" . $new_inf_file ) || die $new_inf_file; print( FD @new_inf ) || die $new_inf_file; close(FD) || die $new_inf_file; rename( $new_inf_file, $inf_file ) || die "rename $inf_file"; print "Done!"; if (!defined $arch) { # # Update OpensslLibCrypto.inf with auto-generated file list (no libssl) # $inf_file = "OpensslLibCrypto.inf"; # Read the contents of the inf file @inf = (); @new_inf = (); open( FD, "<" . $inf_file ) || die "Cannot open \"" . $inf_file . "\"!"; @inf = (); close(FD) || die "Cannot close \"" . $inf_file . "\"!"; $subbing = 0; print "\n--> Updating OpensslLibCrypto.inf ... "; foreach (@inf) { if ( $_ =~ "# Autogenerated files list starts here" ) { push @new_inf, $_, @cryptofilelist; $subbing = 1; next; } if ( $_ =~ "# Autogenerated files list ends here" ) { push @new_inf, $_; $subbing = 0; next; } push @new_inf, $_ unless ($subbing); } $new_inf_file = $inf_file . ".new"; open( FD, ">" . $new_inf_file ) || die $new_inf_file; print( FD @new_inf ) || die $new_inf_file; close(FD) || die $new_inf_file; rename( $new_inf_file, $inf_file ) || die "rename $inf_file"; print "Done!"; } # # Copy opensslconf.h and dso_conf.h generated from OpenSSL Configuration # print "\n--> Duplicating opensslconf.h into Include/openssl ... "; system( "perl -pe 's/\\n/\\r\\n/' " . "< " . $OPENSSL_PATH . "/include/openssl/opensslconf.h " . "> " . $OPENSSL_PATH . "/../../Include/openssl/opensslconf_generated.h" ) == 0 || die "Cannot copy opensslconf.h!"; print "Done!"; print "\n--> Duplicating dso_conf.h into Include/crypto ... "; system( "perl -pe 's/\\n/\\r\\n/' " . "< " . $OPENSSL_PATH . "/include/crypto/dso_conf.h" . "> " . $OPENSSL_PATH . "/../../Include/crypto/dso_conf.h" ) == 0 || die "Cannot copy dso_conf.h!"; print "Done!"; # # Add conditional feature to opensslconf.h # my $conf_file = "../Include/openssl/opensslconf.h"; my @conf_raw = (); my @conditional_define = (); print "\n--> Updating conditional feature in $conf_file ... "; foreach my $pcd_name (keys(%conditional_feature)) { push @conditional_define, "#if !FixedPcdGetBool ($pcd_name)\r\n"; foreach (@{$conditional_feature{$pcd_name}}) { push @conditional_define, "# ifndef OPENSSL_NO_$_\r\n"; push @conditional_define, "# define OPENSSL_NO_$_\r\n"; push @conditional_define, "# endif\r\n"; } push @conditional_define, "#endif\r\n"; } open( FD, "<" . $conf_file ) || die $conf_file; foreach () { # Insert conditional define to the begin of opensslconf.h if ($_ =~ "Autogenerated conditional openssl feature list starts here") { push @conf_raw, $_, @conditional_define; $subbing = 1; next; } if ($_ =~ "Autogenerated conditional openssl feature list ends here") { push @conf_raw, $_; $subbing = 0; next; } push @conf_raw, $_ unless ($subbing); } close(FD) || die $conf_file; open( FD, ">" . $conf_file ) || die $conf_file; print( FD @conf_raw ) || die $conf_file; close(FD) || die $conf_file; print "Done!\n"; print "\nProcessing Files Done!\n"; exit(0);