source: trunk/src/network/ssl/qsslcertificate.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 24.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42
43/*!
44 \class QSslCertificate
45 \brief The QSslCertificate class provides a convenient API for an X509 certificate.
46 \since 4.3
47
48 \reentrant
49 \ingroup io
50 \ingroup ssl
51 \inmodule QtNetwork
52
53 QSslCertificate stores an X509 certificate, and is commonly used
54 to verify the identity and store information about the local host,
55 a remotely connected peer, or a trusted third party Certificate
56 Authority.
57
58 There are many ways to construct a QSslCertificate. The most
59 common way is to call QSslSocket::peerCertificate(), which returns
60 a QSslCertificate object, or QSslSocket::peerCertificateChain(),
61 which returns a list of them. You can also load certificates from
62 a DER (binary) or PEM (Base64) encoded bundle, typically stored as
63 one or more local files, or in a Qt Resource.
64
65 You can call isNull() to check if your certificate is null. By
66 default, QSslCertificate constructs a null certificate. To check
67 if the certificate is valid, call isValid(). A null certificate is
68 invalid, but an invalid certificate is not necessarily null. If
69 you want to reset all contents in a certificate, call clear().
70
71 After loading a certificate, you can find information about the
72 certificate, its subject, and its issuer, by calling one of the
73 many accessor functions, including version(), serialNumber(),
74 issuerInfo() and subjectInfo(). You can call notValidBefore() and
75 notValidAfter() to check when the certificate was issued, and when
76 it expires. The publicKey() function returns the certificate
77 subject's public key as a QSslKey. You can call issuerInfo() or
78 subjectInfo() to get detailed information about the certificate
79 issuer and its subject.
80
81 Internally, QSslCertificate is stored as an X509 structure. You
82 can access this handle by calling handle(), but the results are
83 likely to not be portable.
84
85 \sa QSslSocket, QSslKey, QSslCipher, QSslError
86*/
87
88/*!
89 \enum QSslCertificate::SubjectInfo
90
91 Describes keys that you can pass to QSslCertificate::issuerInfo() or
92 QSslCertificate::subjectInfo() to get information about the certificate
93 issuer or subject.
94
95 \value Organization "O" The name of the organization.
96
97 \value CommonName "CN" The common name; most often this is used to store
98 the host name.
99
100 \value LocalityName "L" The locality.
101
102 \value OrganizationalUnitName "OU" The organizational unit name.
103
104 \value CountryName "C" The country.
105
106 \value StateOrProvinceName "ST" The state or province.
107*/
108
109#include "qsslsocket_openssl_symbols_p.h"
110#include "qsslcertificate.h"
111#include "qsslcertificate_p.h"
112#include "qsslkey.h"
113#include "qsslkey_p.h"
114
115#include <QtCore/qatomic.h>
116#include <QtCore/qdatetime.h>
117#include <QtCore/qdebug.h>
118#include <QtCore/qdir.h>
119#include <QtCore/qdiriterator.h>
120#include <QtCore/qfile.h>
121#include <QtCore/qfileinfo.h>
122#include <QtCore/qmap.h>
123#include <QtCore/qstring.h>
124#include <QtCore/qstringlist.h>
125
126QT_BEGIN_NAMESPACE
127
128/*!
129 Constructs a QSslCertificate by reading \a format encoded data
130 from \a device and using the first certificate found. You can
131 later call isNull() to see if \a device contained a certificate,
132 and if this certificate was loaded successfully.
133*/
134QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
135 : d(new QSslCertificatePrivate)
136{
137 QSslSocketPrivate::ensureInitialized();
138 if (device)
139 d->init(device->readAll(), format);
140}
141
142/*!
143 Constructs a QSslCertificate by parsing the \a format encoded
144 \a data and using the first available certificate found. You can
145 later call isNull() to see if \a data contained a certificate,
146 and if this certificate was loaded successfully.
147*/
148QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat format)
149 : d(new QSslCertificatePrivate)
150{
151 QSslSocketPrivate::ensureInitialized();
152 d->init(data, format);
153}
154
155/*!
156 Constructs an identical copy of \a other.
157*/
158QSslCertificate::QSslCertificate(const QSslCertificate &other) : d(other.d)
159{
160 d->ref.ref();
161}
162
163/*!
164 Destroys the QSslCertificate.
165*/
166QSslCertificate::~QSslCertificate()
167{
168 if (!d->ref.deref())
169 delete d;
170}
171
172/*!
173 Copies the contents of \a other into this certificate, making the two
174 certificates identical.
175*/
176QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
177{
178 qAtomicAssign(d, other.d);
179 return *this;
180}
181
182/*!
183 Returns true if this certificate is the same as \a other; otherwise
184 returns false.
185*/
186bool QSslCertificate::operator==(const QSslCertificate &other) const
187{
188 if (d == other.d)
189 return true;
190 if (d->null && other.d->null)
191 return true;
192 if (d->x509 && other.d->x509)
193 return q_X509_cmp(d->x509, other.d->x509) == 0;
194 return false;
195}
196
197/*!
198 \fn bool QSslCertificate::operator!=(const QSslCertificate &other) const
199
200 Returns true if this certificate is not the same as \a other; otherwise
201 returns false.
202*/
203
204/*!
205 Returns true if this is a null certificate (i.e., a certificate
206 with no contents); otherwise returns false.
207
208 By default, QSslCertificate constructs a null certificate.
209
210 \sa isValid(), clear()
211*/
212bool QSslCertificate::isNull() const
213{
214 return d->null;
215}
216
217/*!
218 Returns true if this certificate is valid; otherwise returns
219 false.
220
221 Note: Currently, this function only checks that the current
222 data-time is within the date-time range during which the
223 certificate is considered valid. No other checks are
224 currently performed.
225
226 \sa isNull()
227*/
228bool QSslCertificate::isValid() const
229{
230 const QDateTime currentTime = QDateTime::currentDateTime();
231 return currentTime >= d->notValidBefore && currentTime <= d->notValidAfter;
232}
233
234/*!
235 Clears the contents of this certificate, making it a null
236 certificate.
237
238 \sa isNull()
239*/
240void QSslCertificate::clear()
241{
242 if (isNull())
243 return;
244 if (d->ref == 1)
245 delete d;
246 else
247 d->ref.deref();
248
249 d = new QSslCertificatePrivate;
250}
251
252/*!
253 Returns the certificate's version string.
254*/
255QByteArray QSslCertificate::version() const
256{
257 return d->versionString;
258}
259
260/*!
261 Returns the certificate's serial number string.
262*/
263QByteArray QSslCertificate::serialNumber() const
264{
265 return d->serialNumberString;
266}
267
268/*!
269 Returns a cryptographic digest of this certificate. By default,
270 and MD5 digest will be generated, but you can also specify a
271 custom \a algorithm.
272*/
273QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) const
274{
275 return QCryptographicHash::hash(toDer(), algorithm);
276}
277
278static QString _q_SubjectInfoToString(QSslCertificate::SubjectInfo info)
279{
280 QString str;
281 switch (info) {
282 case QSslCertificate::Organization: str = QLatin1String("O"); break;
283 case QSslCertificate::CommonName: str = QLatin1String("CN"); break;
284 case QSslCertificate::LocalityName: str = QLatin1String("L"); break;
285 case QSslCertificate::OrganizationalUnitName: str = QLatin1String("OU"); break;
286 case QSslCertificate::CountryName: str = QLatin1String("C"); break;
287 case QSslCertificate::StateOrProvinceName: str = QLatin1String("ST"); break;
288 }
289 return str;
290}
291
292/*!
293 \fn QString QSslCertificate::issuerInfo(SubjectInfo subject) const
294
295 Returns the issuer information for the \a subject from the
296 certificate, or an empty string if there is no information for
297 \a subject in the certificate.
298
299 \sa subjectInfo()
300*/
301QString QSslCertificate::issuerInfo(SubjectInfo info) const
302{
303 return d->issuerInfo.value(_q_SubjectInfoToString(info));
304}
305
306/*!
307 Returns the issuer information for \a tag from the certificate,
308 or an empty string if there is no information for \a tag in the
309 certificate.
310
311 \sa subjectInfo()
312*/
313QString QSslCertificate::issuerInfo(const QByteArray &tag) const
314{
315 // ### Use a QByteArray for the keys in the map
316 return d->issuerInfo.value(QString::fromLatin1(tag));
317}
318
319/*!
320
321 \fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const
322
323 Returns the information for the \a subject, or an empty string if
324 there is no information for \a subject in the certificate.
325
326 \sa issuerInfo()
327*/
328QString QSslCertificate::subjectInfo(SubjectInfo info) const
329{
330 return d->subjectInfo.value(_q_SubjectInfoToString(info));
331}
332
333/*!
334 Returns the subject information for \a tag, or an empty string if
335 there is no information for \a tag in the certificate.
336
337 \sa issuerInfo()
338*/
339QString QSslCertificate::subjectInfo(const QByteArray &tag) const
340{
341 // ### Use a QByteArray for the keys in the map
342 return d->subjectInfo.value(QString::fromLatin1(tag));
343}
344
345/*!
346 Returns the list of alternative subject names for this
347 certificate. The alternate subject names typically contain host
348 names, optionally with wildcards, that are valid for this
349 certificate.
350
351 These names are tested against the connected peer's host name, if
352 either the subject information for \l CommonName doesn't define a
353 valid host name, or the subject info name doesn't match the peer's
354 host name.
355
356 \sa subjectInfo()
357*/
358QMultiMap<QSsl::AlternateNameEntryType, QString> QSslCertificate::alternateSubjectNames() const
359{
360 QMultiMap<QSsl::AlternateNameEntryType, QString> result;
361
362 if (!d->x509)
363 return result;
364
365 STACK *altNames = (STACK *)q_X509_get_ext_d2i(d->x509, NID_subject_alt_name, 0, 0);
366
367 if (altNames) {
368 for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
369 const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
370 if (genName->type != GEN_DNS && genName->type != GEN_EMAIL)
371 continue;
372
373 int len = q_ASN1_STRING_length(genName->d.ia5);
374 if (len < 0 || len >= 8192) {
375 // broken name
376 continue;
377 }
378
379 const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_data(genName->d.ia5));
380 const QString altName = QLatin1String(QByteArray(altNameStr, len));
381 if (genName->type == GEN_DNS)
382 result.insert(QSsl::DnsEntry, altName);
383 else if (genName->type == GEN_EMAIL)
384 result.insert(QSsl::EmailEntry, altName);
385 }
386 q_sk_free(altNames);
387 }
388
389 return result;
390}
391
392/*!
393 Returns the date-time that the certificate becomes valid, or an
394 empty QDateTime if this is a null certificate.
395
396 \sa expiryDate()
397*/
398QDateTime QSslCertificate::effectiveDate() const
399{
400 return d->notValidBefore;
401}
402
403/*!
404 Returns the date-time that the certificate expires, or an empty
405 QDateTime if this is a null certificate.
406
407 \sa effectiveDate()
408*/
409QDateTime QSslCertificate::expiryDate() const
410{
411 return d->notValidAfter;
412}
413
414/*!
415 Returns a pointer to the native certificate handle, if there is
416 one, or a null pointer otherwise.
417
418 You can use this handle, together with the native API, to access
419 extended information about the certificate.
420
421 \warning Use of this function has a high probability of being
422 non-portable, and its return value may vary from platform to
423 platform or change from minor release to minor release.
424*/
425Qt::HANDLE QSslCertificate::handle() const
426{
427 return Qt::HANDLE(d->x509);
428}
429
430/*!
431 Returns the certificate subject's public key.
432*/
433QSslKey QSslCertificate::publicKey() const
434{
435 if (!d->x509)
436 return QSslKey();
437
438 QSslKey key;
439
440 key.d->type = QSsl::PublicKey;
441 X509_PUBKEY *xkey = d->x509->cert_info->key;
442 EVP_PKEY *pkey = q_X509_PUBKEY_get(xkey);
443 Q_ASSERT(pkey);
444
445 if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA) {
446 key.d->rsa = q_EVP_PKEY_get1_RSA(pkey);
447 key.d->algorithm = QSsl::Rsa;
448 key.d->isNull = false;
449 } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) {
450 key.d->dsa = q_EVP_PKEY_get1_DSA(pkey);
451 key.d->algorithm = QSsl::Dsa;
452 key.d->isNull = false;
453 } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DH) {
454 // DH unsupported
455 } else {
456 // error?
457 }
458
459 q_EVP_PKEY_free(pkey);
460 return key;
461}
462
463/*!
464 Returns this certificate converted to a PEM (Base64) encoded
465 representation.
466*/
467QByteArray QSslCertificate::toPem() const
468{
469 if (!d->x509)
470 return QByteArray();
471 return d->QByteArray_from_X509(d->x509, QSsl::Pem);
472}
473
474/*!
475 Returns this certificate converted to a DER (binary) encoded
476 representation.
477*/
478QByteArray QSslCertificate::toDer() const
479{
480 if (!d->x509)
481 return QByteArray();
482 return d->QByteArray_from_X509(d->x509, QSsl::Der);
483}
484
485/*!
486 Searches all files in the \a path for certificates encoded in the
487 specified \a format and returns them in a list. \e must be a file or a
488 pattern matching one or more files, as specified by \a syntax.
489
490 Example:
491
492 \snippet doc/src/snippets/code/src_network_ssl_qsslcertificate.cpp 0
493
494 \sa fromData()
495*/
496QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
497 QSsl::EncodingFormat format,
498 QRegExp::PatternSyntax syntax)
499{
500 // $, (,), *, +, ., ?, [, ,], ^, {, | and }.
501 int pos = -1;
502 if (syntax == QRegExp::Wildcard)
503 pos = path.indexOf(QRegExp(QLatin1String("[^\\][\\*\\?\\[\\]]")));
504 else if (syntax != QRegExp::FixedString)
505 pos = path.indexOf(QRegExp(QLatin1String("[^\\][\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
506 QString pathPrefix = path.left(pos); // == path if pos < 0
507 if (pos != -1)
508 pathPrefix = pathPrefix.left(pathPrefix.lastIndexOf(QLatin1Char('/')));
509
510 // Special case - if the prefix ends up being nothing, use "." instead and
511 // chop off the first two characters from the glob'ed paths.
512 int startIndex = 0;
513 if (pathPrefix.trimmed().isEmpty()) {
514 startIndex = 2;
515 pathPrefix = QLatin1String(".");
516 }
517
518 // The path is a file.
519 if (pos == -1 && QFileInfo(pathPrefix).isFile()) {
520 QFile file(pathPrefix);
521 if (file.open(QIODevice::ReadOnly | QIODevice::Text))
522 return QSslCertificate::fromData(file.readAll(),format);
523 return QList<QSslCertificate>();
524 }
525
526 // The path can be a file or directory.
527 QList<QSslCertificate> certs;
528 QRegExp pattern(path, Qt::CaseSensitive, syntax);
529 QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
530 while (it.hasNext()) {
531 QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex);
532 if (!pattern.exactMatch(filePath))
533 continue;
534
535 QFile file(filePath);
536 if (file.open(QIODevice::ReadOnly | QIODevice::Text))
537 certs += QSslCertificate::fromData(file.readAll(),format);
538 }
539 return certs;
540}
541
542/*!
543 Searches for and parses all certificates in \a device that are
544 encoded in the specified \a format and returns them in a list of
545 certificates.
546
547 \sa fromData()
548*/
549QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::EncodingFormat format)
550{
551 if (!device) {
552 qWarning("QSslCertificate::fromDevice: cannot read from a null device");
553 return QList<QSslCertificate>();
554 }
555 return fromData(device->readAll(), format);
556}
557
558/*!
559 Searches for and parses all certificates in \a data that are
560 encoded in the specified \a format and returns them in a list of
561 certificates.
562
563 \sa fromDevice()
564*/
565QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::EncodingFormat format)
566{
567 return (format == QSsl::Pem)
568 ? QSslCertificatePrivate::certificatesFromPem(data)
569 : QSslCertificatePrivate::certificatesFromDer(data);
570}
571
572void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
573{
574 if (!data.isEmpty()) {
575 QList<QSslCertificate> certs = (format == QSsl::Pem)
576 ? certificatesFromPem(data, 1)
577 : certificatesFromDer(data, 1);
578 if (!certs.isEmpty()) {
579 *this = *certs.first().d;
580 if (x509)
581 x509 = q_X509_dup(x509);
582 }
583 }
584}
585
586#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
587#define ENDCERTSTRING "-----END CERTIFICATE-----"
588
589// ### refactor against QSsl::pemFromDer() etc. (to avoid redundant implementations)
590QByteArray QSslCertificatePrivate::QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format)
591{
592 if (!x509) {
593 qWarning("QSslSocketBackendPrivate::X509_to_QByteArray: null X509");
594 return QByteArray();
595 }
596
597 // Use i2d_X509 to convert the X509 to an array.
598 int length = q_i2d_X509(x509, 0);
599 QByteArray array;
600 array.resize(length);
601 char *data = array.data();
602 char **dataP = &data;
603 unsigned char **dataPu = (unsigned char **)dataP;
604 if (q_i2d_X509(x509, dataPu) < 0)
605 return QByteArray();
606
607 if (format == QSsl::Der)
608 return array;
609
610 // Convert to Base64 - wrap at 64 characters.
611 array = array.toBase64();
612 QByteArray tmp;
613 for (int i = 0; i < array.size() - 64; i += 64) {
614 tmp += QByteArray::fromRawData(array.data() + i, 64);
615 tmp += "\n";
616 }
617 if (int remainder = array.size() % 64) {
618 tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
619 tmp += "\n";
620 }
621
622 return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
623}
624
625static QMap<QString, QString> _q_mapFromOnelineName(char *name)
626{
627 QMap<QString, QString> info;
628 QString infoStr = QString::fromLocal8Bit(name);
629 q_CRYPTO_free(name);
630
631 // ### The right-hand encoding seems to allow hex (Regulierungsbeh\xC8orde)
632 //entry.replace(QLatin1String("\\x"), QLatin1String("%"));
633 //entry = QUrl::fromPercentEncoding(entry.toLatin1());
634 // ### See RFC-4630 for more details!
635
636 QRegExp rx(QLatin1String("/([A-Za-z]+)=(.+)"));
637
638 int pos = 0;
639 while ((pos = rx.indexIn(infoStr, pos)) != -1) {
640 const QString name = rx.cap(1);
641
642 QString value = rx.cap(2);
643 const int valuePos = rx.pos(2);
644
645 const int next = rx.indexIn(value);
646 if (next == -1) {
647 info.insert(name, value);
648 break;
649 }
650
651 value = value.left(next);
652 info.insert(name, value);
653 pos = valuePos + value.length();
654 }
655
656 return info;
657}
658
659QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509)
660{
661 QSslCertificate certificate;
662 if (!x509 || !QSslSocket::supportsSsl())
663 return certificate;
664
665 certificate.d->issuerInfo =
666 _q_mapFromOnelineName(q_X509_NAME_oneline(q_X509_get_issuer_name(x509), 0, 0));
667 certificate.d->subjectInfo =
668 _q_mapFromOnelineName(q_X509_NAME_oneline(q_X509_get_subject_name(x509), 0, 0));
669
670 ASN1_TIME *nbef = q_X509_get_notBefore(x509);
671 ASN1_TIME *naft = q_X509_get_notAfter(x509);
672 certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
673 certificate.d->notValidAfter = q_getTimeFromASN1(naft);
674 certificate.d->null = false;
675 certificate.d->x509 = q_X509_dup(x509);
676
677 return certificate;
678}
679
680static bool matchLineFeed(const QByteArray &pem, int *offset)
681{
682 char ch = pem.at(*offset);
683
684 // ignore extra whitespace at the end of the line
685 while (ch == ' ' && *offset < pem.size())
686 ch = pem.at(++*offset);
687
688 if (ch == '\n') {
689 *offset++;
690 return true;
691 }
692 if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
693 *offset += 2;
694 return true;
695 }
696 return false;
697}
698
699QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
700{
701 QList<QSslCertificate> certificates;
702 QSslSocketPrivate::ensureInitialized();
703
704 int offset = 0;
705 while (count == -1 || certificates.size() < count) {
706 int startPos = pem.indexOf(BEGINCERTSTRING, offset);
707 if (startPos == -1)
708 break;
709 startPos += sizeof(BEGINCERTSTRING) - 1;
710 if (!matchLineFeed(pem, &startPos))
711 break;
712
713 int endPos = pem.indexOf(ENDCERTSTRING, startPos);
714 if (endPos == -1)
715 break;
716
717 offset = endPos + sizeof(ENDCERTSTRING) - 1;
718 if (!matchLineFeed(pem, &offset))
719 break;
720
721 QByteArray decoded = QByteArray::fromBase64(
722 QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
723#if OPENSSL_VERSION_NUMBER >= 0x00908000L
724 const unsigned char *data = (const unsigned char *)decoded.data();
725#else
726 unsigned char *data = (unsigned char *)decoded.data();
727#endif
728
729 if (X509 *x509 = q_d2i_X509(0, &data, decoded.size())) {
730 certificates << QSslCertificate_from_X509(x509);
731 q_X509_free(x509);
732 }
733 }
734
735 return certificates;
736}
737
738QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
739{
740 QList<QSslCertificate> certificates;
741 QSslSocketPrivate::ensureInitialized();
742
743
744#if OPENSSL_VERSION_NUMBER >= 0x00908000L
745 const unsigned char *data = (const unsigned char *)der.data();
746#else
747 unsigned char *data = (unsigned char *)der.data();
748#endif
749 int size = der.size();
750
751 while (count == -1 || certificates.size() < count) {
752 if (X509 *x509 = q_d2i_X509(0, &data, size)) {
753 certificates << QSslCertificate_from_X509(x509);
754 q_X509_free(x509);
755 } else {
756 break;
757 }
758 size -= ((char *)data - der.data());
759 }
760
761 return certificates;
762}
763
764#ifndef QT_NO_DEBUG_STREAM
765QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
766{
767 debug << "QSslCertificate("
768 << certificate.version()
769 << "," << certificate.serialNumber()
770 << "," << certificate.digest().toBase64()
771 << "," << certificate.issuerInfo(QSslCertificate::Organization)
772 << "," << certificate.subjectInfo(QSslCertificate::Organization)
773 << "," << certificate.alternateSubjectNames()
774#ifndef QT_NO_TEXTSTREAM
775 << "," << certificate.effectiveDate()
776 << "," << certificate.expiryDate()
777#endif
778 << ")";
779 return debug;
780}
781QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info)
782{
783 switch (info) {
784 case QSslCertificate::Organization: debug << "Organization"; break;
785 case QSslCertificate::CommonName: debug << "CommonName"; break;
786 case QSslCertificate::CountryName: debug << "CountryName"; break;
787 case QSslCertificate::LocalityName: debug << "LocalityName"; break;
788 case QSslCertificate::OrganizationalUnitName: debug << "OrganizationalUnitName"; break;
789 case QSslCertificate::StateOrProvinceName: debug << "StateOrProvinceName"; break;
790 }
791 return debug;
792}
793#endif
794
795QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.