Qt 4.8
qsslkey.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 
62 #include "qsslkey.h"
63 #include "qsslkey_p.h"
64 #include "qsslsocket.h"
65 #include "qsslsocket_p.h"
66 
67 #include <QtCore/qatomic.h>
68 #include <QtCore/qbytearray.h>
69 #include <QtCore/qiodevice.h>
70 #ifndef QT_NO_DEBUG_STREAM
71 #include <QtCore/qdebug.h>
72 
74 #endif
75 
76 
80 void QSslKeyPrivate::clear(bool deep)
81 {
82  isNull = true;
84  return;
85  if (rsa) {
86  if (deep)
87  q_RSA_free(rsa);
88  rsa = 0;
89  }
90  if (dsa) {
91  if (deep)
92  q_DSA_free(dsa);
93  dsa = 0;
94  }
95 }
96 
113 void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
114  bool deepClear)
115 {
116  if (pem.isEmpty())
117  return;
118 
119  clear(deepClear);
120 
122  return;
123 
124  BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
125  if (!bio)
126  return;
127 
128  void *phrase = (void *)passPhrase.constData();
129 
130  if (algorithm == QSsl::Rsa) {
131  RSA *result = (type == QSsl::PublicKey)
132  ? q_PEM_read_bio_RSA_PUBKEY(bio, &rsa, 0, phrase)
133  : q_PEM_read_bio_RSAPrivateKey(bio, &rsa, 0, phrase);
134  if (rsa && rsa == result)
135  isNull = false;
136  } else {
137  DSA *result = (type == QSsl::PublicKey)
138  ? q_PEM_read_bio_DSA_PUBKEY(bio, &dsa, 0, phrase)
139  : q_PEM_read_bio_DSAPrivateKey(bio, &dsa, 0, phrase);
140  if (dsa && dsa == result)
141  isNull = false;
142  }
143 
144  q_BIO_free(bio);
145 }
146 
153  : d(new QSslKeyPrivate)
154 {
155 }
156 
161 {
162  // ### use QByteArray::fromRawData() instead
163  if (type == QSsl::PublicKey)
164  return QByteArray("-----BEGIN PUBLIC KEY-----\n");
165  else if (algorithm == QSsl::Rsa)
166  return QByteArray("-----BEGIN RSA PRIVATE KEY-----\n");
167  return QByteArray("-----BEGIN DSA PRIVATE KEY-----\n");
168 }
169 
174 {
175  // ### use QByteArray::fromRawData() instead
176  if (type == QSsl::PublicKey)
177  return QByteArray("-----END PUBLIC KEY-----\n");
178  else if (algorithm == QSsl::Rsa)
179  return QByteArray("-----END RSA PRIVATE KEY-----\n");
180  return QByteArray("-----END DSA PRIVATE KEY-----\n");
181 }
182 
192 {
193  QByteArray pem(der.toBase64());
194 
195  const int lineWidth = 64; // RFC 1421
196  const int newLines = pem.size() / lineWidth;
197  const bool rem = pem.size() % lineWidth;
198 
199  // ### optimize
200  for (int i = 0; i < newLines; ++i)
201  pem.insert((i + 1) * lineWidth + i, '\n');
202  if (rem)
203  pem.append('\n'); // ###
204 
205  pem.prepend(pemHeader());
206  pem.append(pemFooter());
207 
208  return pem;
209 }
210 
220 {
221  const QByteArray header = pemHeader();
222  const QByteArray footer = pemFooter();
223 
224  QByteArray der(pem);
225 
226  const int headerIndex = der.indexOf(header);
227  const int footerIndex = der.indexOf(footer);
228  if (headerIndex == -1 || footerIndex == -1)
229  return QByteArray();
230 
231  der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
232 
233  return QByteArray::fromBase64(der); // ignores newlines
234 }
235 
246  QSsl::EncodingFormat encoding, QSsl::KeyType type, const QByteArray &passPhrase)
247  : d(new QSslKeyPrivate)
248 {
249  d->type = type;
250  d->algorithm = algorithm;
251  d->decodePem((encoding == QSsl::Der)
252  ? d->pemFromDer(encoded) : encoded,
253  passPhrase);
254 }
255 
266  QSsl::KeyType type, const QByteArray &passPhrase)
267  : d(new QSslKeyPrivate)
268 {
269  QByteArray encoded;
270  if (device)
271  encoded = device->readAll();
272  d->type = type;
273  d->algorithm = algorithm;
274  d->decodePem((encoding == QSsl::Der) ?
275  d->pemFromDer(encoded) : encoded,
276  passPhrase);
277 }
278 
282 QSslKey::QSslKey(const QSslKey &other) : d(other.d)
283 {
284 }
285 
290 {
291 }
292 
300 {
301  d = other.d;
302  return *this;
303 }
304 
310 bool QSslKey::isNull() const
311 {
312  return d->isNull;
313 }
314 
321 {
322  d = new QSslKeyPrivate;
323 }
324 
328 int QSslKey::length() const
329 {
330  if (d->isNull)
331  return -1;
332  return (d->algorithm == QSsl::Rsa)
333  ? q_BN_num_bits(d->rsa->n) : q_BN_num_bits(d->dsa->p);
334 }
335 
340 {
341  return d->type;
342 }
343 
348 {
349  return d->algorithm;
350 }
351 
357 // ### autotest failure for non-empty passPhrase and private key
358 QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
359 {
360  if (d->isNull)
361  return QByteArray();
362  return d->derFromPem(toPem(passPhrase));
363 }
364 
370 QByteArray QSslKey::toPem(const QByteArray &passPhrase) const
371 {
372  if (!QSslSocket::supportsSsl() || d->isNull)
373  return QByteArray();
374 
375  BIO *bio = q_BIO_new(q_BIO_s_mem());
376  if (!bio)
377  return QByteArray();
378 
379  bool fail = false;
380 
381  if (d->algorithm == QSsl::Rsa) {
382  if (d->type == QSsl::PublicKey) {
383  if (!q_PEM_write_bio_RSA_PUBKEY(bio, d->rsa))
384  fail = true;
385  } else {
387  bio, d->rsa,
388  // ### the cipher should be selectable in the API:
389  passPhrase.isEmpty() ? (const EVP_CIPHER *)0 : q_EVP_des_ede3_cbc(),
390  (uchar *)passPhrase.data(), passPhrase.size(), 0, 0)) {
391  fail = true;
392  }
393  }
394  } else {
395  if (d->type == QSsl::PublicKey) {
396  if (!q_PEM_write_bio_DSA_PUBKEY(bio, d->dsa))
397  fail = true;
398  } else {
400  bio, d->dsa,
401  // ### the cipher should be selectable in the API:
402  passPhrase.isEmpty() ? (const EVP_CIPHER *)0 : q_EVP_des_ede3_cbc(),
403  (uchar *)passPhrase.data(), passPhrase.size(), 0, 0)) {
404  fail = true;
405  }
406  }
407  }
408 
409  QByteArray pem;
410  if (!fail) {
411  char *data;
412  long size = q_BIO_get_mem_data(bio, &data);
413  pem = QByteArray(data, size);
414  }
415  q_BIO_free(bio);
416  return pem;
417 }
418 
431 {
432  return (d->algorithm == QSsl::Rsa) ? Qt::HANDLE(d->rsa) : Qt::HANDLE(d->dsa);
433 }
434 
438 bool QSslKey::operator==(const QSslKey &other) const
439 {
440  if (isNull())
441  return other.isNull();
442  if (other.isNull())
443  return isNull();
444  if (algorithm() != other.algorithm())
445  return false;
446  if (type() != other.type())
447  return false;
448  if (length() != other.length())
449  return false;
450  return toDer() == other.toDer();
451 }
452 
462 #ifndef QT_NO_DEBUG_STREAM
463 class QDebug;
465 {
466  debug << "QSslKey("
467  << (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey")
468  << ", " << (key.algorithm() == QSsl::Rsa ? "RSA" : "DSA")
469  << ", " << key.length()
470  << ')';
471  return debug;
472 }
473 #endif
474 
QByteArray pemFromDer(const QByteArray &der) const
Returns a DER key formatted as PEM.
Definition: qsslkey.cpp:191
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:62
double d
Definition: qnumeric_p.h:62
QSsl::KeyAlgorithm algorithm() const
Returns the key algorithm.
Definition: qsslkey.cpp:347
The QSslKey class provides an interface for private and public keys.
Definition: qsslkey.h:64
QExplicitlySharedDataPointer< QSslKeyPrivate > d
Definition: qsslkey.h:96
BIO_METHOD * q_BIO_s_mem()
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QByteArray toPem(const QByteArray &passPhrase=QByteArray()) const
Returns the key in PEM encoding.
Definition: qsslkey.cpp:370
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
QSsl::KeyType type
Definition: qsslkey_p.h:87
Qt::HANDLE handle() const
Returns a pointer to the native key handle, if it is available; otherwise a null pointer is returned...
Definition: qsslkey.cpp:430
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
int q_PEM_write_bio_RSAPrivateKey(BIO *a, RSA *b, const EVP_CIPHER *c, unsigned char *d, int e, pem_password_cb *f, void *g)
Definition: qssl.h:67
QByteArray toDer(const QByteArray &passPhrase=QByteArray()) const
Returns the key in DER encoding.
Definition: qsslkey.cpp:358
QSsl::KeyAlgorithm algorithm
Definition: qsslkey_p.h:88
DSA * q_PEM_read_bio_DSAPrivateKey(BIO *a, DSA **b, pem_password_cb *c, void *d)
int q_BN_num_bits(const BIGNUM *a)
static bool supportsSsl()
Returns true if this platform supports SSL; otherwise, returns false.
QSslKey()
Constructs a null key.
Definition: qsslkey.cpp:152
RSA * q_PEM_read_bio_RSA_PUBKEY(BIO *a, RSA **b, pem_password_cb *c, void *d)
unsigned char uchar
Definition: qglobal.h:994
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
BIO * q_BIO_new(BIO_METHOD *a)
QByteArray derFromPem(const QByteArray &pem) const
Returns a PEM key formatted as DER.
Definition: qsslkey.cpp:219
void decodePem(const QByteArray &pem, const QByteArray &passPhrase, bool deepClear=true)
Allocates a new rsa or dsa struct and decodes pem into it according to the current algorithm and type...
Definition: qsslkey.cpp:113
QByteArray pemFooter() const
Definition: qsslkey.cpp:173
RSA * q_PEM_read_bio_RSAPrivateKey(BIO *a, RSA **b, pem_password_cb *c, void *d)
static const char * data(const QByteArray &arr)
int q_BIO_free(BIO *a)
void * HANDLE
Definition: qnamespace.h:1671
int q_PEM_write_bio_DSA_PUBKEY(BIO *a, DSA *b)
QByteArray mid(int index, int len=-1) const
Returns a byte array containing len bytes from this byte array, starting at position pos...
int indexOf(char c, int from=0) const
Returns the index position of the first occurrence of the character ch in the byte array...
int q_PEM_write_bio_RSA_PUBKEY(BIO *a, RSA *b)
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
static QByteArray fromBase64(const QByteArray &base64)
Returns a decoded copy of the Base64 array base64.
void clear()
Clears the contents of this key, making it a null key.
Definition: qsslkey.cpp:320
EncodingFormat
Describes supported encoding formats for certificates and keys.
Definition: qssl.h:61
DSA * q_PEM_read_bio_DSA_PUBKEY(BIO *a, DSA **b, pem_password_cb *c, void *d)
void clear(bool deep=true)
Definition: qsslkey.cpp:80
int key
QDebug operator<<(QDebug debug, const QSslKey &key)
Definition: qsslkey.cpp:464
BIO * q_BIO_new_mem_buf(void *a, int b)
QByteArray toBase64() const
Returns a copy of the byte array, encoded as Base64.
QByteArray readAll()
Reads all available data from the device, and returns it as a QByteArray.
Definition: qiodevice.cpp:1025
Definition: qssl.h:63
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
QByteArray pemHeader() const
Definition: qsslkey.cpp:160
~QSslKey()
Destroys the QSslKey object.
Definition: qsslkey.cpp:289
QSslKey & operator=(const QSslKey &other)
Copies the contents of other into this key, making the two keys identical.
Definition: qsslkey.cpp:299
bool isNull() const
Returns true if this is a null key; otherwise false.
Definition: qsslkey.cpp:310
KeyAlgorithm
Describes the different key algorithms supported by QSslKey.
Definition: qssl.h:66
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
KeyType
Describes the two types of keys QSslKey supports.
Definition: qssl.h:56
int q_PEM_write_bio_DSAPrivateKey(BIO *a, DSA *b, const EVP_CIPHER *c, unsigned char *d, int e, pem_password_cb *f, void *g)
const EVP_CIPHER * q_EVP_des_ede3_cbc()
int length() const
Returns the length of the key in bits, or -1 if the key is null.
Definition: qsslkey.cpp:328
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
#define q_BIO_get_mem_data(b, pp)
bool operator==(const QSslKey &key) const
Returns true if this key is equal to other; otherwise returns false.
Definition: qsslkey.cpp:438
void q_DSA_free(DSA *a)
QSsl::KeyType type() const
Returns the type of the key (i.e., PublicKey or PrivateKey).
Definition: qsslkey.cpp:339
void q_RSA_free(RSA *a)