OpenCoverage

qsslcertificate.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/network/ssl/qsslcertificate.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2016 The Qt Company Ltd.-
4** Contact: https://www.qt.io/licensing/-
5**-
6** This file is part of the QtNetwork module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL$-
9** Commercial License Usage-
10** Licensees holding valid commercial Qt licenses may use this file in-
11** accordance with the commercial license agreement provided with the-
12** Software or, alternatively, in accordance with the terms contained in-
13** a written agreement between you and The Qt Company. For licensing terms-
14** and conditions see https://www.qt.io/terms-conditions. For further-
15** information use the contact form at https://www.qt.io/contact-us.-
16**-
17** GNU Lesser General Public License Usage-
18** Alternatively, this file may be used under the terms of the GNU Lesser-
19** General Public License version 3 as published by the Free Software-
20** Foundation and appearing in the file LICENSE.LGPL3 included in the-
21** packaging of this file. Please review the following information to-
22** ensure the GNU Lesser General Public License version 3 requirements-
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
24**-
25** GNU General Public License Usage-
26** Alternatively, this file may be used under the terms of the GNU-
27** General Public License version 2.0 or (at your option) the GNU General-
28** Public license version 3 or any later version approved by the KDE Free-
29** Qt Foundation. The licenses are as published by the Free Software-
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
31** included in the packaging of this file. Please review the following-
32** information to ensure the GNU General Public License requirements will-
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
34** https://www.gnu.org/licenses/gpl-3.0.html.-
35**-
36** $QT_END_LICENSE$-
37**-
38****************************************************************************/-
39-
40-
41/*!-
42 \class QSslCertificate-
43 \brief The QSslCertificate class provides a convenient API for an X509 certificate.-
44 \since 4.3-
45-
46 \reentrant-
47 \ingroup network-
48 \ingroup ssl-
49 \ingroup shared-
50 \inmodule QtNetwork-
51-
52 QSslCertificate stores an X509 certificate, and is commonly used-
53 to verify the identity and store information about the local host,-
54 a remotely connected peer, or a trusted third party Certificate-
55 Authority.-
56-
57 There are many ways to construct a QSslCertificate. The most-
58 common way is to call QSslSocket::peerCertificate(), which returns-
59 a QSslCertificate object, or QSslSocket::peerCertificateChain(),-
60 which returns a list of them. You can also load certificates from-
61 a DER (binary) or PEM (Base64) encoded bundle, typically stored as-
62 one or more local files, or in a Qt Resource.-
63-
64 You can call isNull() to check if your certificate is null. By default,-
65 QSslCertificate constructs a null certificate. A null certificate is-
66 invalid, but an invalid certificate is not necessarily null. If you want-
67 to reset all contents in a certificate, call clear().-
68-
69 After loading a certificate, you can find information about the-
70 certificate, its subject, and its issuer, by calling one of the-
71 many accessor functions, including version(), serialNumber(),-
72 issuerInfo() and subjectInfo(). You can call effectiveDate() and-
73 expiryDate() to check when the certificate starts being-
74 effective and when it expires.-
75 The publicKey() function returns the certificate-
76 subject's public key as a QSslKey. You can call issuerInfo() or-
77 subjectInfo() to get detailed information about the certificate-
78 issuer and its subject.-
79-
80 Internally, QSslCertificate is stored as an X509 structure. You-
81 can access this handle by calling handle(), but the results are-
82 likely to not be portable.-
83-
84 \sa QSslSocket, QSslKey, QSslCipher, QSslError-
85*/-
86-
87/*!-
88 \enum QSslCertificate::SubjectInfo-
89-
90 Describes keys that you can pass to QSslCertificate::issuerInfo() or-
91 QSslCertificate::subjectInfo() to get information about the certificate-
92 issuer or subject.-
93-
94 \value Organization "O" The name of the organization.-
95-
96 \value CommonName "CN" The common name; most often this is used to store-
97 the host name.-
98-
99 \value LocalityName "L" The locality.-
100-
101 \value OrganizationalUnitName "OU" The organizational unit name.-
102-
103 \value CountryName "C" The country.-
104-
105 \value StateOrProvinceName "ST" The state or province.-
106-
107 \value DistinguishedNameQualifier The distinguished name qualifier-
108-
109 \value SerialNumber The certificate's serial number-
110-
111 \value EmailAddress The email address associated with the certificate-
112*/-
113-
114#include <QtCore/qglobal.h>-
115#ifndef QT_NO_OPENSSL-
116#include "qsslsocket_openssl_symbols_p.h"-
117#endif-
118#ifdef Q_OS_WINRT-
119#include "qsslsocket_winrt_p.h"-
120#endif-
121#ifdef QT_SECURETRANSPORT-
122#include "qsslsocket_mac_p.h"-
123#endif-
124-
125#include "qssl_p.h"-
126#include "qsslcertificate.h"-
127#include "qsslcertificate_p.h"-
128#include "qsslkey_p.h"-
129-
130#include <QtCore/qdir.h>-
131#include <QtCore/qdiriterator.h>-
132#include <QtCore/qfile.h>-
133-
134QT_BEGIN_NAMESPACE-
135-
136/*!-
137 Constructs a QSslCertificate by reading \a format encoded data-
138 from \a device and using the first certificate found. You can-
139 later call isNull() to see if \a device contained a certificate,-
140 and if this certificate was loaded successfully.-
141*/-
142QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)-
143 : d(new QSslCertificatePrivate)-
144{-
145 QSslSocketPrivate::ensureInitialized();-
146 if (device)
deviceDescription
TRUEevaluated 4 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEnever evaluated
0-4
147 d->init(device->readAll(), format);
executed 4 times by 1 test: d->init(device->readAll(), format);
Executed by:
  • tst_qsslcertificate - unknown status
4
148}
executed 4 times by 1 test: end of block
Executed by:
  • tst_qsslcertificate - unknown status
4
149-
150/*!-
151 Constructs a QSslCertificate by parsing the \a format encoded-
152 \a data and using the first available certificate found. You can-
153 later call isNull() to see if \a data contained a certificate,-
154 and if this certificate was loaded successfully.-
155*/-
156QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat format)-
157 : d(new QSslCertificatePrivate)-
158{-
159 QSslSocketPrivate::ensureInitialized();-
160 d->init(data, format);-
161}
executed 30261 times by 16 tests: end of block
Executed by:
  • tst_NetworkSelfTest
  • tst_QAbstractNetworkCache
  • tst_QHttpNetworkConnection
  • tst_QNetworkAccessManager_And_QProgressDialog
  • tst_QNetworkDiskCache
  • tst_QNetworkProxyFactory
  • tst_QNetworkReply
  • tst_QXmlInputSource
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslellipticcurve - unknown status
  • tst_qsslerror - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
  • tst_qtcpsocket - unknown status
30261
162-
163/*!-
164 Constructs an identical copy of \a other.-
165*/-
166QSslCertificate::QSslCertificate(const QSslCertificate &other) : d(other.d)-
167{-
168}
executed 50550 times by 9 tests: end of block
Executed by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslerror - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
50550
169-
170/*!-
171 Destroys the QSslCertificate.-
172*/-
173QSslCertificate::~QSslCertificate()-
174{-
175}-
176-
177/*!-
178 Copies the contents of \a other into this certificate, making the two-
179 certificates identical.-
180*/-
181QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)-
182{-
183 d = other.d;-
184 return *this;
executed 2084 times by 10 tests: return *this;
Executed by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslerror - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
  • tst_qtcpsocket - unknown status
2084
185}-
186-
187/*!-
188 \fn void QSslCertificate::swap(QSslCertificate &other)-
189 \since 5.0-
190-
191 Swaps this certificate instance with \a other. This function is-
192 very fast and never fails.-
193*/-
194-
195/*!-
196 \fn bool QSslCertificate::operator==(const QSslCertificate &other) const-
197-
198 Returns \c true if this certificate is the same as \a other; otherwise-
199 returns \c false.-
200*/-
201-
202/*!-
203 \fn bool QSslCertificate::operator!=(const QSslCertificate &other) const-
204-
205 Returns \c true if this certificate is not the same as \a other; otherwise-
206 returns \c false.-
207*/-
208-
209/*!-
210 \fn bool QSslCertificate::isNull() const-
211-
212 Returns \c true if this is a null certificate (i.e., a certificate-
213 with no contents); otherwise returns \c false.-
214-
215 By default, QSslCertificate constructs a null certificate.-
216-
217 \sa clear()-
218*/-
219-
220#if QT_DEPRECATED_SINCE(5,0)-
221/*!-
222 \fn bool QSslCertificate::isValid() const-
223 \obsolete-
224-
225 To verify a certificate, use verify().-
226 To check if a certificate is blacklisted, use isBlacklisted().-
227 To check if a certificate has expired or is not yet valid, compare-
228 expiryDate() and effectiveDate() with QDateTime::currentDateTime()-
229-
230 This function checks that the current-
231 date-time is within the date-time range during which the-
232 certificate is considered valid, and checks that the-
233 certificate is not in a blacklist of fraudulent certificates.-
234-
235 \sa isNull(), verify(), isBlacklisted(), expiryDate(), effectiveDate()-
236*/-
237#endif-
238-
239/*!-
240 Returns \c true if this certificate is blacklisted; otherwise-
241 returns \c false.-
242-
243 \sa isNull()-
244*/-
245bool QSslCertificate::isBlacklisted() const-
246{-
247 return QSslCertificatePrivate::isBlacklisted(*this);
executed 55 times by 1 test: return QSslCertificatePrivate::isBlacklisted(*this);
Executed by:
  • tst_qsslcertificate - unknown status
55
248}-
249-
250/*!-
251 \fn bool QSslCertificate::isSelfSigned() const-
252 \since 5.4-
253-
254 Returns \c true if this certificate is self signed; otherwise-
255 returns \c false.-
256-
257 A certificate is considered self-signed its issuer and subject-
258 are identical.-
259*/-
260-
261/*!-
262 Clears the contents of this certificate, making it a null-
263 certificate.-
264-
265 \sa isNull()-
266*/-
267void QSslCertificate::clear()-
268{-
269 if (isNull())
isNull()Description
TRUEevaluated 2074 times by 8 tests
Evaluated by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
  • tst_qtcpsocket - unknown status
FALSEevaluated 59 times by 2 tests
Evaluated by:
  • tst_QNetworkReply
  • tst_qsslsocket - unknown status
59-2074
270 return;
executed 2074 times by 8 tests: return;
Executed by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
  • tst_qtcpsocket - unknown status
2074
271 d = new QSslCertificatePrivate;-
272}
executed 59 times by 2 tests: end of block
Executed by:
  • tst_QNetworkReply
  • tst_qsslsocket - unknown status
59
273-
274/*!-
275 \fn QByteArray QSslCertificate::version() const-
276 Returns the certificate's version string.-
277*/-
278-
279/*!-
280 \fn QByteArray QSslCertificate::serialNumber() const-
281-
282 Returns the certificate's serial number string in hexadecimal format.-
283*/-
284-
285/*!-
286 Returns a cryptographic digest of this certificate. By default,-
287 an MD5 digest will be generated, but you can also specify a-
288 custom \a algorithm.-
289*/-
290QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) const-
291{-
292 return QCryptographicHash::hash(toDer(), algorithm);
executed 49 times by 1 test: return QCryptographicHash::hash(toDer(), algorithm);
Executed by:
  • tst_qsslcertificate - unknown status
49
293}-
294-
295/*!-
296 \fn QString QSslCertificate::issuerInfo(SubjectInfo subject) const-
297-
298 Returns the issuer information for the \a subject from the-
299 certificate, or an empty list if there is no information for-
300 \a subject in the certificate. There can be more than one entry-
301 of each type.-
302-
303 \sa subjectInfo()-
304*/-
305-
306/*!-
307 \fn QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const-
308-
309 Returns the issuer information for \a attribute from the certificate,-
310 or an empty list if there is no information for \a attribute in the-
311 certificate. There can be more than one entry for an attribute.-
312-
313 \sa subjectInfo()-
314*/-
315-
316/*!-
317 \fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const-
318-
319 Returns the information for the \a subject, or an empty list if-
320 there is no information for \a subject in the certificate. There-
321 can be more than one entry of each type.-
322-
323 \sa issuerInfo()-
324*/-
325-
326/*!-
327 \fn QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const-
328-
329 Returns the subject information for \a attribute, or an empty list if-
330 there is no information for \a attribute in the certificate. There-
331 can be more than one entry for an attribute.-
332-
333 \sa issuerInfo()-
334*/-
335-
336/*!-
337 \fn QList<QByteArray> QSslCertificate::subjectInfoAttributes() const-
338-
339 \since 5.0-
340 Returns a list of the attributes that have values in the subject-
341 information of this certificate. The information associated-
342 with a given attribute can be accessed using the subjectInfo()-
343 method. Note that this list may include the OIDs for any-
344 elements that are not known by the SSL backend.-
345-
346 \sa subjectInfo()-
347*/-
348-
349/*!-
350 \fn QList<QByteArray> QSslCertificate::issuerInfoAttributes() const-
351-
352 \since 5.0-
353 Returns a list of the attributes that have values in the issuer-
354 information of this certificate. The information associated-
355 with a given attribute can be accessed using the issuerInfo()-
356 method. Note that this list may include the OIDs for any-
357 elements that are not known by the SSL backend.-
358-
359 \sa subjectInfo()-
360*/-
361-
362#if QT_DEPRECATED_SINCE(5,0)-
363/*!-
364 \fn QMultiMap<QSsl::AlternateNameEntryType, QString> QSslCertificate::alternateSubjectNames() const-
365 \obsolete-
366-
367 Use QSslCertificate::subjectAlternativeNames();-
368*/-
369#endif-
370-
371/*!-
372 \fn QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const-
373-
374 Returns the list of alternative subject names for this-
375 certificate. The alternative names typically contain host-
376 names, optionally with wildcards, that are valid for this-
377 certificate.-
378-
379 These names are tested against the connected peer's host name, if-
380 either the subject information for \l CommonName doesn't define a-
381 valid host name, or the subject info name doesn't match the peer's-
382 host name.-
383-
384 \sa subjectInfo()-
385*/-
386-
387/*!-
388 \fn QDateTime QSslCertificate::effectiveDate() const-
389-
390 Returns the date-time that the certificate becomes valid, or an-
391 empty QDateTime if this is a null certificate.-
392-
393 \sa expiryDate()-
394*/-
395-
396/*!-
397 \fn QDateTime QSslCertificate::expiryDate() const-
398-
399 Returns the date-time that the certificate expires, or an empty-
400 QDateTime if this is a null certificate.-
401-
402 \sa effectiveDate()-
403*/-
404-
405/*!-
406 \fn Qt::HANDLE QSslCertificate::handle() const-
407 Returns a pointer to the native certificate handle, if there is-
408 one, or a null pointer otherwise.-
409-
410 You can use this handle, together with the native API, to access-
411 extended information about the certificate.-
412-
413 \warning Use of this function has a high probability of being-
414 non-portable, and its return value may vary from platform to-
415 platform or change from minor release to minor release.-
416*/-
417-
418/*!-
419 \fn QSslKey QSslCertificate::publicKey() const-
420 Returns the certificate subject's public key.-
421*/-
422-
423/*!-
424 \fn QList<QSslCertificateExtension> QSslCertificate::extensions() const-
425-
426 Returns a list containing the X509 extensions of this certificate.-
427 \since 5.0-
428 */-
429-
430/*!-
431 \fn QByteArray QSslCertificate::toPem() const-
432-
433 Returns this certificate converted to a PEM (Base64) encoded-
434 representation.-
435*/-
436-
437/*!-
438 \fn QByteArray QSslCertificate::toDer() const-
439-
440 Returns this certificate converted to a DER (binary) encoded-
441 representation.-
442*/-
443-
444/*!-
445 \fn QString QSslCertificate::toText() const-
446-
447 Returns this certificate converted to a human-readable text-
448 representation.-
449-
450 \since 5.0-
451*/-
452-
453/*!-
454 Searches all files in the \a path for certificates encoded in the-
455 specified \a format and returns them in a list. \a path must be a file-
456 or a pattern matching one or more files, as specified by \a syntax.-
457-
458 Example:-
459-
460 \snippet code/src_network_ssl_qsslcertificate.cpp 0-
461-
462 \sa fromData()-
463*/-
464QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,-
465 QSsl::EncodingFormat format,-
466 QRegExp::PatternSyntax syntax)-
467{-
468 // $, (,), *, +, ., ?, [, ,], ^, {, | and }.-
469-
470 // make sure to use the same path separators on Windows and Unix like systems.-
471 QString sourcePath = QDir::fromNativeSeparators(path);-
472-
473 // Find the path without the filename-
474 QString pathPrefix = sourcePath.left(sourcePath.lastIndexOf(QLatin1Char('/')));-
475-
476 // Check if the path contains any special chars-
477 int pos = -1;-
478 if (syntax == QRegExp::Wildcard)
syntax == QRegExp::WildcardDescription
TRUEevaluated 22 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEevaluated 9845 times by 4 tests
Evaluated by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
22-9845
479 pos = pathPrefix.indexOf(QRegExp(QLatin1String("[*?[]")));
executed 22 times by 1 test: pos = pathPrefix.indexOf(QRegExp(QLatin1String("[*?[]")));
Executed by:
  • tst_qsslcertificate - unknown status
22
480 else if (syntax != QRegExp::FixedString)
syntax != QRegExp::FixedStringDescription
TRUEevaluated 16 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEevaluated 9829 times by 4 tests
Evaluated by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
16-9829
481 pos = sourcePath.indexOf(QRegExp(QLatin1String("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
executed 16 times by 1 test: pos = sourcePath.indexOf(QRegExp(QLatin1String("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
Executed by:
  • tst_qsslcertificate - unknown status
16
482 if (pos != -1) {
pos != -1Description
TRUEevaluated 20 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEevaluated 9847 times by 4 tests
Evaluated by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
20-9847
483 // there was a special char in the path so cut of the part containing that char.-
484 pathPrefix = pathPrefix.left(pos);-
485 const int lastIndexOfSlash = pathPrefix.lastIndexOf(QLatin1Char('/'));-
486 if (lastIndexOfSlash != -1)
lastIndexOfSlash != -1Description
TRUEnever evaluated
FALSEevaluated 20 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
0-20
487 pathPrefix = pathPrefix.left(lastIndexOfSlash);
never executed: pathPrefix = pathPrefix.left(lastIndexOfSlash);
0
488 else-
489 pathPrefix.clear();
executed 20 times by 1 test: pathPrefix.clear();
Executed by:
  • tst_qsslcertificate - unknown status
20
490 } else {-
491 // Check if the path is a file.-
492 if (QFileInfo(sourcePath).isFile()) {
QFileInfo(sourcePath).isFile()Description
TRUEevaluated 9709 times by 4 tests
Evaluated by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
FALSEevaluated 138 times by 3 tests
Evaluated by:
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
138-9709
493 QFile file(sourcePath);-
494 QIODevice::OpenMode openMode = QIODevice::ReadOnly;-
495 if (format == QSsl::Pem)
format == QSsl::PemDescription
TRUEevaluated 9707 times by 4 tests
Evaluated by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
FALSEevaluated 2 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
2-9707
496 openMode |= QIODevice::Text;
executed 9707 times by 4 tests: openMode |= QIODevice::Text;
Executed by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
9707
497 if (file.open(openMode))
file.open(openMode)Description
TRUEevaluated 9709 times by 4 tests
Evaluated by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
FALSEnever evaluated
0-9709
498 return QSslCertificate::fromData(file.readAll(), format);
executed 9709 times by 4 tests: return QSslCertificate::fromData(file.readAll(), format);
Executed by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
9709
499 return QList<QSslCertificate>();
never executed: return QList<QSslCertificate>();
0
500 }-
501 }
executed 138 times by 3 tests: end of block
Executed by:
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
138
502-
503 // Special case - if the prefix ends up being nothing, use "." instead.-
504 int startIndex = 0;-
505 if (pathPrefix.isEmpty()) {
pathPrefix.isEmpty()Description
TRUEevaluated 26 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEevaluated 132 times by 3 tests
Evaluated by:
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
26-132
506 pathPrefix = QLatin1String(".");-
507 startIndex = 2;-
508 }
executed 26 times by 1 test: end of block
Executed by:
  • tst_qsslcertificate - unknown status
26
509-
510 // The path can be a file or directory.-
511 QList<QSslCertificate> certs;-
512 QRegExp pattern(sourcePath, Qt::CaseSensitive, syntax);-
513 QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);-
514 while (it.hasNext()) {
it.hasNext()Description
TRUEevaluated 2628 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEevaluated 158 times by 3 tests
Evaluated by:
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
158-2628
515 QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex);
startIndex == 0Description
TRUEevaluated 496 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEevaluated 2132 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
496-2132
516 if (!pattern.exactMatch(filePath))
!pattern.exactMatch(filePath)Description
TRUEevaluated 2492 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEevaluated 136 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
136-2492
517 continue;
executed 2492 times by 1 test: continue;
Executed by:
  • tst_qsslcertificate - unknown status
2492
518-
519 QFile file(filePath);-
520 QIODevice::OpenMode openMode = QIODevice::ReadOnly;-
521 if (format == QSsl::Pem)
format == QSsl::PemDescription
TRUEevaluated 94 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEevaluated 42 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
42-94
522 openMode |= QIODevice::Text;
executed 94 times by 1 test: openMode |= QIODevice::Text;
Executed by:
  • tst_qsslcertificate - unknown status
94
523 if (file.open(openMode))
file.open(openMode)Description
TRUEevaluated 136 times by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEnever evaluated
0-136
524 certs += QSslCertificate::fromData(file.readAll(), format);
executed 136 times by 1 test: certs += QSslCertificate::fromData(file.readAll(), format);
Executed by:
  • tst_qsslcertificate - unknown status
136
525 }
executed 136 times by 1 test: end of block
Executed by:
  • tst_qsslcertificate - unknown status
136
526 return certs;
executed 158 times by 3 tests: return certs;
Executed by:
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
158
527}-
528-
529/*!-
530 Searches for and parses all certificates in \a device that are-
531 encoded in the specified \a format and returns them in a list of-
532 certificates.-
533-
534 \sa fromData()-
535*/-
536QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::EncodingFormat format)-
537{-
538 if (!device) {
!deviceDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEnever evaluated
0-1
539 qCWarning(lcSsl, "QSslCertificate::fromDevice: cannot read from a null device");
executed 1 time by 1 test: QMessageLogger(__FILE__, 539, __PRETTY_FUNCTION__, lcSsl().categoryName()).warning("QSslCertificate::fromDevice: cannot read from a null device");
Executed by:
  • tst_qsslcertificate - unknown status
qt_category_enabledDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
FALSEevaluated 1 time by 1 test
Evaluated by:
  • tst_qsslcertificate - unknown status
1
540 return QList<QSslCertificate>();
executed 1 time by 1 test: return QList<QSslCertificate>();
Executed by:
  • tst_qsslcertificate - unknown status
1
541 }-
542 return fromData(device->readAll(), format);
never executed: return fromData(device->readAll(), format);
0
543}-
544-
545/*!-
546 Searches for and parses all certificates in \a data that are-
547 encoded in the specified \a format and returns them in a list of-
548 certificates.-
549-
550 \sa fromDevice()-
551*/-
552QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::EncodingFormat format)-
553{-
554 return (format == QSsl::Pem)
executed 9845 times by 4 tests: return (format == QSsl::Pem) ? QSslCertificatePrivate::certificatesFromPem(data) : QSslCertificatePrivate::certificatesFromDer(data);
Executed by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
9845
555 ? QSslCertificatePrivate::certificatesFromPem(data)
executed 9845 times by 4 tests: return (format == QSsl::Pem) ? QSslCertificatePrivate::certificatesFromPem(data) : QSslCertificatePrivate::certificatesFromDer(data);
Executed by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
9845
556 : QSslCertificatePrivate::certificatesFromDer(data);
executed 9845 times by 4 tests: return (format == QSsl::Pem) ? QSslCertificatePrivate::certificatesFromPem(data) : QSslCertificatePrivate::certificatesFromDer(data);
Executed by:
  • tst_QNetworkReply
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
9845
557}-
558-
559/*!-
560 Verifies a certificate chain. The chain to be verified is passed in the-
561 \a certificateChain parameter. The first certificate in the list should-
562 be the leaf certificate of the chain to be verified. If \a hostName is-
563 specified then the certificate is also checked to see if it is valid for-
564 the specified host name.-
565-
566 Note that the root (CA) certificate should not be included in the list to be verified,-
567 this will be looked up automatically either using the CA list specified by-
568 QSslSocket::defaultCaCertificates() or, if possible, it will be loaded on demand-
569 on Unix.-
570-
571 \since 5.0-
572 */-
573#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)-
574QList<QSslError> QSslCertificate::verify(const QList<QSslCertificate> &certificateChain, const QString &hostName)-
575#else-
576QList<QSslError> QSslCertificate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)-
577#endif-
578{-
579 return QSslSocketBackendPrivate::verify(certificateChain, hostName);
executed 8 times by 1 test: return QSslSocketBackendPrivate::verify(certificateChain, hostName);
Executed by:
  • tst_qsslcertificate - unknown status
8
580}-
581-
582/*!-
583 \since 5.4-
584-
585 Imports a PKCS#12 (pfx) file from the specified \a device. A PKCS#12-
586 file is a bundle that can contain a number of certificates and keys.-
587 This method reads a single \a key, its \a certificate and any-
588 associated \a caCertificates from the bundle. If a \a passPhrase is-
589 specified then this will be used to decrypt the bundle. Returns-
590 \c true if the PKCS#12 file was successfully loaded.-
591-
592 \note The \a device must be open and ready to be read from.-
593 */-
594bool QSslCertificate::importPkcs12(QIODevice *device,-
595 QSslKey *key, QSslCertificate *certificate,-
596 QList<QSslCertificate> *caCertificates,-
597 const QByteArray &passPhrase)-
598{-
599 return QSslSocketBackendPrivate::importPkcs12(device, key, certificate, caCertificates, passPhrase);
executed 1 time by 1 test: return QSslSocketBackendPrivate::importPkcs12(device, key, certificate, caCertificates, passPhrase);
Executed by:
  • tst_qsslcertificate - unknown status
1
600}-
601-
602// These certificates are known to be fraudulent and were created during the comodo-
603// compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html-
604static const char *const certificate_blacklist[] = {-
605 "04:7e:cb:e9:fc:a5:5f:7b:d0:9e:ae:36:e1:0c:ae:1e", "mail.google.com", // Comodo-
606 "f5:c8:6a:f3:61:62:f1:3a:64:f5:4f:6d:c9:58:7c:06", "www.google.com", // Comodo-
607 "d7:55:8f:da:f5:f1:10:5b:b2:13:28:2b:70:77:29:a3", "login.yahoo.com", // Comodo-
608 "39:2a:43:4f:0e:07:df:1f:8a:a3:05:de:34:e0:c2:29", "login.yahoo.com", // Comodo-
609 "3e:75:ce:d4:6b:69:30:21:21:88:30:ae:86:a8:2a:71", "login.yahoo.com", // Comodo-
610 "e9:02:8b:95:78:e4:15:dc:1a:71:0a:2b:88:15:44:47", "login.skype.com", // Comodo-
611 "92:39:d5:34:8f:40:d1:69:5a:74:54:70:e1:f2:3f:43", "addons.mozilla.org", // Comodo-
612 "b0:b7:13:3e:d0:96:f9:b5:6f:ae:91:c8:74:bd:3a:c0", "login.live.com", // Comodo-
613 "d8:f3:5f:4e:b7:87:2b:2d:ab:06:92:e3:15:38:2f:b0", "global trustee", // Comodo-
614-
615 "05:e2:e6:a4:cd:09:ea:54:d6:65:b0:75:fe:22:a2:56", "*.google.com", // leaf certificate issued by DigiNotar-
616 "0c:76:da:9c:91:0c:4e:2c:9e:fe:15:d0:58:93:3c:4c", "DigiNotar Root CA", // DigiNotar root-
617 "f1:4a:13:f4:87:2b:56:dc:39:df:84:ca:7a:a1:06:49", "DigiNotar Services CA", // DigiNotar intermediate signed by DigiNotar Root-
618 "36:16:71:55:43:42:1b:9d:e6:cb:a3:64:41:df:24:38", "DigiNotar Services 1024 CA", // DigiNotar intermediate signed by DigiNotar Root-
619 "0a:82:bd:1e:14:4e:88:14:d7:5b:1a:55:27:be:bf:3e", "DigiNotar Root CA G2", // other DigiNotar Root CA-
620 "a4:b6:ce:e3:2e:d3:35:46:26:3c:b3:55:3a:a8:92:21", "CertiID Enterprise Certificate Authority", // DigiNotar intermediate signed by "DigiNotar Root CA G2"-
621 "5b:d5:60:9c:64:17:68:cf:21:0e:35:fd:fb:05:ad:41", "DigiNotar Qualified CA", // DigiNotar intermediate signed by DigiNotar Root-
622-
623 "46:9c:2c:b0", "DigiNotar Services 1024 CA", // DigiNotar intermediate cross-signed by Entrust-
624 "07:27:10:0d", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust-
625 "07:27:0f:f9", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust-
626 "07:27:10:03", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust-
627 "01:31:69:b0", "DigiNotar PKIoverheid CA Overheid en Bedrijven", // DigiNotar intermediate cross-signed by the Dutch government-
628 "01:31:34:bf", "DigiNotar PKIoverheid CA Organisatie - G2", // DigiNotar intermediate cross-signed by the Dutch government-
629 "d6:d0:29:77:f1:49:fd:1a:83:f2:b9:ea:94:8c:5c:b4", "DigiNotar Extended Validation CA", // DigiNotar intermediate signed by DigiNotar EV Root-
630 "1e:7d:7a:53:3d:45:30:41:96:40:0f:71:48:1f:45:04", "DigiNotar Public CA 2025", // DigiNotar intermediate-
631// "(has not been seen in the wild so far)", "DigiNotar Public CA - G2", // DigiNotar intermediate-
632// "(has not been seen in the wild so far)", "Koninklijke Notariele Beroepsorganisatie CA", // compromised during DigiNotar breach-
633// "(has not been seen in the wild so far)", "Stichting TTP Infos CA," // compromised during DigiNotar breach-
634 "46:9c:2c:af", "DigiNotar Root CA", // DigiNotar intermediate cross-signed by Entrust-
635 "46:9c:3c:c9", "DigiNotar Root CA", // DigiNotar intermediate cross-signed by Entrust-
636-
637 "07:27:14:a9", "Digisign Server ID (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Verizon CyberTrust-
638 "4c:0e:63:6a", "Digisign Server ID - (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Entrust-
639 "72:03:21:05:c5:0c:08:57:3d:8e:a5:30:4e:fe:e8:b0", "UTN-USERFirst-Hardware", // comodogate test certificate-
640 "41", "MD5 Collisions Inc. (http://www.phreedom.org/md5)", // http://www.phreedom.org/research/rogue-ca/-
641-
642 "08:27", "*.EGO.GOV.TR", // Turktrust mis-issued intermediate certificate-
643 "08:64", "e-islem.kktcmerkezbankasi.org", // Turktrust mis-issued intermediate certificate-
644-
645 "03:1d:a7", "AC DG Tr\xC3\xA9sor SSL", // intermediate certificate linking back to ANSSI French National Security Agency-
646 "27:83", "NIC Certifying Authority", // intermediate certificate from NIC India (2007)-
647 "27:92", "NIC CA 2011", // intermediate certificate from NIC India (2011)-
648 "27:b1", "NIC CA 2014", // intermediate certificate from NIC India (2014)-
649 0-
650};-
651-
652bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)-
653{-
654 for (int a = 0; certificate_blacklist[a] != 0; a++) {
certificate_blacklist[a] != 0Description
TRUEevaluated 16975 times by 8 tests
Evaluated by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
FALSEevaluated 464 times by 8 tests
Evaluated by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
464-16975
655 QString blacklistedCommonName = QString::fromUtf8(certificate_blacklist[(a+1)]);-
656 if (certificate.serialNumber() == certificate_blacklist[a++] &&
certificate.se...blacklist[a++]Description
TRUEevaluated 18 times by 2 tests
Evaluated by:
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
FALSEevaluated 16957 times by 8 tests
Evaluated by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
18-16957
657 (certificate.subjectInfo(QSslCertificate::CommonName).contains(blacklistedCommonName) ||
certificate.su...tedCommonName)Description
TRUEevaluated 18 times by 2 tests
Evaluated by:
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
FALSEnever evaluated
0-18
658 certificate.issuerInfo(QSslCertificate::CommonName).contains(blacklistedCommonName)))
certificate.is...tedCommonName)Description
TRUEnever evaluated
FALSEnever evaluated
0
659 return true;
executed 18 times by 2 tests: return true;
Executed by:
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
18
660 }
executed 16957 times by 8 tests: end of block
Executed by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
16957
661 return false;
executed 464 times by 8 tests: return false;
Executed by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
464
662}-
663-
664QByteArray QSslCertificatePrivate::subjectInfoToString(QSslCertificate::SubjectInfo info)-
665{-
666 QByteArray str;-
667 switch (info) {-
668 case QSslCertificate::Organization: str = QByteArray("O"); break;
executed 76 times by 1 test: break;
Executed by:
  • tst_qsslcertificate - unknown status
executed 76 times by 1 test: case QSslCertificate::Organization:
Executed by:
  • tst_qsslcertificate - unknown status
76
669 case QSslCertificate::CommonName: str = QByteArray("CN"); break;
executed 484 times by 8 tests: break;
Executed by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
executed 484 times by 8 tests: case QSslCertificate::CommonName:
Executed by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
484
670 case QSslCertificate::LocalityName: str = QByteArray("L"); break;
executed 74 times by 1 test: break;
Executed by:
  • tst_qsslcertificate - unknown status
executed 74 times by 1 test: case QSslCertificate::LocalityName:
Executed by:
  • tst_qsslcertificate - unknown status
74
671 case QSslCertificate::OrganizationalUnitName: str = QByteArray("OU"); break;
executed 74 times by 1 test: break;
Executed by:
  • tst_qsslcertificate - unknown status
executed 74 times by 1 test: case QSslCertificate::OrganizationalUnitName:
Executed by:
  • tst_qsslcertificate - unknown status
74
672 case QSslCertificate::CountryName: str = QByteArray("C"); break;
executed 74 times by 1 test: break;
Executed by:
  • tst_qsslcertificate - unknown status
executed 74 times by 1 test: case QSslCertificate::CountryName:
Executed by:
  • tst_qsslcertificate - unknown status
74
673 case QSslCertificate::StateOrProvinceName: str = QByteArray("ST"); break;
executed 74 times by 1 test: break;
Executed by:
  • tst_qsslcertificate - unknown status
executed 74 times by 1 test: case QSslCertificate::StateOrProvinceName:
Executed by:
  • tst_qsslcertificate - unknown status
74
674 case QSslCertificate::DistinguishedNameQualifier: str = QByteArray("dnQualifier"); break;
never executed: break;
never executed: case QSslCertificate::DistinguishedNameQualifier:
0
675 case QSslCertificate::SerialNumber: str = QByteArray("serialNumber"); break;
never executed: break;
never executed: case QSslCertificate::SerialNumber:
0
676 case QSslCertificate::EmailAddress: str = QByteArray("emailAddress"); break;
never executed: break;
never executed: case QSslCertificate::EmailAddress:
0
677 }-
678 return str;
executed 856 times by 8 tests: return str;
Executed by:
  • tst_NetworkSelfTest
  • tst_QHttpNetworkConnection
  • tst_QNetworkReply
  • tst_Spdy
  • tst_qsslcertificate - unknown status
  • tst_qsslsocket - unknown status
  • tst_qsslsocket_onDemandCertificates_member - unknown status
  • tst_qsslsocket_onDemandCertificates_static - unknown status
856
679}-
680-
681/*!-
682 \fn uint qHash(const QSslCertificate &key, uint seed)-
683-
684 Returns the hash value for the \a key, using \a seed to seed the calculation.-
685 \since 5.4-
686 \relates QHash-
687*/-
688-
689#ifndef QT_NO_DEBUG_STREAM-
690QDebug operator<<(QDebug debug, const QSslCertificate &certificate)-
691{-
692 QDebugStateSaver saver(debug);-
693 debug.resetFormat().nospace();-
694 debug << "QSslCertificate("-
695 << certificate.version()-
696 << ", " << certificate.serialNumber()-
697 << ", " << certificate.digest().toBase64()-
698 << ", " << certificate.issuerInfo(QSslCertificate::Organization)-
699 << ", " << certificate.subjectInfo(QSslCertificate::Organization)-
700 << ", " << certificate.subjectAlternativeNames()-
701#ifndef QT_NO_DATESTRING-
702 << ", " << certificate.effectiveDate()-
703 << ", " << certificate.expiryDate()-
704#endif-
705 << ')';-
706 return debug;
never executed: return debug;
0
707}-
708QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info)-
709{-
710 switch (info) {-
711 case QSslCertificate::Organization: debug << "Organization"; break;
never executed: break;
never executed: case QSslCertificate::Organization:
0
712 case QSslCertificate::CommonName: debug << "CommonName"; break;
never executed: break;
never executed: case QSslCertificate::CommonName:
0
713 case QSslCertificate::CountryName: debug << "CountryName"; break;
never executed: break;
never executed: case QSslCertificate::CountryName:
0
714 case QSslCertificate::LocalityName: debug << "LocalityName"; break;
never executed: break;
never executed: case QSslCertificate::LocalityName:
0
715 case QSslCertificate::OrganizationalUnitName: debug << "OrganizationalUnitName"; break;
never executed: break;
never executed: case QSslCertificate::OrganizationalUnitName:
0
716 case QSslCertificate::StateOrProvinceName: debug << "StateOrProvinceName"; break;
never executed: break;
never executed: case QSslCertificate::StateOrProvinceName:
0
717 case QSslCertificate::DistinguishedNameQualifier: debug << "DistinguishedNameQualifier"; break;
never executed: break;
never executed: case QSslCertificate::DistinguishedNameQualifier:
0
718 case QSslCertificate::SerialNumber: debug << "SerialNumber"; break;
never executed: break;
never executed: case QSslCertificate::SerialNumber:
0
719 case QSslCertificate::EmailAddress: debug << "EmailAddress"; break;
never executed: break;
never executed: case QSslCertificate::EmailAddress:
0
720 }-
721 return debug;
never executed: return debug;
0
722}-
723#endif-
724-
725QT_END_NAMESPACE-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9