Tls12Checker::checkCiphers()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 11
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
#!/usr/bin/env php
2
<?php
3
4
class Tls12Checker
5
{
6
    const API_URI = 'api.commercetools.com';
7
8
    const URIS = [
9
        'auth.commercetools.com',
10
        'api.commercetools.com',
11
        'auth.commercetools.co',
12
        'api.commercetools.co',
13
    ];
14
15
    public function allowedCiphers()
16
    {
17
        return [
18
            'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA',
19
            'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',
20
            'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA',
21
            'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384',
22
            'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256',
23
            'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA',
24
            'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256',
25
            'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA',
26
            'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384',
27
            'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256',
28
        ];
29
    }
30
31
    /**
32
     * @return array
33
     * @throws \Exception
34
     */
35
    private function getSupportedCiphers()
36
    {
37
        $ch = curl_init();
38
        curl_setopt($ch, CURLOPT_URL, "https://www.howsmyssl.com/a/check");
39
        curl_setopt($ch, CURLOPT_SSLVERSION, 6);
40
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
41
        $response = curl_exec($ch);
42
        curl_close($ch);
43
        $tlsInfo = json_decode($response, true);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

43
        $tlsInfo = json_decode(/** @scrutinizer ignore-type */ $response, true);
Loading history...
44
45
        if ($response === false) {
46
            throw new \Exception('Connection not connect using TLS 1.2', 1);
47
        }
48
49
        return isset($tlsInfo['given_cipher_suites']) ? $tlsInfo['given_cipher_suites'] : [];
50
    }
51
52
    /**
53
     * @throws \Exception
54
     */
55
    private function checkCiphers()
56
    {
57
        $supportedCiphers = $this->getSupportedCiphers();
58
        $allowedCiphers = $this->allowedCiphers();
59
60
        $diff = array_diff($allowedCiphers, $supportedCiphers);
61
62
        if (count($diff) < count($allowedCiphers)) {
63
            return;
64
        };
65
        throw new \Exception('None of the allowed cipher suites are supported by curl: ' . implode(', ', $allowedCiphers), 1);
66
    }
67
68
    /**
69
     * @param string $apiUri
70
     * @param string $cipher
71
     * @throws Exception
72
     */
73
    private function checkApiConnection($apiUri = self::API_URI, $cipher = null)
74
    {
75
        $ch = curl_init();
76
        curl_setopt($ch, CURLOPT_URL, 'https://' . $apiUri);
77
        curl_setopt($ch, CURLOPT_SSLVERSION, 6);
78
        if (!is_null($cipher)) {
79
            curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $cipher);
80
        }
81
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
82
        $response = curl_exec($ch);
83
        curl_close($ch);
84
85
        if ($response == false) {
86
            throw new \Exception('Could not connect not connect to API using TLS 1.2' . (is_null($cipher) ? '' : ' with cipher ' . $cipher), 1);
87
        }
88
    }
89
90
    private function checkCurlVersion()
91
    {
92
        $curlVersion = curl_version();
93
        $supportsTLS12 = true;
94
        if (version_compare(curl_version()['version'], '7.34.0', '<')) {
95
            $supportsTLS12 = false;
96
        }
97
        echo 'Curl version: ' . ($supportsTLS12 ? "\033[32m" : "\033[31m") . curl_version()['version'] . "\033[0m" . ($supportsTLS12 ? '' : '(TLS 1.2 not supported)') . PHP_EOL;
98
99
        if (isset($curlVersion['ssl_version'])) {
100
            echo 'Curl SSL Library: ' . curl_version()['ssl_version'] . PHP_EOL;
101
        }
102
    }
103
104
    /**
105
     * @return int
106
     */
107
    public function check()
108
    {
109
        $this->checkCurlVersion();
110
111
        echo "Checking TLS 1.2 connection ... ";
112
        try {
113
            $this->checkCiphers();
114
            foreach (self::URIS as $uri) {
115
                $this->checkApiConnection($uri);
116
            }
117
        } catch (\Exception $exception) {
118
            echo "\033[31mFailed\033[0m" . PHP_EOL;
119
            echo $exception->getMessage() . PHP_EOL;
120
            return (int)$exception->getCode();
121
        }
122
123
        echo "\033[32mOK\033[0m" . PHP_EOL;
124
125
        return 0;
126
    }
127
128
//    private function availableCiphers()
129
//    {
130
//        $localCiphers = explode(' ', exec('openssl ciphers \'ALL:eNULL\' | tr \':\' \' \''));
131
//        $allowedCiphers = [];
132
//        foreach ($localCiphers as $localCipher) {
133
//            exec('echo -n | openssl s_client -connect ' . self::API_URI . ':443 -cipher ' . $localCipher . ' -tls1_2 2>&1', $dummy, $status);
134
//            if ($status === 0) {
135
//                $allowedCiphers[] = $localCipher;
136
//            }
137
//        }
138
//
139
//        return $allowedCiphers;
140
//    }
141
//
142
//    private function checkAvailableCiphers()
143
//    {
144
//        $availableCiphers = $this->availableCiphers();
145
//        foreach ($availableCiphers as $cipher) {
146
//            echo 'Testing ' . $cipher . '...';
147
//            try {
148
//                $this->checkApiConnection(self::API_URI, $cipher);
149
//                echo "\033[32mOK\033[0m" . PHP_EOL;
150
//            } catch (\Exception $exception) {
151
//                echo "\033[31mFailed\033[0m" . PHP_EOL;
152
//            }
153
//        }
154
//    }
155
}
156
157
$checker = new Tls12Checker();
158
exit($checker->check());
159