Home | History | Annotate | Download | only in openssl
      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