1 #!/bin/bash 2 # 3 # Copyright (C) 2009 The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 # 17 18 # 19 # This script imports new versions of OpenSSL (http://openssl.org/source) into the 20 # Android source tree. To run, (1) fetch the appropriate tarball from the OpenSSL repository, 21 # (2) check the gpg/pgp signature, and then (3) run: 22 # ./import_openssl.sh import openssl-*.tar.gz 23 # 24 # IMPORTANT: See README.android for additional details. 25 26 # turn on exit on error as well as a warning when it happens 27 set -e 28 trap "echo WARNING: Exiting on non-zero subprocess exit code" ERR; 29 30 # Ensure consistent sorting order / tool output. 31 export LANG=C 32 export LC_ALL=C 33 34 function die() { 35 declare -r message=$1 36 37 echo $message 38 exit 1 39 } 40 41 function usage() { 42 declare -r message=$1 43 44 if [ ! "$message" = "" ]; then 45 echo $message 46 fi 47 echo "Usage:" 48 echo " ./import_openssl.sh import </path/to/openssl-*.tar.gz>" 49 echo " ./import_openssl.sh regenerate <patch/*.patch>" 50 echo " ./import_openssl.sh generate <patch/*.patch> </path/to/openssl-*.tar.gz>" 51 exit 1 52 } 53 54 function main() { 55 if [ ! -d patches ]; then 56 die "OpenSSL patch directory patches/ not found" 57 fi 58 59 if [ ! -f openssl.version ]; then 60 die "openssl.version not found" 61 fi 62 63 source openssl.version 64 if [ "$OPENSSL_VERSION" == "" ]; then 65 die "Invalid openssl.version; see README.android for more information" 66 fi 67 68 OPENSSL_DIR=openssl-$OPENSSL_VERSION 69 OPENSSL_DIR_ORIG=$OPENSSL_DIR.orig 70 71 if [ ! -f openssl.config ]; then 72 die "openssl.config not found" 73 fi 74 75 source openssl.config 76 if [ "$CONFIGURE_ARGS" == "" -o "$UNNEEDED_SOURCES" == "" -o "$NEEDED_SOURCES" == "" ]; then 77 die "Invalid openssl.config; see README.android for more information" 78 fi 79 80 declare -r command=$1 81 shift || usage "No command specified. Try import, regenerate, or generate." 82 if [ "$command" = "import" ]; then 83 declare -r tar=$1 84 shift || usage "No tar file specified." 85 import $tar 86 elif [ "$command" = "regenerate" ]; then 87 declare -r patch=$1 88 shift || usage "No patch file specified." 89 [ -d $OPENSSL_DIR ] || usage "$OPENSSL_DIR not found, did you mean to use generate?" 90 [ -d $OPENSSL_DIR_ORIG_ORIG ] || usage "$OPENSSL_DIR_ORIG not found, did you mean to use generate?" 91 regenerate $patch 92 elif [ "$command" = "generate" ]; then 93 declare -r patch=$1 94 shift || usage "No patch file specified." 95 declare -r tar=$1 96 shift || usage "No tar file specified." 97 generate $patch $tar 98 else 99 usage "Unknown command specified $command. Try import, regenerate, or generate." 100 fi 101 } 102 103 # Compute the name of an assembly source file generated by one of the 104 # gen_asm_xxxx() functions below. The logic is the following: 105 # - if "$2" is not empty, output it directly 106 # - otherwise, change the file extension of $1 from .pl to .S and output 107 # it. 108 # Usage: default_asm_file "$1" "$2" 109 # or default_asm_file "$@" 110 # 111 # $1: generator path (perl script) 112 # $2: optional output file name. 113 function default_asm_file () { 114 if [ "$2" ]; then 115 echo "$2" 116 else 117 echo "${1%%.pl}.S" 118 fi 119 } 120 121 # Generate an ARM assembly file. 122 # $1: generator (perl script) 123 # $2: [optional] output file name 124 function gen_asm_arm () { 125 local OUT 126 OUT=$(default_asm_file "$@") 127 perl "$1" > "$OUT" 128 } 129 130 function gen_asm_mips () { 131 local OUT 132 OUT=$(default_asm_file "$@") 133 # The perl scripts expect to run the target compiler as $CC to determine 134 # the endianess of the target. Setting CC to true is a hack that forces the scripts 135 # to generate little endian output 136 CC=true perl "$1" o32 > "$OUT" 137 } 138 139 function gen_asm_x86 () { 140 local OUT 141 OUT=$(default_asm_file "$@") 142 perl "$1" elf -fPIC > "$OUT" 143 } 144 145 function gen_asm_x86_64 () { 146 local OUT 147 OUT=$(default_asm_file "$@") 148 perl "$1" elf "$OUT" > "$OUT" 149 } 150 151 152 # Filter all items in a list that match a given pattern. 153 # $1: space-separated list 154 # $2: egrep pattern. 155 # Out: items in $1 that match $2 156 function filter_by_egrep() { 157 declare -r pattern=$1 158 shift 159 echo "$@" | tr ' ' '\n' | grep -e "$pattern" | tr '\n' ' ' 160 } 161 162 # Sort and remove duplicates in a space-separated list 163 # $1: space-separated list 164 # Out: new space-separated list 165 function uniq_sort () { 166 echo "$@" | tr ' ' '\n' | sort -u | tr '\n' ' ' 167 } 168 169 function print_autogenerated_header() { 170 echo "# Auto-generated - DO NOT EDIT!" 171 echo "# To regenerate, edit openssl.config, then run:" 172 echo "# ./import_openssl.sh import /path/to/openssl-$OPENSSL_VERSION.tar.gz" 173 echo "#" 174 } 175 176 function generate_build_config_mk() { 177 ./Configure $CONFIGURE_ARGS 178 rm -f apps/CA.pl.bak crypto/opensslconf.h.bak 179 180 declare -r tmpfile=$(mktemp) 181 (grep -e -D Makefile | grep -v CONFIGURE_ARGS= | grep -v OPTIONS= | grep -v -e -DOPENSSL_NO_DEPRECATED) > $tmpfile 182 183 declare -r cflags=$(filter_by_egrep "^-D" $(grep -e "^CFLAG=" $tmpfile)) 184 declare -r depflags=$(filter_by_egrep "^-D" $(grep -e "^DEPFLAG=" $tmpfile)) 185 rm -f $tmpfile 186 187 echo "Generating $(basename $1)" 188 ( 189 print_autogenerated_header 190 191 echo "openssl_cflags := \\" 192 for cflag in $cflags $depflags; do 193 echo " $cflag \\" 194 done 195 echo "" 196 ) > $1 197 } 198 199 # Return the value of a computed variable name. 200 # E.g.: 201 # FOO=foo 202 # BAR=bar 203 # echo $(var_value FOO_$BAR) -> prints the value of ${FOO_bar} 204 # $1: Variable name 205 # Out: variable value 206 var_value() { 207 # Note: don't use 'echo' here, because it's sensitive to values 208 # that begin with an underscore (e.g. "-n") 209 eval printf \"%s\\n\" \$$1 210 } 211 212 # Same as var_value, but returns sorted output without duplicates. 213 # $1: Variable name 214 # Out: variable value (if space-separated list, sorted with no duplicates) 215 var_sorted_value() { 216 uniq_sort $(var_value $1) 217 } 218 219 # Print the definition of a given variable in a GNU Make build file. 220 # $1: Variable name (e.g. common_src_files) 221 # $2+: Variable value (e.g. list of sources) 222 print_vardef_in_mk() { 223 declare -r varname=$1 224 shift 225 if [ -z "$1" ]; then 226 echo "$varname :=" 227 else 228 echo "$varname := \\" 229 for src; do 230 echo " $src \\" 231 done 232 fi 233 echo "" 234 } 235 236 # Same as print_vardef_in_mk, but print a CFLAGS definition from 237 # a list of compiler defines. 238 # $1: Variable name (e.g. common_c_flags) 239 # $2: List of defines (e.g. OPENSSL_NO_CAMELLIA ...) 240 print_defines_in_mk() { 241 declare -r varname=$1 242 shift 243 if [ -z "$1" ]; then 244 echo "$varname :=" 245 else 246 echo "$varname := \\" 247 for def; do 248 echo " -D$def \\" 249 done 250 fi 251 echo "" 252 } 253 254 # Generate a configuration file like Crypto-config.mk 255 # This uses variable definitions from openssl.config to build a config 256 # file that can compute the list of target- and host-specific sources / 257 # compiler flags for a given component. 258 # 259 # $1: Target file name. (e.g. Crypto-config.mk) 260 # $2: Variable prefix. (e.g. CRYPTO) 261 function generate_config_mk() { 262 declare -r output="$1" 263 declare -r prefix="$2" 264 declare -r all_archs="arm x86 x86_64 mips" 265 266 echo "Generating $(basename $output)" 267 ( 268 print_autogenerated_header 269 echo \ 270 "# Before including this file, the local Android.mk must define the following 271 # variables: 272 # 273 # local_c_flags 274 # local_c_includes 275 # local_additional_dependencies 276 # 277 # This script will define the following variables: 278 # 279 # target_c_flags 280 # target_c_includes 281 # target_src_files 282 # 283 # host_c_flags 284 # host_c_includes 285 # host_src_files 286 # 287 288 # Ensure these are empty. 289 unknown_arch_c_flags := 290 unknown_arch_src_files := 291 unknown_arch_exclude_files := 292 293 " 294 common_defines=$(var_sorted_value OPENSSL_${prefix}_DEFINES) 295 print_defines_in_mk common_c_flags $common_defines 296 297 common_sources=$(var_sorted_value OPENSSL_${prefix}_SOURCES) 298 print_vardef_in_mk common_src_files $common_sources 299 300 common_includes=$(var_sorted_value OPENSSL_${prefix}_INCLUDES) 301 print_vardef_in_mk common_c_includes $common_includes 302 303 for arch in $all_archs; do 304 arch_defines=$(var_sorted_value OPENSSL_${prefix}_DEFINES_${arch}) 305 print_defines_in_mk ${arch}_c_flags $arch_defines 306 307 arch_sources=$(var_sorted_value OPENSSL_${prefix}_SOURCES_${arch}) 308 print_vardef_in_mk ${arch}_src_files $arch_sources 309 310 arch_exclude_sources=$(var_sorted_value OPENSSL_${prefix}_SOURCES_EXCLUDES_${arch}) 311 print_vardef_in_mk ${arch}_exclude_files $arch_exclude_sources 312 313 done 314 315 echo "\ 316 target_arch := \$(TARGET_ARCH) 317 ifeq (\$(target_arch)-\$(TARGET_HAS_BIGENDIAN),mips-true) 318 target_arch := unknown_arch 319 endif 320 321 target_c_flags := \$(common_c_flags) \$(\$(target_arch)_c_flags) \$(local_c_flags) 322 target_c_includes := \$(addprefix external/openssl/,\$(common_c_includes)) \$(local_c_includes) 323 target_src_files := \$(common_src_files) \$(\$(target_arch)_src_files) 324 target_src_files := \$(filter-out \$(\$(target_arch)_exclude_files), \$(target_src_files)) 325 326 ifeq (\$(HOST_OS)-\$(HOST_ARCH),linux-x86) 327 host_arch := x86 328 else 329 host_arch := unknown_arch 330 endif 331 332 host_c_flags := \$(common_c_flags) \$(\$(host_arch)_c_flags) \$(local_c_flags) 333 host_c_includes := \$(addprefix external/openssl/,\$(common_c_includes)) \$(local_c_includes) 334 host_src_files := \$(common_src_files) \$(\$(host_arch)_src_files) 335 host_src_files := \$(filter-out \$(\$(host_arch)_exclude_files), \$(host_src_files)) 336 337 local_additional_dependencies += \$(LOCAL_PATH)/$(basename $output) 338 " 339 340 ) > "$output" 341 } 342 343 function import() { 344 declare -r OPENSSL_SOURCE=$1 345 346 untar $OPENSSL_SOURCE readonly 347 applypatches $OPENSSL_DIR 348 349 cd $OPENSSL_DIR 350 351 generate_build_config_mk ../build-config.mk 352 353 cp -f LICENSE ../NOTICE 354 touch ../MODULE_LICENSE_BSD_LIKE 355 356 # Avoid checking in symlinks 357 for i in `find include/openssl -type l`; do 358 target=`readlink $i` 359 rm -f $i 360 if [ -f include/openssl/$target ]; then 361 cp include/openssl/$target $i 362 fi 363 done 364 365 # Generate arm asm 366 gen_asm_arm crypto/aes/asm/aes-armv4.pl 367 gen_asm_arm crypto/bn/asm/armv4-gf2m.pl 368 gen_asm_arm crypto/bn/asm/armv4-mont.pl 369 gen_asm_arm crypto/modes/asm/ghash-armv4.pl 370 gen_asm_arm crypto/sha/asm/sha1-armv4-large.pl 371 gen_asm_arm crypto/sha/asm/sha256-armv4.pl 372 gen_asm_arm crypto/sha/asm/sha512-armv4.pl 373 374 # Generate mips asm 375 gen_asm_mips crypto/aes/asm/aes-mips.pl 376 gen_asm_mips crypto/bn/asm/mips.pl crypto/bn/asm/bn-mips.S 377 gen_asm_mips crypto/bn/asm/mips-mont.pl 378 gen_asm_mips crypto/sha/asm/sha1-mips.pl 379 gen_asm_mips crypto/sha/asm/sha512-mips.pl crypto/sha/asm/sha256-mips.S 380 381 # Generate x86 asm 382 gen_asm_x86 crypto/x86cpuid.pl 383 gen_asm_x86 crypto/aes/asm/aes-586.pl 384 gen_asm_x86 crypto/aes/asm/vpaes-x86.pl 385 gen_asm_x86 crypto/aes/asm/aesni-x86.pl 386 gen_asm_x86 crypto/bn/asm/bn-586.pl 387 gen_asm_x86 crypto/bn/asm/co-586.pl 388 gen_asm_x86 crypto/bn/asm/x86-mont.pl 389 gen_asm_x86 crypto/bn/asm/x86-gf2m.pl 390 gen_asm_x86 crypto/modes/asm/ghash-x86.pl 391 gen_asm_x86 crypto/sha/asm/sha1-586.pl 392 gen_asm_x86 crypto/sha/asm/sha256-586.pl 393 gen_asm_x86 crypto/sha/asm/sha512-586.pl 394 gen_asm_x86 crypto/md5/asm/md5-586.pl 395 gen_asm_x86 crypto/des/asm/des-586.pl 396 gen_asm_x86 crypto/des/asm/crypt586.pl 397 gen_asm_x86 crypto/bf/asm/bf-586.pl 398 399 # Generate x86_64 asm 400 gen_asm_x86_64 crypto/x86_64cpuid.pl 401 gen_asm_x86_64 crypto/sha/asm/sha1-x86_64.pl 402 gen_asm_x86_64 crypto/sha/asm/sha512-x86_64.pl crypto/sha/asm/sha256-x86_64.S 403 gen_asm_x86_64 crypto/sha/asm/sha512-x86_64.pl 404 gen_asm_x86_64 crypto/modes/asm/ghash-x86_64.pl 405 gen_asm_x86_64 crypto/aes/asm/aesni-x86_64.pl 406 gen_asm_x86_64 crypto/aes/asm/vpaes-x86_64.pl 407 gen_asm_x86_64 crypto/aes/asm/bsaes-x86_64.pl 408 gen_asm_x86_64 crypto/aes/asm/aes-x86_64.pl 409 gen_asm_x86_64 crypto/aes/asm/aesni-sha1-x86_64.pl 410 gen_asm_x86_64 crypto/md5/asm/md5-x86_64.pl 411 gen_asm_x86_64 crypto/bn/asm/modexp512-x86_64.pl 412 gen_asm_x86_64 crypto/bn/asm/x86_64-mont.pl 413 gen_asm_x86_64 crypto/bn/asm/x86_64-gf2m.pl 414 gen_asm_x86_64 crypto/bn/asm/x86_64-mont5.pl 415 gen_asm_x86_64 crypto/rc4/asm/rc4-x86_64.pl 416 gen_asm_x86_64 crypto/rc4/asm/rc4-md5-x86_64.pl 417 418 # Setup android.testssl directory 419 mkdir android.testssl 420 cat test/testssl | \ 421 sed 's#../util/shlib_wrap.sh ./ssltest#adb shell /system/bin/ssltest#' | \ 422 sed 's#../util/shlib_wrap.sh ../apps/openssl#adb shell /system/bin/openssl#' | \ 423 sed 's#adb shell /system/bin/openssl no-dh#[ `adb shell /system/bin/openssl no-dh` = no-dh ]#' | \ 424 sed 's#adb shell /system/bin/openssl no-rsa#[ `adb shell /system/bin/openssl no-rsa` = no-dh ]#' | \ 425 sed 's#../apps/server2.pem#/sdcard/android.testssl/server2.pem#' | \ 426 cat > \ 427 android.testssl/testssl 428 chmod +x android.testssl/testssl 429 cat test/Uss.cnf | sed 's#./.rnd#/sdcard/android.testssl/.rnd#' >> android.testssl/Uss.cnf 430 cat test/CAss.cnf | sed 's#./.rnd#/sdcard/android.testssl/.rnd#' >> android.testssl/CAss.cnf 431 cp apps/server2.pem android.testssl/ 432 cp ../patches/testssl.sh android.testssl/ 433 434 cd .. 435 436 generate_config_mk Crypto-config.mk CRYPTO 437 generate_config_mk Ssl-config.mk SSL 438 generate_config_mk Apps-config.mk APPS 439 440 # Prune unnecessary sources 441 prune 442 443 NEEDED_SOURCES="$NEEDED_SOURCES android.testssl" 444 for i in $NEEDED_SOURCES; do 445 echo "Updating $i" 446 rm -r $i 447 mv $OPENSSL_DIR/$i . 448 done 449 450 cleantar 451 } 452 453 function regenerate() { 454 declare -r patch=$1 455 456 generatepatch $patch 457 } 458 459 function generate() { 460 declare -r patch=$1 461 declare -r OPENSSL_SOURCE=$2 462 463 untar $OPENSSL_SOURCE 464 applypatches $OPENSSL_DIR_ORIG $patch 465 prune 466 467 for i in $NEEDED_SOURCES; do 468 echo "Restoring $i" 469 rm -r $OPENSSL_DIR/$i 470 cp -rf $i $OPENSSL_DIR/$i 471 done 472 473 generatepatch $patch 474 cleantar 475 } 476 477 # Find all files in a sub-directory that are encoded in ISO-8859 478 # $1: Directory. 479 # Out: list of files in $1 that are encoded as ISO-8859. 480 function find_iso8859_files() { 481 find $1 -type f -print0 | xargs -0 file | fgrep "ISO-8859" | cut -d: -f1 482 } 483 484 # Convert all ISO-8859 files in a given subdirectory to UTF-8 485 # $1: Directory name 486 function convert_iso8859_to_utf8() { 487 declare -r iso_files=$(find_iso8859_files "$1") 488 for iso_file in $iso_files; do 489 iconv --from-code iso-8859-1 --to-code utf-8 $iso_file > $iso_file.tmp 490 rm -f $iso_file 491 mv $iso_file.tmp $iso_file 492 done 493 } 494 495 function untar() { 496 declare -r OPENSSL_SOURCE=$1 497 declare -r readonly=$2 498 499 # Remove old source 500 cleantar 501 502 # Process new source 503 tar -zxf $OPENSSL_SOURCE 504 convert_iso8859_to_utf8 $OPENSSL_DIR 505 cp -rfP $OPENSSL_DIR $OPENSSL_DIR_ORIG 506 if [ ! -z $readonly ]; then 507 find $OPENSSL_DIR_ORIG -type f -print0 | xargs -0 chmod a-w 508 fi 509 } 510 511 function prune() { 512 echo "Removing $UNNEEDED_SOURCES" 513 (cd $OPENSSL_DIR_ORIG && rm -rf $UNNEEDED_SOURCES) 514 (cd $OPENSSL_DIR && rm -r $UNNEEDED_SOURCES) 515 } 516 517 function cleantar() { 518 rm -rf $OPENSSL_DIR_ORIG 519 rm -rf $OPENSSL_DIR 520 } 521 522 function applypatches () { 523 declare -r dir=$1 524 declare -r skip_patch=$2 525 526 cd $dir 527 528 # Apply appropriate patches 529 for i in $OPENSSL_PATCHES; do 530 if [ ! "$skip_patch" = "patches/$i" ]; then 531 echo "Applying patch $i" 532 patch -p1 --merge < ../patches/$i || die "Could not apply patches/$i. Fix source and run: $0 regenerate patches/$i" 533 else 534 echo "Skiping patch $i" 535 fi 536 537 done 538 539 # Cleanup patch output 540 find . \( -type f -o -type l \) -name "*.orig" -print0 | xargs -0 rm -f 541 542 cd .. 543 } 544 545 function generatepatch() { 546 declare -r patch=$1 547 548 # Cleanup stray files before generating patch 549 find $BOUNCYCASTLE_DIR -type f -name "*.orig" -print0 | xargs -0 rm -f 550 find $BOUNCYCASTLE_DIR -type f -name "*~" -print0 | xargs -0 rm -f 551 552 declare -r variable_name=OPENSSL_PATCHES_`basename $patch .patch | sed s/-/_/`_SOURCES 553 # http://tldp.org/LDP/abs/html/ivr.html 554 eval declare -r sources=\$$variable_name 555 rm -f $patch 556 touch $patch 557 for i in $sources; do 558 LC_ALL=C TZ=UTC0 diff -aup $OPENSSL_DIR_ORIG/$i $OPENSSL_DIR/$i >> $patch && die "ERROR: No diff for patch $path in file $i" 559 done 560 echo "Generated patch $patch" 561 echo "NOTE To make sure there are not unwanted changes from conflicting patches, be sure to review the generated patch." 562 } 563 564 main $@ 565