# Commands covered:  tls::ciphers
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#

# All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

# The build dir is added as the first element of $PATH
set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]]

package require tls

# One of these should == 1, depending on what type of ssl library
# tls was compiled against. (RSA BSAFE SSL-C or OpenSSL).
#
set ::tcltest::testConstraints(rsabsafe) 0
set ::tcltest::testConstraints(openssl) [string match "OpenSSL*" [tls::version]]
set ::tcltest::testConstraints(libressl) [string match "LibreSSL*" [tls::version]]

set ::EXPECTEDCIPHERS(rsabsafe) {
    EDH-DSS-RC4-SHA
    EDH-RSA-DES-CBC3-SHA
    EDH-DSS-DES-CBC3-SHA
    DES-CBC3-SHA
    RC4-SHA
    RC4-MD5
    EDH-RSA-DES-CBC-SHA
    EDH-DSS-DES-CBC-SHA
    DES-CBC-SHA
    EXP-EDH-DSS-DES-56-SHA
    EXP-EDH-DSS-RC4-56-SHA
    EXP-DES-56-SHA
    EXP-RC4-56-SHA
    EXP-EDH-RSA-DES-CBC-SHA
    EXP-EDH-DSS-DES-CBC-SHA
    EXP-DES-CBC-SHA
    EXP-RC2-CBC-MD5
    EXP-RC4-MD5
}

set ::EXPECTEDCIPHERS(openssl) {
    AES128-SHA
    AES256-SHA
    DES-CBC-SHA
    DES-CBC3-SHA
    DHE-DSS-AES128-SHA
    DHE-DSS-AES256-SHA
    DHE-DSS-RC4-SHA
    DHE-RSA-AES128-SHA
    DHE-RSA-AES256-SHA
    EDH-DSS-DES-CBC-SHA
    EDH-DSS-DES-CBC3-SHA
    EDH-RSA-DES-CBC-SHA
    EDH-RSA-DES-CBC3-SHA
    EXP-DES-CBC-SHA
    EXP-EDH-DSS-DES-CBC-SHA
    EXP-EDH-RSA-DES-CBC-SHA
    EXP-RC2-CBC-MD5
    EXP-RC4-MD5
    EXP1024-DES-CBC-SHA
    EXP1024-DHE-DSS-DES-CBC-SHA
    EXP1024-DHE-DSS-RC4-SHA
    EXP1024-RC2-CBC-MD5
    EXP1024-RC4-MD5
    EXP1024-RC4-SHA
    IDEA-CBC-SHA
    RC4-MD5
    RC4-SHA
}

set ::EXPECTEDCIPHERS(openssl0.9.8) {
    DHE-RSA-AES256-SHA
    DHE-DSS-AES256-SHA
    AES256-SHA
    EDH-RSA-DES-CBC3-SHA
    EDH-DSS-DES-CBC3-SHA
    DES-CBC3-SHA
    DHE-RSA-AES128-SHA
    DHE-DSS-AES128-SHA
    AES128-SHA
    IDEA-CBC-SHA
    RC4-SHA
    RC4-MD5
    EDH-RSA-DES-CBC-SHA
    EDH-DSS-DES-CBC-SHA
    DES-CBC-SHA
    EXP-EDH-RSA-DES-CBC-SHA
    EXP-EDH-DSS-DES-CBC-SHA
    EXP-DES-CBC-SHA
    EXP-RC2-CBC-MD5
    EXP-RC4-MD5
}

set ::EXPECTEDCIPHERS(libressl) {
    AES128-GCM-SHA256
    AES128-SHA
    AES128-SHA256
    AES256-GCM-SHA384
    AES256-SHA
    AES256-SHA256
    CAMELLIA128-SHA
    CAMELLIA128-SHA256
    CAMELLIA256-SHA
    CAMELLIA256-SHA256
    DES-CBC-SHA
    DES-CBC3-SHA
    DHE-DSS-AES128-GCM-SHA256
    DHE-DSS-AES128-SHA
    DHE-DSS-AES128-SHA256
    DHE-DSS-AES256-GCM-SHA384
    DHE-DSS-AES256-SHA
    DHE-DSS-AES256-SHA256
    DHE-DSS-CAMELLIA128-SHA
    DHE-DSS-CAMELLIA128-SHA256
    DHE-DSS-CAMELLIA256-SHA
    DHE-DSS-CAMELLIA256-SHA256
    DHE-RSA-AES128-GCM-SHA256
    DHE-RSA-AES128-SHA
    DHE-RSA-AES128-SHA256
    DHE-RSA-AES256-GCM-SHA384
    DHE-RSA-AES256-SHA
    DHE-RSA-AES256-SHA256
    DHE-RSA-CAMELLIA128-SHA
    DHE-RSA-CAMELLIA128-SHA256
    DHE-RSA-CAMELLIA256-SHA
    DHE-RSA-CAMELLIA256-SHA256
    DHE-RSA-CHACHA20-POLY1305
    ECDH-ECDSA-AES128-GCM-SHA256
    ECDH-ECDSA-AES128-SHA
    ECDH-ECDSA-AES128-SHA256
    ECDH-ECDSA-AES256-GCM-SHA384
    ECDH-ECDSA-AES256-SHA
    ECDH-ECDSA-AES256-SHA384
    ECDH-ECDSA-DES-CBC3-SHA
    ECDH-ECDSA-RC4-SHA
    ECDH-RSA-AES128-GCM-SHA256
    ECDH-RSA-AES128-SHA
    ECDH-RSA-AES128-SHA256
    ECDH-RSA-AES256-GCM-SHA384
    ECDH-RSA-AES256-SHA
    ECDH-RSA-AES256-SHA384
    ECDH-RSA-DES-CBC3-SHA
    ECDH-RSA-RC4-SHA
    ECDHE-ECDSA-AES128-GCM-SHA256
    ECDHE-ECDSA-AES128-SHA
    ECDHE-ECDSA-AES128-SHA256
    ECDHE-ECDSA-AES256-GCM-SHA384
    ECDHE-ECDSA-AES256-SHA
    ECDHE-ECDSA-AES256-SHA384
    ECDHE-ECDSA-CHACHA20-POLY1305
    ECDHE-ECDSA-DES-CBC3-SHA
    ECDHE-ECDSA-RC4-SHA
    ECDHE-RSA-AES128-GCM-SHA256
    ECDHE-RSA-AES128-SHA
    ECDHE-RSA-AES128-SHA256
    ECDHE-RSA-AES256-GCM-SHA384
    ECDHE-RSA-AES256-SHA
    ECDHE-RSA-AES256-SHA384
    ECDHE-RSA-CHACHA20-POLY1305
    ECDHE-RSA-DES-CBC3-SHA
    ECDHE-RSA-RC4-SHA
    EDH-DSS-DES-CBC-SHA
    EDH-DSS-DES-CBC3-SHA
    EDH-RSA-DES-CBC-SHA
    EDH-RSA-DES-CBC3-SHA
    GOST2001-GOST89-GOST89
    GOST2012256-GOST89-GOST89
    IDEA-CBC-SHA
    RC4-MD5
    RC4-SHA
}

set version ""
if {[string match "OpenSSL*" [tls::version]]} {
   regexp {OpenSSL ([\d\.]+)} [tls::version] -> version
}
if {![info exists ::EXPECTEDCIPHERS(openssl$version)]} {
    set version ""
}

proc listcompare {wants haves} {
    array set want {}
    array set have {}
    foreach item $wants { set want($item) 1 }
    foreach item $haves { set have($item) 1 }
    foreach item [lsort -dictionary [array names have]] {
	if {[info exists want($item)]} {
	    unset want($item) have($item)
	}
    }
    if {[array size want] || [array size have]} {
	return [list MISSING [array names want] UNEXPECTED [array names have]]
    }
}

test ciphers-1.1 {Tls::ciphers for ssl3} {rsabsafe} {
    # This will fail if you compiled against OpenSSL.
    # Change the constraint setting above.
    listcompare $::EXPECTEDCIPHERS(rsabsafe) [tls::ciphers ssl3]
} {}

test ciphers-1.2 {Tls::ciphers for tls1} {rsabsafe} {
    # This will fail if you compiled against OpenSSL.
    # Change the constraint setting above.
    listcompare $::EXPECTEDCIPHERS(rsabsafe) [tls::ciphers tls1]
} {}

test ciphers-1.3 {Tls::ciphers for ssl3} {openssl} {
    # This will fail if you compiled against RSA bsafe or with a
    # different set of defines than the default.
    # Change the constraint setting above.
    listcompare $::EXPECTEDCIPHERS(openssl$version) [tls::ciphers ssl3]
} {}

# This version of the test is correct for OpenSSL only.
# An equivalent test for the RSA BSAFE SSL-C is earlier in this file.

test ciphers-1.4 {Tls::ciphers for tls1} {openssl} {
    # This will fail if you compiled against RSA bsafe or with a
    # different set of defines than the default.
    # Change the constraint setting in all.tcl
    listcompare $::EXPECTEDCIPHERS(openssl$version) [tls::ciphers tls1]
} {}

# This version of the test is correct for LibreSSL 2.2.6 only.

test ciphers-1.5 {Tls::ciphers for ssl3} {libressl} {
    # See notes in ciphers-1.4
    listcompare $::EXPECTEDCIPHERS(libressl) [tls::ciphers ssl3]
} {}

test ciphers-1.6 {Tls::ciphers for tls1} {libressl} {
    # See notes in ciphers-1.4
    listcompare $::EXPECTEDCIPHERS(libressl) [tls::ciphers tls1]
} {}

# cleanup
::tcltest::cleanupTests
return
