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