1#!/bin/sh 2 3# compat.sh 4# 5# Copyright The Mbed TLS Contributors 6# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 7# 8# Purpose 9# 10# Test interoperbility with OpenSSL, GnuTLS as well as itself. 11# 12# Check each common ciphersuite, with each version, both ways (client/server), 13# with and without client authentication. 14 15set -u 16 17# Limit the size of each log to 10 GiB, in case of failures with this script 18# where it may output seemingly unlimited length error logs. 19ulimit -f 20971520 20 21ORIGINAL_PWD=$PWD 22if ! cd "$(dirname "$0")"; then 23 exit 125 24fi 25 26# initialise counters 27TESTS=0 28FAILED=0 29SKIPPED=0 30SRVMEM=0 31 32# default commands, can be overridden by the environment 33: ${M_SRV:=../programs/ssl/ssl_server2} 34: ${M_CLI:=../programs/ssl/ssl_client2} 35: ${OPENSSL:=openssl} 36: ${GNUTLS_CLI:=gnutls-cli} 37: ${GNUTLS_SERV:=gnutls-serv} 38 39# The OPENSSL variable used to be OPENSSL_CMD for historical reasons. 40# To help the migration, error out if the old variable is set, 41# but only if it has a different value than the new one. 42if [ "${OPENSSL_CMD+set}" = set ]; then 43 # the variable is set, we can now check its value 44 if [ "$OPENSSL_CMD" != "$OPENSSL" ]; then 45 echo "Please use OPENSSL instead of OPENSSL_CMD." >&2 46 exit 125 47 fi 48fi 49 50# do we have a recent enough GnuTLS? 51if ( which $GNUTLS_CLI && which $GNUTLS_SERV ) >/dev/null 2>&1; then 52 G_VER="$( $GNUTLS_CLI --version | head -n1 )" 53 if echo "$G_VER" | grep '@VERSION@' > /dev/null; then # git version 54 PEER_GNUTLS=" GnuTLS" 55 else 56 eval $( echo $G_VER | sed 's/.* \([0-9]*\)\.\([0-9]\)*\.\([0-9]*\)$/MAJOR="\1" MINOR="\2" PATCH="\3"/' ) 57 if [ $MAJOR -lt 3 -o \ 58 \( $MAJOR -eq 3 -a $MINOR -lt 2 \) -o \ 59 \( $MAJOR -eq 3 -a $MINOR -eq 2 -a $PATCH -lt 15 \) ] 60 then 61 PEER_GNUTLS="" 62 else 63 PEER_GNUTLS=" GnuTLS" 64 if [ $MINOR -lt 4 ]; then 65 GNUTLS_MINOR_LT_FOUR='x' 66 fi 67 fi 68 fi 69else 70 PEER_GNUTLS="" 71fi 72 73guess_config_name() { 74 if git diff --quiet ../include/mbedtls/mbedtls_config.h 2>/dev/null; then 75 echo "default" 76 else 77 echo "unknown" 78 fi 79} 80: ${MBEDTLS_TEST_OUTCOME_FILE=} 81: ${MBEDTLS_TEST_CONFIGURATION:="$(guess_config_name)"} 82: ${MBEDTLS_TEST_PLATFORM:="$(uname -s | tr -c \\n0-9A-Za-z _)-$(uname -m | tr -c \\n0-9A-Za-z _)"} 83 84# default values for options 85# /!\ keep this synchronised with: 86# - basic-build-test.sh 87# - all.sh (multiple components) 88MODES="tls12 dtls12" 89VERIFIES="NO YES" 90TYPES="ECDSA RSA PSK" 91FILTER="" 92# By default, exclude: 93# - NULL: excluded from our default config + requires OpenSSL legacy 94# - ARIA: requires OpenSSL >= 1.1.1 95# - ChachaPoly: requires OpenSSL >= 1.1.0 96EXCLUDE='NULL\|ARIA\|CHACHA20_POLY1305' 97VERBOSE="" 98MEMCHECK=0 99MIN_TESTS=1 100PRESERVE_LOGS=0 101PEERS="OpenSSL$PEER_GNUTLS mbedTLS" 102 103# hidden option: skip DTLS with OpenSSL 104# (travis CI has a version that doesn't work for us) 105: ${OSSL_NO_DTLS:=0} 106 107print_usage() { 108 echo "Usage: $0" 109 printf " -h|--help\tPrint this help.\n" 110 printf " -f|--filter\tOnly matching ciphersuites are tested (Default: '%s')\n" "$FILTER" 111 printf " -e|--exclude\tMatching ciphersuites are excluded (Default: '%s')\n" "$EXCLUDE" 112 printf " -m|--modes\tWhich modes to perform (Default: '%s')\n" "$MODES" 113 printf " -t|--types\tWhich key exchange type to perform (Default: '%s')\n" "$TYPES" 114 printf " -V|--verify\tWhich verification modes to perform (Default: '%s')\n" "$VERIFIES" 115 printf " -p|--peers\tWhich peers to use (Default: '%s')\n" "$PEERS" 116 printf " \tAlso available: GnuTLS (needs v3.2.15 or higher)\n" 117 printf " -M|--memcheck\tCheck memory leaks and errors.\n" 118 printf " -v|--verbose\tSet verbose output.\n" 119 printf " --list-test-cases\tList all potential test cases (No Execution)\n" 120 printf " --min \tMinimum number of non-skipped tests (default 1)\n" 121 printf " --outcome-file\tFile where test outcomes are written\n" 122 printf " \t(default: \$MBEDTLS_TEST_OUTCOME_FILE, none if empty)\n" 123 printf " --preserve-logs\tPreserve logs of successful tests as well\n" 124} 125 126# print_test_case <CLIENT> <SERVER> <STANDARD_CIPHER_SUITE> 127print_test_case() { 128 for i in $3; do 129 uniform_title $1 $2 $i 130 echo "compat;$TITLE" 131 done 132} 133 134# list_test_cases lists all potential test cases in compat.sh without execution 135list_test_cases() { 136 for TYPE in $TYPES; do 137 reset_ciphersuites 138 add_common_ciphersuites 139 add_openssl_ciphersuites 140 add_gnutls_ciphersuites 141 add_mbedtls_ciphersuites 142 143 # PSK cipher suites do not allow client certificate verification. 144 SUB_VERIFIES=$VERIFIES 145 if [ "$TYPE" = "PSK" ]; then 146 SUB_VERIFIES="NO" 147 fi 148 149 for VERIFY in $SUB_VERIFIES; do 150 VERIF=$(echo $VERIFY | tr '[:upper:]' '[:lower:]') 151 for MODE in $MODES; do 152 print_test_case m O "$O_CIPHERS" 153 print_test_case O m "$O_CIPHERS" 154 print_test_case m G "$G_CIPHERS" 155 print_test_case G m "$G_CIPHERS" 156 print_test_case m m "$M_CIPHERS" 157 done 158 done 159 done 160} 161 162get_options() { 163 while [ $# -gt 0 ]; do 164 case "$1" in 165 -f|--filter) 166 shift; FILTER=$1 167 ;; 168 -e|--exclude) 169 shift; EXCLUDE=$1 170 ;; 171 -m|--modes) 172 shift; MODES=$1 173 ;; 174 -t|--types) 175 shift; TYPES=$1 176 ;; 177 -V|--verify) 178 shift; VERIFIES=$1 179 ;; 180 -p|--peers) 181 shift; PEERS=$1 182 ;; 183 -v|--verbose) 184 VERBOSE=1 185 ;; 186 -M|--memcheck) 187 MEMCHECK=1 188 ;; 189 # Please check scripts/check_test_cases.py correspondingly 190 # if you have to modify option, --list-test-cases 191 --list-test-cases) 192 list_test_cases 193 exit $? 194 ;; 195 --min) 196 shift; MIN_TESTS=$1 197 ;; 198 --outcome-file) 199 shift; MBEDTLS_TEST_OUTCOME_FILE=$1 200 ;; 201 --preserve-logs) 202 PRESERVE_LOGS=1 203 ;; 204 -h|--help) 205 print_usage 206 exit 0 207 ;; 208 *) 209 echo "Unknown argument: '$1'" 210 print_usage 211 exit 1 212 ;; 213 esac 214 shift 215 done 216 217 # sanitize some options (modes checked later) 218 VERIFIES="$( echo $VERIFIES | tr [a-z] [A-Z] )" 219 TYPES="$( echo $TYPES | tr [a-z] [A-Z] )" 220} 221 222log() { 223 if [ "X" != "X$VERBOSE" ]; then 224 echo "" 225 echo "$@" 226 fi 227} 228 229# is_dtls <mode> 230is_dtls() 231{ 232 test "$1" = "dtls12" 233} 234 235# minor_ver <mode> 236minor_ver() 237{ 238 case "$1" in 239 tls12|dtls12) 240 echo 3 241 ;; 242 *) 243 echo "error: invalid mode: $MODE" >&2 244 # exiting is no good here, typically called in a subshell 245 echo -1 246 esac 247} 248 249filter() 250{ 251 LIST="$1" 252 NEW_LIST="" 253 254 EXCLMODE="$EXCLUDE" 255 256 for i in $LIST; 257 do 258 NEW_LIST="$NEW_LIST $( echo "$i" | grep "$FILTER" | grep -v "$EXCLMODE" )" 259 done 260 261 # normalize whitespace 262 echo "$NEW_LIST" | sed -e 's/[[:space:]][[:space:]]*/ /g' -e 's/^ //' -e 's/ $//' 263} 264 265filter_ciphersuites() 266{ 267 if [ "X" != "X$FILTER" -o "X" != "X$EXCLUDE" ]; 268 then 269 # Ciphersuite for Mbed TLS 270 M_CIPHERS=$( filter "$M_CIPHERS" ) 271 272 # Ciphersuite for OpenSSL 273 O_CIPHERS=$( filter "$O_CIPHERS" ) 274 275 # Ciphersuite for GnuTLS 276 G_CIPHERS=$( filter "$G_CIPHERS" ) 277 fi 278} 279 280reset_ciphersuites() 281{ 282 M_CIPHERS="" 283 O_CIPHERS="" 284 G_CIPHERS="" 285} 286 287# translate_ciphers {g|m|o} {STANDARD_CIPHER_SUITE_NAME...} 288# Set $ciphers to the cipher suite name translations for the specified 289# program (gnutls, mbedtls or openssl). $ciphers is a space-separated 290# list of entries of the form "STANDARD_NAME=PROGRAM_NAME". 291translate_ciphers() 292{ 293 ciphers=$(../framework/scripts/translate_ciphers.py "$@") 294 if [ $? -ne 0 ]; then 295 echo "translate_ciphers.py failed with exit code $1" >&2 296 echo "$2" >&2 297 exit 1 298 fi 299} 300 301# Ciphersuites that can be used with all peers. 302# Since we currently have three possible peers, each ciphersuite should appear 303# three times: in each peer's list (with the name that this peer uses). 304add_common_ciphersuites() 305{ 306 CIPHERS="" 307 case $TYPE in 308 309 "ECDSA") 310 CIPHERS="$CIPHERS \ 311 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA \ 312 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 \ 313 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 \ 314 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA \ 315 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 \ 316 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 \ 317 TLS_ECDHE_ECDSA_WITH_NULL_SHA \ 318 " 319 ;; 320 321 "RSA") 322 CIPHERS="$CIPHERS \ 323 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA \ 324 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 \ 325 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 \ 326 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA \ 327 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 \ 328 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 \ 329 TLS_ECDHE_RSA_WITH_NULL_SHA \ 330 " 331 ;; 332 333 "PSK") 334 CIPHERS="$CIPHERS \ 335 TLS_PSK_WITH_AES_128_CBC_SHA \ 336 TLS_PSK_WITH_AES_256_CBC_SHA \ 337 " 338 ;; 339 esac 340 341 O_CIPHERS="$O_CIPHERS $CIPHERS" 342 G_CIPHERS="$G_CIPHERS $CIPHERS" 343 M_CIPHERS="$M_CIPHERS $CIPHERS" 344} 345 346# Ciphersuites usable only with Mbed TLS and OpenSSL 347# A list of ciphersuites in the standard naming convention is appended 348# to the list of Mbed TLS ciphersuites $M_CIPHERS and 349# to the list of OpenSSL ciphersuites $O_CIPHERS respectively. 350# Based on client's naming convention, all ciphersuite names will be 351# translated into another naming format before sent to the client. 352# 353# ChachaPoly suites are here rather than in "common", as they were added in 354# GnuTLS in 3.5.0 and the CI only has 3.4.x so far. 355add_openssl_ciphersuites() 356{ 357 CIPHERS="" 358 case $TYPE in 359 360 "ECDSA") 361 CIPHERS="$CIPHERS \ 362 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA \ 363 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 \ 364 TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 \ 365 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA \ 366 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 \ 367 TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 \ 368 TLS_ECDH_ECDSA_WITH_NULL_SHA \ 369 TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 \ 370 TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 \ 371 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 \ 372 " 373 ;; 374 375 "RSA") 376 CIPHERS="$CIPHERS \ 377 TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 \ 378 TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 \ 379 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 \ 380 " 381 ;; 382 383 "PSK") 384 CIPHERS="$CIPHERS \ 385 TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 \ 386 TLS_PSK_WITH_ARIA_128_GCM_SHA256 \ 387 TLS_PSK_WITH_ARIA_256_GCM_SHA384 \ 388 TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 \ 389 " 390 ;; 391 esac 392 393 O_CIPHERS="$O_CIPHERS $CIPHERS" 394 M_CIPHERS="$M_CIPHERS $CIPHERS" 395} 396 397# Ciphersuites usable only with Mbed TLS and GnuTLS 398# A list of ciphersuites in the standard naming convention is appended 399# to the list of Mbed TLS ciphersuites $M_CIPHERS and 400# to the list of GnuTLS ciphersuites $G_CIPHERS respectively. 401# Based on client's naming convention, all ciphersuite names will be 402# translated into another naming format before sent to the client. 403add_gnutls_ciphersuites() 404{ 405 CIPHERS="" 406 case $TYPE in 407 408 "ECDSA") 409 CIPHERS="$CIPHERS \ 410 TLS_ECDHE_ECDSA_WITH_AES_128_CCM \ 411 TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 \ 412 TLS_ECDHE_ECDSA_WITH_AES_256_CCM \ 413 TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 \ 414 TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 \ 415 TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 \ 416 TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 \ 417 TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 \ 418 " 419 ;; 420 421 "RSA") 422 CIPHERS="$CIPHERS \ 423 TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 \ 424 TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 \ 425 TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 \ 426 TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 \ 427 " 428 ;; 429 430 "PSK") 431 CIPHERS="$CIPHERS \ 432 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA \ 433 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 \ 434 TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA \ 435 TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 \ 436 TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 \ 437 TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 \ 438 TLS_ECDHE_PSK_WITH_NULL_SHA256 \ 439 TLS_ECDHE_PSK_WITH_NULL_SHA384 \ 440 TLS_PSK_WITH_AES_128_CBC_SHA256 \ 441 TLS_PSK_WITH_AES_128_CCM \ 442 TLS_PSK_WITH_AES_128_CCM_8 \ 443 TLS_PSK_WITH_AES_128_GCM_SHA256 \ 444 TLS_PSK_WITH_AES_256_CBC_SHA384 \ 445 TLS_PSK_WITH_AES_256_CCM \ 446 TLS_PSK_WITH_AES_256_CCM_8 \ 447 TLS_PSK_WITH_AES_256_GCM_SHA384 \ 448 TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 \ 449 TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 \ 450 TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 \ 451 TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 \ 452 TLS_PSK_WITH_NULL_SHA256 \ 453 TLS_PSK_WITH_NULL_SHA384 \ 454 " 455 ;; 456 esac 457 458 G_CIPHERS="$G_CIPHERS $CIPHERS" 459 M_CIPHERS="$M_CIPHERS $CIPHERS" 460} 461 462# Ciphersuites usable only with Mbed TLS (not currently supported by another 463# peer usable in this script). This provides only very rudimentaty testing, as 464# this is not interop testing, but it's better than nothing. 465add_mbedtls_ciphersuites() 466{ 467 case $TYPE in 468 469 "ECDSA") 470 M_CIPHERS="$M_CIPHERS \ 471 TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 \ 472 TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 \ 473 TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 \ 474 TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 \ 475 TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 \ 476 TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 \ 477 TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 \ 478 TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 \ 479 TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 \ 480 TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 \ 481 " 482 ;; 483 484 "RSA") 485 M_CIPHERS="$M_CIPHERS \ 486 TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 \ 487 TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 \ 488 " 489 ;; 490 491 "PSK") 492 # *PSK_NULL_SHA suites supported by GnuTLS 3.3.5 but not 3.2.15 493 M_CIPHERS="$M_CIPHERS \ 494 TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 \ 495 TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 \ 496 TLS_ECDHE_PSK_WITH_NULL_SHA \ 497 TLS_PSK_WITH_ARIA_128_CBC_SHA256 \ 498 TLS_PSK_WITH_ARIA_256_CBC_SHA384 \ 499 TLS_PSK_WITH_NULL_SHA \ 500 " 501 ;; 502 esac 503} 504 505# o_check_ciphersuite STANDARD_CIPHER_SUITE 506o_check_ciphersuite() 507{ 508 # skip DTLS when lack of support was declared 509 if test "$OSSL_NO_DTLS" -gt 0 && is_dtls "$MODE"; then 510 SKIP_NEXT_="YES" 511 fi 512 513 # skip DTLS 1.2 is support was not detected 514 if [ "$O_SUPPORT_DTLS12" = "NO" -a "$MODE" = "dtls12" ]; then 515 SKIP_NEXT="YES" 516 fi 517 518 # skip static ECDH when OpenSSL doesn't support it 519 if [ "${O_SUPPORT_STATIC_ECDH}" = "NO" ]; then 520 case "$1" in 521 *ECDH_*) SKIP_NEXT="YES" 522 esac 523 fi 524} 525 526setup_arguments() 527{ 528 DATA_FILES_PATH="../framework/data_files" 529 530 O_MODE="" 531 G_MODE="" 532 case "$MODE" in 533 "tls12") 534 O_MODE="tls1_2" 535 G_PRIO_MODE="+VERS-TLS1.2" 536 ;; 537 "dtls12") 538 O_MODE="dtls1_2" 539 G_PRIO_MODE="+VERS-DTLS1.2" 540 G_MODE="-u" 541 ;; 542 *) 543 echo "error: invalid mode: $MODE" >&2 544 exit 1; 545 esac 546 547 # GnuTLS < 3.4 will choke if we try to allow CCM-8 548 if [ -z "${GNUTLS_MINOR_LT_FOUR-}" ]; then 549 G_PRIO_CCM="+AES-256-CCM-8:+AES-128-CCM-8:" 550 else 551 G_PRIO_CCM="" 552 fi 553 554 M_SERVER_ARGS="server_port=$PORT server_addr=0.0.0.0 force_version=$MODE" 555 O_SERVER_ARGS="-accept $PORT -cipher ALL,COMPLEMENTOFALL -$O_MODE" 556 G_SERVER_ARGS="-p $PORT --http $G_MODE" 557 G_SERVER_PRIO="NORMAL:${G_PRIO_CCM}+NULL:+MD5:+PSK:+ECDHE-PSK:+SHA256:+SHA384:-VERS-TLS-ALL:$G_PRIO_MODE" 558 559 # The default prime for `openssl s_server` depends on the version: 560 # * OpenSSL <= 1.0.2a: 512-bit 561 # * OpenSSL 1.0.2b to 1.1.1b: 1024-bit 562 # * OpenSSL >= 1.1.1c: 2048-bit 563 # Mbed TLS wants >=1024, so force that for older versions. Don't force 564 # it for newer versions, which reject a 1024-bit prime. Indifferently 565 # force it or not for intermediate versions. 566 case $($OPENSSL version) in 567 "OpenSSL 1.0"*) 568 O_SERVER_ARGS="$O_SERVER_ARGS -dhparam $DATA_FILES_PATH/dhparams.pem" 569 ;; 570 esac 571 572 # with OpenSSL 1.0.1h, -www, -WWW and -HTTP break DTLS handshakes 573 if is_dtls "$MODE"; then 574 O_SERVER_ARGS="$O_SERVER_ARGS" 575 else 576 O_SERVER_ARGS="$O_SERVER_ARGS -www" 577 fi 578 579 M_CLIENT_ARGS="server_port=$PORT server_addr=127.0.0.1 force_version=$MODE" 580 O_CLIENT_ARGS="-connect localhost:$PORT -$O_MODE" 581 G_CLIENT_ARGS="-p $PORT --debug 3 $G_MODE" 582 583 # Newer versions of OpenSSL have a syntax to enable all "ciphers", even 584 # low-security ones. This covers not just cipher suites but also protocol 585 # versions. It is necessary, for example, to use (D)TLS 1.0/1.1 on 586 # OpenSSL 1.1.1f from Ubuntu 20.04. The syntax was only introduced in 587 # OpenSSL 1.1.0 (21e0c1d23afff48601eb93135defddae51f7e2e3) and I can't find 588 # a way to discover it from -help, so check the openssl version. 589 case $($OPENSSL version) in 590 "OpenSSL 0"*|"OpenSSL 1.0"*) :;; 591 *) 592 O_CLIENT_ARGS="$O_CLIENT_ARGS -cipher ALL@SECLEVEL=0" 593 O_SERVER_ARGS="$O_SERVER_ARGS -cipher ALL@SECLEVEL=0" 594 ;; 595 esac 596 597 case $($OPENSSL ciphers ALL) in 598 *ECDH-ECDSA*|*ECDH-RSA*) O_SUPPORT_STATIC_ECDH="YES";; 599 *) O_SUPPORT_STATIC_ECDH="NO";; 600 esac 601 602 # OpenSSL <1.0.2 doesn't support DTLS 1.2. Check if OpenSSL 603 # supports -dtls1_2 from the s_server help. (The s_client 604 # help isn't accurate as of 1.0.2g: it supports DTLS 1.2 605 # but doesn't list it. But the s_server help seems to be 606 # accurate.) 607 O_SUPPORT_DTLS12="NO" 608 if $OPENSSL s_server -help 2>&1 | grep -q "^ *-dtls1_2 "; then 609 O_SUPPORT_DTLS12="YES" 610 fi 611 612 if [ "X$VERIFY" = "XYES" ]; 613 then 614 M_SERVER_ARGS="$M_SERVER_ARGS ca_file=$DATA_FILES_PATH/test-ca_cat12.crt auth_mode=required" 615 O_SERVER_ARGS="$O_SERVER_ARGS -CAfile $DATA_FILES_PATH/test-ca_cat12.crt -Verify 10" 616 G_SERVER_ARGS="$G_SERVER_ARGS --x509cafile $DATA_FILES_PATH/test-ca_cat12.crt --require-client-cert" 617 618 M_CLIENT_ARGS="$M_CLIENT_ARGS ca_file=$DATA_FILES_PATH/test-ca_cat12.crt auth_mode=required" 619 O_CLIENT_ARGS="$O_CLIENT_ARGS -CAfile $DATA_FILES_PATH/test-ca_cat12.crt -verify 10" 620 G_CLIENT_ARGS="$G_CLIENT_ARGS --x509cafile $DATA_FILES_PATH/test-ca_cat12.crt" 621 else 622 # don't request a client cert at all 623 M_SERVER_ARGS="$M_SERVER_ARGS ca_file=none auth_mode=none" 624 G_SERVER_ARGS="$G_SERVER_ARGS --disable-client-cert" 625 626 M_CLIENT_ARGS="$M_CLIENT_ARGS ca_file=none auth_mode=none" 627 O_CLIENT_ARGS="$O_CLIENT_ARGS" 628 G_CLIENT_ARGS="$G_CLIENT_ARGS --insecure" 629 fi 630 631 case $TYPE in 632 "ECDSA") 633 M_SERVER_ARGS="$M_SERVER_ARGS crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key" 634 O_SERVER_ARGS="$O_SERVER_ARGS -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" 635 G_SERVER_ARGS="$G_SERVER_ARGS --x509certfile $DATA_FILES_PATH/server5.crt --x509keyfile $DATA_FILES_PATH/server5.key" 636 637 if [ "X$VERIFY" = "XYES" ]; then 638 M_CLIENT_ARGS="$M_CLIENT_ARGS crt_file=$DATA_FILES_PATH/server6.crt key_file=$DATA_FILES_PATH/server6.key" 639 O_CLIENT_ARGS="$O_CLIENT_ARGS -cert $DATA_FILES_PATH/server6.crt -key $DATA_FILES_PATH/server6.key" 640 G_CLIENT_ARGS="$G_CLIENT_ARGS --x509certfile $DATA_FILES_PATH/server6.crt --x509keyfile $DATA_FILES_PATH/server6.key" 641 else 642 M_CLIENT_ARGS="$M_CLIENT_ARGS crt_file=none key_file=none" 643 fi 644 ;; 645 646 "RSA") 647 M_SERVER_ARGS="$M_SERVER_ARGS crt_file=$DATA_FILES_PATH/server2-sha256.crt key_file=$DATA_FILES_PATH/server2.key" 648 O_SERVER_ARGS="$O_SERVER_ARGS -cert $DATA_FILES_PATH/server2-sha256.crt -key $DATA_FILES_PATH/server2.key" 649 G_SERVER_ARGS="$G_SERVER_ARGS --x509certfile $DATA_FILES_PATH/server2-sha256.crt --x509keyfile $DATA_FILES_PATH/server2.key" 650 651 if [ "X$VERIFY" = "XYES" ]; then 652 M_CLIENT_ARGS="$M_CLIENT_ARGS crt_file=$DATA_FILES_PATH/cert_sha256.crt key_file=$DATA_FILES_PATH/server1.key" 653 O_CLIENT_ARGS="$O_CLIENT_ARGS -cert $DATA_FILES_PATH/cert_sha256.crt -key $DATA_FILES_PATH/server1.key" 654 G_CLIENT_ARGS="$G_CLIENT_ARGS --x509certfile $DATA_FILES_PATH/cert_sha256.crt --x509keyfile $DATA_FILES_PATH/server1.key" 655 else 656 M_CLIENT_ARGS="$M_CLIENT_ARGS crt_file=none key_file=none" 657 fi 658 ;; 659 660 "PSK") 661 M_SERVER_ARGS="$M_SERVER_ARGS psk=6162636465666768696a6b6c6d6e6f70 ca_file=none" 662 O_SERVER_ARGS="$O_SERVER_ARGS -psk 6162636465666768696a6b6c6d6e6f70 -nocert" 663 G_SERVER_ARGS="$G_SERVER_ARGS --pskpasswd $DATA_FILES_PATH/passwd.psk" 664 665 M_CLIENT_ARGS="$M_CLIENT_ARGS psk=6162636465666768696a6b6c6d6e6f70 crt_file=none key_file=none" 666 O_CLIENT_ARGS="$O_CLIENT_ARGS -psk 6162636465666768696a6b6c6d6e6f70" 667 G_CLIENT_ARGS="$G_CLIENT_ARGS --pskusername Client_identity --pskkey=6162636465666768696a6b6c6d6e6f70" 668 ;; 669 esac 670} 671 672# is_mbedtls <cmd_line> 673is_mbedtls() { 674 case $1 in 675 *ssl_client2*) true;; 676 *ssl_server2*) true;; 677 *) false;; 678 esac 679} 680 681# has_mem_err <log_file_name> 682has_mem_err() { 683 if ( grep -F 'All heap blocks were freed -- no leaks are possible' "$1" && 684 grep -F 'ERROR SUMMARY: 0 errors from 0 contexts' "$1" ) > /dev/null 685 then 686 return 1 # false: does not have errors 687 else 688 return 0 # true: has errors 689 fi 690} 691 692# Wait for process $2 to be listening on port $1 693if type lsof >/dev/null 2>/dev/null; then 694 wait_server_start() { 695 START_TIME=$(date +%s) 696 if is_dtls "$MODE"; then 697 proto=UDP 698 else 699 proto=TCP 700 fi 701 while ! lsof -a -n -b -i "$proto:$1" -p "$2" >/dev/null 2>/dev/null; do 702 if [ $(( $(date +%s) - $START_TIME )) -gt $DOG_DELAY ]; then 703 echo "SERVERSTART TIMEOUT" 704 echo "SERVERSTART TIMEOUT" >> $SRV_OUT 705 break 706 fi 707 # Linux and *BSD support decimal arguments to sleep. On other 708 # OSes this may be a tight loop. 709 sleep 0.1 2>/dev/null || true 710 done 711 } 712else 713 echo "Warning: lsof not available, wait_server_start = sleep" 714 wait_server_start() { 715 sleep 2 716 } 717fi 718 719 720# start_server <name> 721# also saves name and command 722start_server() { 723 case $1 in 724 [Oo]pen*) 725 SERVER_CMD="$OPENSSL s_server $O_SERVER_ARGS" 726 ;; 727 [Gg]nu*) 728 SERVER_CMD="$GNUTLS_SERV $G_SERVER_ARGS --priority $G_SERVER_PRIO" 729 ;; 730 mbed*) 731 SERVER_CMD="$M_SRV $M_SERVER_ARGS" 732 if [ "$MEMCHECK" -gt 0 ]; then 733 SERVER_CMD="valgrind --leak-check=full $SERVER_CMD" 734 fi 735 ;; 736 *) 737 echo "error: invalid server name: $1" >&2 738 exit 1 739 ;; 740 esac 741 SERVER_NAME=$1 742 743 log "$SERVER_CMD" 744 echo "$SERVER_CMD" > $SRV_OUT 745 # for servers without -www or equivalent 746 while :; do echo bla; sleep 1; done | $SERVER_CMD >> $SRV_OUT 2>&1 & 747 SRV_PID=$! 748 749 wait_server_start "$PORT" "$SRV_PID" 750} 751 752# terminate the running server 753stop_server() { 754 # For Ubuntu 22.04, `Terminated` message is outputed by wait command. 755 # To remove it from stdout, redirect stdout/stderr to SRV_OUT 756 kill $SRV_PID >/dev/null 2>&1 757 wait $SRV_PID >> $SRV_OUT 2>&1 758 759 if [ "$MEMCHECK" -gt 0 ]; then 760 if is_mbedtls "$SERVER_CMD" && has_mem_err $SRV_OUT; then 761 echo " ! Server had memory errors" 762 SRVMEM=$(( $SRVMEM + 1 )) 763 return 764 fi 765 fi 766 767 rm -f $SRV_OUT 768} 769 770# kill the running server (used when killed by signal) 771cleanup() { 772 rm -f $SRV_OUT $CLI_OUT 773 kill $SRV_PID >/dev/null 2>&1 774 kill $WATCHDOG_PID >/dev/null 2>&1 775 exit 1 776} 777 778# wait for client to terminate and set EXIT 779# must be called right after starting the client 780wait_client_done() { 781 CLI_PID=$! 782 783 ( sleep "$DOG_DELAY"; echo "TIMEOUT" >> $CLI_OUT; kill $CLI_PID ) & 784 WATCHDOG_PID=$! 785 786 # For Ubuntu 22.04, `Terminated` message is outputed by wait command. 787 # To remove it from stdout, redirect stdout/stderr to CLI_OUT 788 wait $CLI_PID >> $CLI_OUT 2>&1 789 EXIT=$? 790 791 kill $WATCHDOG_PID >/dev/null 2>&1 792 wait $WATCHDOG_PID >> $CLI_OUT 2>&1 793 794 echo "EXIT: $EXIT" >> $CLI_OUT 795} 796 797# uniform_title <CLIENT> <SERVER> <STANDARD_CIPHER_SUITE> 798# $TITLE is considered as test case description for both --list-test-cases and 799# MBEDTLS_TEST_OUTCOME_FILE. This function aims to control the format of 800# each test case description. 801uniform_title() { 802 TITLE="$1->$2 $MODE,$VERIF $3" 803} 804 805# record_outcome <outcome> [<failure-reason>] 806record_outcome() { 807 echo "$1" 808 if [ -n "$MBEDTLS_TEST_OUTCOME_FILE" ]; then 809 # The test outcome file has the format (in single line): 810 # platform;configuration; 811 # test suite name;test case description; 812 # PASS/FAIL/SKIP;[failure cause] 813 printf '%s;%s;%s;%s;%s;%s\n' \ 814 "$MBEDTLS_TEST_PLATFORM" "$MBEDTLS_TEST_CONFIGURATION" \ 815 "compat" "$TITLE" \ 816 "$1" "${2-}" \ 817 >> "$MBEDTLS_TEST_OUTCOME_FILE" 818 fi 819} 820 821save_logs() { 822 cp $SRV_OUT c-srv-${TESTS}.log 823 cp $CLI_OUT c-cli-${TESTS}.log 824} 825 826# display additional information if test case fails 827report_fail() { 828 FAIL_PROMPT="outputs saved to c-srv-${TESTS}.log, c-cli-${TESTS}.log" 829 record_outcome "FAIL" "$FAIL_PROMPT" 830 save_logs 831 echo " ! $FAIL_PROMPT" 832 833 if [ "${LOG_FAILURE_ON_STDOUT:-0}" != 0 ]; then 834 echo " ! server output:" 835 cat c-srv-${TESTS}.log 836 echo " ! ===================================================" 837 echo " ! client output:" 838 cat c-cli-${TESTS}.log 839 fi 840} 841 842# run_client PROGRAM_NAME STANDARD_CIPHER_SUITE PROGRAM_CIPHER_SUITE 843run_client() { 844 # announce what we're going to do 845 TESTS=$(( $TESTS + 1 )) 846 uniform_title "${1%"${1#?}"}" "${SERVER_NAME%"${SERVER_NAME#?}"}" $2 847 DOTS72="........................................................................" 848 printf "%s %.*s " "$TITLE" "$((71 - ${#TITLE}))" "$DOTS72" 849 850 # should we skip? 851 if [ "X$SKIP_NEXT" = "XYES" ]; then 852 SKIP_NEXT="NO" 853 record_outcome "SKIP" 854 SKIPPED=$(( $SKIPPED + 1 )) 855 return 856 fi 857 858 # run the command and interpret result 859 case $1 in 860 [Oo]pen*) 861 CLIENT_CMD="$OPENSSL s_client $O_CLIENT_ARGS -cipher $3" 862 log "$CLIENT_CMD" 863 echo "$CLIENT_CMD" > $CLI_OUT 864 printf 'GET HTTP/1.0\r\n\r\n' | $CLIENT_CMD >> $CLI_OUT 2>&1 & 865 wait_client_done 866 867 if [ $EXIT -eq 0 ]; then 868 RESULT=0 869 else 870 # If it is NULL cipher ... 871 if grep 'Cipher is (NONE)' $CLI_OUT >/dev/null; then 872 RESULT=1 873 else 874 RESULT=2 875 fi 876 fi 877 ;; 878 879 [Gg]nu*) 880 CLIENT_CMD="$GNUTLS_CLI $G_CLIENT_ARGS --priority $G_PRIO_MODE:$3 localhost" 881 log "$CLIENT_CMD" 882 echo "$CLIENT_CMD" > $CLI_OUT 883 printf 'GET HTTP/1.0\r\n\r\n' | $CLIENT_CMD >> $CLI_OUT 2>&1 & 884 wait_client_done 885 886 if [ $EXIT -eq 0 ]; then 887 RESULT=0 888 else 889 RESULT=2 890 # interpret early failure, with a handshake_failure alert 891 # before the server hello, as "no ciphersuite in common" 892 if grep -F 'Received alert [40]: Handshake failed' $CLI_OUT; then 893 if grep -i 'SERVER HELLO .* was received' $CLI_OUT; then : 894 else 895 RESULT=1 896 fi 897 fi >/dev/null 898 fi 899 ;; 900 901 mbed*) 902 CLIENT_CMD="$M_CLI $M_CLIENT_ARGS force_ciphersuite=$3" 903 if [ "$MEMCHECK" -gt 0 ]; then 904 CLIENT_CMD="valgrind --leak-check=full $CLIENT_CMD" 905 fi 906 log "$CLIENT_CMD" 907 echo "$CLIENT_CMD" > $CLI_OUT 908 $CLIENT_CMD >> $CLI_OUT 2>&1 & 909 wait_client_done 910 911 case $EXIT in 912 # Success 913 "0") RESULT=0 ;; 914 915 # Ciphersuite not supported 916 "2") RESULT=1 ;; 917 918 # Error 919 *) RESULT=2 ;; 920 esac 921 922 if [ "$MEMCHECK" -gt 0 ]; then 923 if is_mbedtls "$CLIENT_CMD" && has_mem_err $CLI_OUT; then 924 RESULT=2 925 fi 926 fi 927 928 ;; 929 930 *) 931 echo "error: invalid client name: $1" >&2 932 exit 1 933 ;; 934 esac 935 936 echo "EXIT: $EXIT" >> $CLI_OUT 937 938 # report and count result 939 case $RESULT in 940 "0") 941 record_outcome "PASS" 942 if [ "$PRESERVE_LOGS" -gt 0 ]; then 943 save_logs 944 fi 945 ;; 946 "1") 947 record_outcome "SKIP" 948 SKIPPED=$(( $SKIPPED + 1 )) 949 ;; 950 "2") 951 report_fail 952 FAILED=$(( $FAILED + 1 )) 953 ;; 954 esac 955 956 rm -f $CLI_OUT 957} 958 959# 960# MAIN 961# 962 963get_options "$@" 964 965# Make the outcome file path relative to the original directory, not 966# to .../tests 967case "$MBEDTLS_TEST_OUTCOME_FILE" in 968 [!/]*) 969 MBEDTLS_TEST_OUTCOME_FILE="$ORIGINAL_PWD/$MBEDTLS_TEST_OUTCOME_FILE" 970 ;; 971esac 972 973# sanity checks, avoid an avalanche of errors 974if [ ! -x "$M_SRV" ]; then 975 echo "Command '$M_SRV' is not an executable file" >&2 976 exit 1 977fi 978if [ ! -x "$M_CLI" ]; then 979 echo "Command '$M_CLI' is not an executable file" >&2 980 exit 1 981fi 982 983if echo "$PEERS" | grep -i openssl > /dev/null; then 984 if which "$OPENSSL" >/dev/null 2>&1; then :; else 985 echo "Command '$OPENSSL' not found" >&2 986 exit 1 987 fi 988fi 989 990if echo "$PEERS" | grep -i gnutls > /dev/null; then 991 for CMD in "$GNUTLS_CLI" "$GNUTLS_SERV"; do 992 if which "$CMD" >/dev/null 2>&1; then :; else 993 echo "Command '$CMD' not found" >&2 994 exit 1 995 fi 996 done 997fi 998 999for PEER in $PEERS; do 1000 case "$PEER" in 1001 mbed*|[Oo]pen*|[Gg]nu*) 1002 ;; 1003 *) 1004 echo "Unknown peers: $PEER" >&2 1005 exit 1 1006 esac 1007done 1008 1009# Pick a "unique" port in the range 10000-19999. 1010PORT="0000$$" 1011PORT="1$(echo $PORT | tail -c 5)" 1012 1013# Also pick a unique name for intermediate files 1014SRV_OUT="srv_out.$$" 1015CLI_OUT="cli_out.$$" 1016 1017# client timeout delay: be more patient with valgrind 1018if [ "$MEMCHECK" -gt 0 ]; then 1019 DOG_DELAY=30 1020else 1021 DOG_DELAY=10 1022fi 1023 1024SKIP_NEXT="NO" 1025 1026trap cleanup INT TERM HUP 1027 1028for MODE in $MODES; do 1029 for TYPE in $TYPES; do 1030 1031 # PSK cipher suites do not allow client certificate verification. 1032 # This means PSK test cases with VERIFY=YES should be replaced by 1033 # VERIFY=NO or be ignored. SUB_VERIFIES variable is used to constrain 1034 # verification option for PSK test cases. 1035 SUB_VERIFIES=$VERIFIES 1036 if [ "$TYPE" = "PSK" ]; then 1037 SUB_VERIFIES="NO" 1038 fi 1039 1040 for VERIFY in $SUB_VERIFIES; do 1041 VERIF=$(echo $VERIFY | tr '[:upper:]' '[:lower:]') 1042 for PEER in $PEERS; do 1043 1044 setup_arguments 1045 1046 case "$PEER" in 1047 1048 [Oo]pen*) 1049 1050 reset_ciphersuites 1051 add_common_ciphersuites 1052 add_openssl_ciphersuites 1053 filter_ciphersuites 1054 1055 if [ "X" != "X$M_CIPHERS" ]; then 1056 start_server "OpenSSL" 1057 translate_ciphers m $M_CIPHERS 1058 for i in $ciphers; do 1059 o_check_ciphersuite "${i%%=*}" 1060 run_client mbedTLS ${i%%=*} ${i#*=} 1061 done 1062 stop_server 1063 fi 1064 1065 if [ "X" != "X$O_CIPHERS" ]; then 1066 start_server "mbedTLS" 1067 translate_ciphers o $O_CIPHERS 1068 for i in $ciphers; do 1069 o_check_ciphersuite "${i%%=*}" 1070 run_client OpenSSL ${i%%=*} ${i#*=} 1071 done 1072 stop_server 1073 fi 1074 1075 ;; 1076 1077 [Gg]nu*) 1078 1079 reset_ciphersuites 1080 add_common_ciphersuites 1081 add_gnutls_ciphersuites 1082 filter_ciphersuites 1083 1084 if [ "X" != "X$M_CIPHERS" ]; then 1085 start_server "GnuTLS" 1086 translate_ciphers m $M_CIPHERS 1087 for i in $ciphers; do 1088 run_client mbedTLS ${i%%=*} ${i#*=} 1089 done 1090 stop_server 1091 fi 1092 1093 if [ "X" != "X$G_CIPHERS" ]; then 1094 start_server "mbedTLS" 1095 translate_ciphers g $G_CIPHERS 1096 for i in $ciphers; do 1097 run_client GnuTLS ${i%%=*} ${i#*=} 1098 done 1099 stop_server 1100 fi 1101 1102 ;; 1103 1104 mbed*) 1105 1106 reset_ciphersuites 1107 add_common_ciphersuites 1108 add_openssl_ciphersuites 1109 add_gnutls_ciphersuites 1110 add_mbedtls_ciphersuites 1111 filter_ciphersuites 1112 1113 if [ "X" != "X$M_CIPHERS" ]; then 1114 start_server "mbedTLS" 1115 translate_ciphers m $M_CIPHERS 1116 for i in $ciphers; do 1117 run_client mbedTLS ${i%%=*} ${i#*=} 1118 done 1119 stop_server 1120 fi 1121 1122 ;; 1123 1124 *) 1125 echo "Unknown peer: $PEER" >&2 1126 exit 1 1127 ;; 1128 1129 esac 1130 1131 done 1132 done 1133 done 1134done 1135 1136echo "------------------------------------------------------------------------" 1137 1138if [ $FAILED -ne 0 -o $SRVMEM -ne 0 ]; then 1139 printf "FAILED" 1140else 1141 printf "PASSED" 1142fi 1143 1144if [ "$MEMCHECK" -gt 0 ]; then 1145 MEMREPORT=", $SRVMEM server memory errors" 1146else 1147 MEMREPORT="" 1148fi 1149 1150PASSED=$(( $TESTS - $FAILED )) 1151echo " ($PASSED / $TESTS tests ($SKIPPED skipped$MEMREPORT))" 1152 1153if [ $((TESTS - SKIPPED)) -lt $MIN_TESTS ]; then 1154 cat <<EOF 1155Error: Expected to run at least $MIN_TESTS, but only ran $((TESTS - SKIPPED)). 1156Maybe a bad filter ('$FILTER' excluding '$EXCLUDE') or a bad configuration? 1157EOF 1158 if [ $FAILED -eq 0 ]; then 1159 FAILED=1 1160 fi 1161fi 1162 1163FAILED=$(( $FAILED + $SRVMEM )) 1164if [ $FAILED -gt 255 ]; then 1165 # Clamp at 255 as caller gets exit code & 0xFF 1166 # (so 256 would be 0, or success, etc) 1167 FAILED=255 1168fi 1169exit $FAILED 1170