1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-07-31 19:30:21 +02:00

Merge pull request #236 from tomahawk-player/qt-certificate-addon

Qt certificate addon
This commit is contained in:
Uwe L. Korn
2014-06-27 15:51:24 +02:00
63 changed files with 3713 additions and 12 deletions

View File

@@ -257,10 +257,17 @@ macro_log_feature(Boost_FOUND "Boost" "Provides free peer-reviewed portable C++
macro_optional_find_package(Sparsehash)
macro_log_feature(SPARSEHASH_FOUND "Sparsehash"
"https://code.google.com/p/sparsehash/" "" TRUE ""
"An extremely memory-efficient hash_map implementation."
"https://code.google.com/p/sparsehash/" TRUE ""
"Sparsehash is needed for reading metadata of mediastreams and fast
forward/backward seeking in HTTP streams")
macro_optional_find_package(GnuTLS)
macro_log_feature(GNUTLS_FOUND "GnuTLS"
"GnuTLS is a secure communications library implementing the SSL, TLS and DTLS protocols and technologies around them."
"http://gnutls.org/" TRUE ""
"GnuTLS is needed for serving the Playdar/HTTP API via TLS")
macro_optional_find_package(QCA2)
macro_log_feature(QCA2_FOUND "QCA2" "Provides encryption and signing functions necessary for some resolvers and accounts" "http://delta.affinix.com/qca/" TRUE "" "")

View File

@@ -31,7 +31,7 @@ Version 0.8.0:
* Support additional headers in CustomUrlHandler
* Fuzzy search indices for JS Resolvers
* Add metadata retrieval of HTTP(S) streams in JavaScript resolvers
* New Dependency: google-sparsehash
* New Dependencies: google-sparsehash, GnuTLS
Version 0.7.0:
* JavaScript Resolvers can now expose collections.

View File

@@ -11,12 +11,18 @@ list(APPEND ${TOMAHAWK_PLAYDARAPI_LIBRARY_TARGET}_SOURCES
list(APPEND ${TOMAHAWK_PLAYDARAPI_LIBRARY_TARGET}_UI
)
include_directories(${QXTWEB_INCLUDE_DIRS})
include_directories(
${QXTWEB_INCLUDE_DIRS}
${THIRDPARTY_DIR}/qt-certificate-addon/src/
)
tomahawk_add_library(${TOMAHAWK_PLAYDARAPI_LIBRARY_TARGET}
SOURCES ${${TOMAHAWK_PLAYDARAPI_LIBRARY_TARGET}_SOURCES}
UI ${${TOMAHAWK_PLAYDARAPI_LIBRARY_TARGET}_UI}
LINK_PRIVATE_LIBRARIES ${QXTWEB_LIBRARIES}
LINK_PRIVATE_LIBRARIES
${QXTWEB_LIBRARIES}
qtcertificateaddon
${GNUTLS_LIBRARIES}
EXPORT TomahawkLibraryDepends
VERSION ${TOMAHAWK_VERSION_SHORT}
)

View File

@@ -18,9 +18,19 @@
#include "PlaydarApi_p.h"
#include "qxtsslserver.h"
#include "TomahawkSettings.h"
#include "Typedefs.h"
#include "certificate/certificatebuilder.h"
#include "certificate/certificaterequestbuilder.h"
#include "certificate/keybuilder.h"
#include "utils/Logger.h"
PlaydarApi::PlaydarApi( QHostAddress ha, qint16 port, QObject* parent )
using namespace QtAddOn::Certificate;
PlaydarApi::PlaydarApi( QHostAddress ha, qint16 port, qint16 sport, QObject* parent )
: QObject( parent )
, d_ptr( new PlaydarApiPrivate( this ) )
{
@@ -28,6 +38,7 @@ PlaydarApi::PlaydarApi( QHostAddress ha, qint16 port, QObject* parent )
d->ha = ha;
d->port = port;
d->sport = sport;
}
@@ -48,12 +59,19 @@ PlaydarApi::start()
d->session.reset( new QxtHttpSessionManager() );
d->connector.reset( new QxtHttpServerConnector() );
if ( d->session.isNull() || d->connector.isNull() )
d->tlsSession.reset( new QxtHttpSessionManager() );
d->tlsConnector.reset( new QxtHttpsServerConnector() );
if ( d->session.isNull() || d->connector.isNull()
|| d->tlsSession.isNull() || d->tlsConnector.isNull() )
{
if ( !d->session.isNull() )
delete d->session.data();
d->session.reset();
if ( !d->connector.isNull() )
delete d->connector.data();
d->connector.reset();
if ( !d->tlsSession.isNull() )
d->tlsSession.reset();
if ( !d->tlsConnector.isNull() )
d->tlsConnector.reset();
tLog() << "Failed to start HTTPd, could not create object";
return;
}
@@ -67,4 +85,68 @@ PlaydarApi::start()
tLog() << "Starting HTTPd on" << d->session->listenInterface().toString() << d->session->port();
d->session->start();
d->tlsSession->setListenInterface( d->ha );
d->tlsSession->setPort( d->sport );
d->tlsSession->setConnector( d->tlsConnector.data() );
d->tlsInstance.reset( new Api_v1( d->tlsSession.data() ) );
d->tlsSession->setStaticContentService( d->tlsInstance.data() );
QByteArray settingsKey = TomahawkSettings::instance()->playdarKey();
QSslKey key;
if ( settingsKey.isNull() || settingsKey.isEmpty() )
{
// Generate a SSL key
key = KeyBuilder::generate( QSsl::Rsa, KeyBuilder::StrengthNormal );
TomahawkSettings::instance()->setPlaydarKey( key.toPem() );
}
else
{
// Restore key
key = QSslKey( settingsKey, QSsl::Rsa );
}
QByteArray settingsCert = TomahawkSettings::instance()->playdarCertificate();
QSslCertificate cert;
if ( settingsCert.isNull() || settingsCert.isEmpty() )
{
// Generate a SSL certificate
CertificateRequestBuilder reqbuilder;
reqbuilder.setVersion( 1 );
reqbuilder.setKey( key );
reqbuilder.addNameEntry( Certificate::EntryCountryName, "GB" );
reqbuilder.addNameEntry( Certificate::EntryOrganizationName, "Tomahawk Player (Desktop)" );
reqbuilder.addNameEntry( Certificate::EntryCommonName, "localhost" );
// Sign the request
CertificateRequest req = reqbuilder.signedRequest(key);
// Now make a certificate
CertificateBuilder builder;
builder.setRequest( req );
builder.setVersion( 3 );
builder.setSerial( uuid().toLatin1() );
builder.setActivationTime( QDateTime::currentDateTimeUtc());
builder.setExpirationTime( QDateTime::currentDateTimeUtc().addYears( 10 ) );
builder.setBasicConstraints( false );
builder.addKeyPurpose( CertificateBuilder::PurposeWebServer );
builder.setKeyUsage( CertificateBuilder::UsageKeyAgreement|CertificateBuilder::UsageKeyEncipherment );
builder.addSubjectKeyIdentifier();
cert = builder.signedCertificate( key );
TomahawkSettings::instance()->setPlaydarCertificate( cert.toPem() );
}
else
{
cert = QSslCertificate( settingsCert );
}
QxtSslServer* sslServer = d->tlsConnector->tcpServer();
sslServer->setPrivateKey( key );
sslServer->setLocalCertificate( cert );
tLog() << "Starting HTTPSd on" << d->tlsSession->listenInterface().toString() << d->tlsSession->port();
tLog() << Q_FUNC_INFO << d->tlsSession->start();
}

View File

@@ -30,7 +30,14 @@ class TOMAHAWK_PLAYDARAPI_EXPORT PlaydarApi : public QObject
{
Q_OBJECT
public:
explicit PlaydarApi( QHostAddress ha, qint16 port, QObject *parent = 0 );
/**
* Creates a Playdar HTTP interface
* @param ha Address to listen on
* @param port Port to listen on with HTTP
* @param sport Pot to listen on with HTTPS
* @param parent
*/
explicit PlaydarApi( QHostAddress ha, qint16 port, qint16 sport, QObject *parent = 0 );
virtual ~PlaydarApi();
void start();

View File

@@ -38,8 +38,15 @@ private:
QScopedPointer< Api_v1 > instance;
QScopedPointer< QxtHttpServerConnector > connector;
QScopedPointer< QxtHttpSessionManager > session;
// TLS secured interface
QScopedPointer< Api_v1 > tlsInstance;
QScopedPointer< QxtHttpsServerConnector > tlsConnector;
QScopedPointer< QxtHttpSessionManager > tlsSession;
QHostAddress ha;
qint16 port;
qint16 sport;
};
#endif // PLAYDARAPI_P_H

View File

@@ -1643,3 +1643,31 @@ TomahawkSettings::removeAtticaResolverState ( const QString& resolver )
setValue( "script/atticaresolverstates", QVariant::fromValue< AtticaManager::StateHash >( resolvers ) );
}
QByteArray
TomahawkSettings::playdarCertificate() const
{
return value( "playdar/certificate").value< QByteArray >();
}
void
TomahawkSettings::setPlaydarCertificate( const QByteArray& cert )
{
setValue( "playdar/certificate", cert );
}
QByteArray
TomahawkSettings::playdarKey() const
{
return value( "playdar/key" ).value< QByteArray >();
}
void
TomahawkSettings::setPlaydarKey( const QByteArray& key )
{
setValue( "playdar/key", key );
}

View File

@@ -232,6 +232,13 @@ public:
void setAtticaResolverState( const QString& resolver, AtticaManager::ResolverState state );
void removeAtticaResolverState( const QString& resolver );
// Playdar TLS Certificate and Key.
// TODO: Store in Keychain
QByteArray playdarCertificate() const;
void setPlaydarCertificate( const QByteArray& cert );
QByteArray playdarKey() const;
void setPlaydarKey( const QByteArray& key );
signals:
void changed();

View File

@@ -492,14 +492,14 @@ TomahawkApp::initHTTP()
if ( TomahawkSettings::instance()->httpBindAll() )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
playdarApi = new PlaydarApi( QHostAddress::Any, 60210, this ); // TODO Auth
playdarApi = new PlaydarApi( QHostAddress::Any, 60210, 60211, this ); // TODO Auth
#else
playdarApi = new PlaydarApi( QHostAddress::AnyIPv6, 60210, this ); // TODO Auth
playdarApi = new PlaydarApi( QHostAddress::AnyIPv6, 60210, 60211, this ); // TODO Auth
#endif
}
else
{
playdarApi = new PlaydarApi( QHostAddress::LocalHost, 60210, this ); // TODO Config port
playdarApi = new PlaydarApi( QHostAddress::LocalHost, 60210, 60211, this ); // TODO Config port
}
playdarApi->start();
}

View File

@@ -1,5 +1,6 @@
ADD_SUBDIRECTORY( qxt )
ADD_SUBDIRECTORY( kdsingleapplicationguard )
ADD_SUBDIRECTORY( qt-certificate-addon )
IF( WITH_CRASHREPORTER )
ADD_SUBDIRECTORY( libcrashreporter-qt )
ENDIF()

View File

@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 2.6)
project(qtcertificateaddon)
add_subdirectory( src )

502
thirdparty/qt-certificate-addon/LICENSE vendored Normal file
View File

@@ -0,0 +1,502 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -0,0 +1,9 @@
Qt Certificate Addon
====================
This is the start of some work to create a nice Qt-style API for creating SSL
certificates. Unlike the QSsl classes in the QtNetwork module, it uses the
gnutls library, but it automatically converts between the two, for example a
created certificate is returned as a QSslCertificate.
Richard J. Moore, rich@kde.org

View File

@@ -0,0 +1,33 @@
project = Certificate
description = Certificate Documentation
sourcedirs = ../src ./src
headerdirs = ../src
exampledirs = ../examples
sources.fileextensions = "*.cpp *.qdoc"
headers.fileextensions = "*.h"
examples.fileextensions = "*.h *.cpp"
outputdir = html
outputformats = HTML
Cpp.ignoretokens = \
QT_BEGIN_NAMESPACE_CERTIFICATE \
QT_END_NAMESPACE_CERTIFICATE \
Q_ADDON_CERTIFICATE_EXPORT
HTML.nobreadcrumbs = "true"
HTML.templatedir = .
HTML.stylesheets = style/style.css
HTML.headerstyles = " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />\n"
HTML.endheader = "</head>\n"
HTML.postheader = \
" <div class=\"header\">\n" \
" <div id=\"nav-logo\">\n" \
" <a href=\"index.html\">Certificate Reference</a>" \
" </div>\n" \
" </div>\n"

View File

@@ -0,0 +1,8 @@
OTHER_FILES += $$PWD/certificate.qdocconf
docs_target.target = docs
docs_target.commands = qdoc3 $$PWD/certificate.qdocconf
QMAKE_EXTRA_TARGETS = docs_target
QMAKE_CLEAN += "-r $$PWD/html"

View File

@@ -0,0 +1,21 @@
// -*- c++ -*-
/*!
\module Certificate
\title Addon Certificate Reference Documentation
\page index.html
\brief The Certificate module provides facilities for creating X.509
certificates.
This is the start of some work to create a nice Qt-style API for creating SSL
certificates. Unlike the QSsl classes in the QtNetwork module, it uses the
gnutls library, but it automatically converts between the two, for example a
created certificate is returned as a QSslCertificate.
Richard J. Moore, rich@kde.org
\section1 C++ Classes
\generatelist annotatedclasses
*/

View File

@@ -0,0 +1,137 @@
a:link, a:visited {
color: #00732F;
text-decoration: none;
font-weight: bold;
}
body {
font: normal 400 14px/1.2 Arial;
margin-top: 85px;
}
h1 {
margin: 0;
}
h2 {
font: 500 20px/1.2 Arial;
}
h3.fn, span.fn {
-moz-border-radius: 7px 7px 7px 7px;
-webkit-border-radius: 7px 7px 7px 7px;
border-radius: 7px 7px 7px 7px;
background-color: #F6F6F6;
border-width: 1px;
border-style: solid;
border-color: #E6E6E6;
word-spacing: 3px;
padding: 3px 5px;
}
table, pre {
-moz-border-radius: 7px 7px 7px 7px;
-webkit-border-radius: 7px 7px 7px 7px;
border-radius: 7px 7px 7px 7px;
background-color: #F6F6F6;
border: 1px solid #E6E6E6;
border-collapse: separate;
font-size: 12px;
line-height: 1.2;
margin-bottom: 25px;
margin-left: 15px;
}
table td {
padding: 3px 15px 3px 20px;
}
table tr.even {
background-color: white;
color: #66666E;
}
table tr.odd {
background-color: #F6F6F6;
color: #66666E;
}
li {
margin-bottom: 10px;
padding-left: 12px;
}
.cpp {
display: block;
margin: 10;
overflow: hidden;
overflow-x: hidden;
overflow-y: hidden;
padding: 20px 0 20px 0;
}
.footer {
margin-top: 50px;
}
.memItemLeft {
padding-right: 3px;
}
.memItemRight {
padding: 3px 15px 3px 0;
}
.qml {
display: block;
margin: 10;
overflow: hidden;
overflow-x: hidden;
overflow-y: hidden;
padding: 20px 0 20px 0;
}
.qmldefault {
padding-left: 5px;
float: right;
color: red;
}
.qmlreadonly {
padding-left: 5px;
float: right;
color: #254117;
}
.rightAlign {
padding: 3px 5px 3px 10px;
text-align: right;
}
.title {
background-color: white;
color: #44A51C;
font-family: Verdana;
font-size: 35px;
font-weight: normal;
left: 0;
padding-bottom: 5px;
padding-left: 16px;
padding-top: 20px;
position: absolute;
right: 0;
top: 0;
}
.toc {
float: right;
-moz-border-radius: 7px 7px 7px 7px;
-webkit-border-radius: 7px 7px 7px 7px;
border-radius: 7px 7px 7px 7px;
background-color: #F6F6F6;
border: 1px solid #DDD;
margin: 0 20px 10px 10px;
padding: 20px 15px 20px 20px;
height: auto;
width: 200px;
}

View File

@@ -0,0 +1,2 @@
output.*
create_certificate

View File

@@ -0,0 +1,9 @@
TEMPLATE = app
TARGET = create_certificate
QT += network
LIBS += -Wl,-rpath,../../src/certificate -L../../src/certificate -lcertificate
INCLUDEPATH += ../../src/certificate
SOURCES = main.cpp

View File

@@ -0,0 +1,63 @@
#include <QByteArray>
#include <QFile>
#include <QDateTime>
#include <QSslKey>
#include <QSslCertificate>
#include "keybuilder.h"
#include "certificaterequestbuilder.h"
#include "certificaterequest.h"
#include "certificatebuilder.h"
#include "certificate.h"
QT_USE_NAMESPACE_CERTIFICATE
int main(int argc, char **argv)
{
QSslKey key = KeyBuilder::generate( QSsl::Rsa, KeyBuilder::StrengthNormal );
QFile k("output.key");
k.open(QIODevice::WriteOnly);
k.write(key.toPem());
k.close();
CertificateRequestBuilder reqbuilder;
reqbuilder.setVersion(1);
reqbuilder.setKey(key);
reqbuilder.addNameEntry(Certificate::EntryCountryName, "GB");
reqbuilder.addNameEntry(Certificate::EntryOrganizationName, "Westpoint");
reqbuilder.addNameEntry(Certificate::EntryOrganizationName, "West");
reqbuilder.addNameEntry(Certificate::EntryCommonName, "www.example.com");
// Sign the request
CertificateRequest req = reqbuilder.signedRequest(key);
//
// Export the results
//
QFile f("output.req");
f.open(QIODevice::WriteOnly);
f.write(req.toPem());
f.close();
//
// Now make a certificate
//
CertificateBuilder builder;
builder.setRequest(req);
builder.setVersion(3);
builder.setSerial("helloworld");
builder.setActivationTime(QDateTime::currentDateTimeUtc());
builder.setExpirationTime(QDateTime::currentDateTimeUtc());
builder.setBasicConstraints(true);
builder.setKeyUsage(CertificateBuilder::UsageCrlSign|CertificateBuilder::UsageKeyCertSign);
builder.addSubjectKeyIdentifier();
QSslCertificate cert = builder.signedCertificate(key);
QFile c("output.crt");
c.open(QIODevice::WriteOnly);
c.write(cert.toPem());
c.close();
}

View File

@@ -0,0 +1,9 @@
TEMPLATE = app
TARGET = create_certificate_chain
QT += network
LIBS += -Wl,-rpath,../../src/certificate -L../../src/certificate -lcertificate
INCLUDEPATH += ../../src/certificate
SOURCES = main.cpp

View File

@@ -0,0 +1,141 @@
#include <QByteArray>
#include <QFile>
#include <QDateTime>
#include <QDebug>
#include <QSslKey>
#include <QSslCertificate>
#include "keybuilder.h"
#include "certificaterequestbuilder.h"
#include "certificaterequest.h"
#include "certificatebuilder.h"
#include "randomgenerator.h"
#include "certificate.h"
QT_USE_NAMESPACE_CERTIFICATE
void save_key(const QString &filename, const QSslKey &key)
{
QFile k(filename);
k.open(QIODevice::WriteOnly);
k.write(key.toPem());
k.close();
}
void save_request(const QString &filename, CertificateRequest &req)
{
QFile k(filename);
k.open(QIODevice::WriteOnly);
k.write(req.toPem());
k.close();
}
void save_certificate(const QString &filename, const QSslCertificate &crt)
{
QFile k(filename);
k.open(QIODevice::WriteOnly);
k.write(crt.toPem());
k.close();
}
int main(int argc, char **argv)
{
//
// Create the CA key
//
QSslKey cakey = KeyBuilder::generate(QSsl::Rsa, KeyBuilder::StrengthNormal);
save_key("ca.key", cakey);
CertificateRequestBuilder careqbuilder;
careqbuilder.setVersion(1);
careqbuilder.setKey(cakey);
careqbuilder.addNameEntry(Certificate::EntryCountryName, "GB");
careqbuilder.addNameEntry(Certificate::EntryOrganizationName, "Westpoint CA Key");
careqbuilder.addNameEntry(Certificate::EntryOrganizationName, "Westpoint");
// Sign the request
CertificateRequest careq = careqbuilder.signedRequest(cakey);
save_request("ca.req", careq);
//
// Now make a certificate
//
CertificateBuilder cabuilder;
cabuilder.setRequest(careq);
cabuilder.setVersion(3);
cabuilder.setSerial(RandomGenerator::getPositiveBytes(16));
cabuilder.setActivationTime(QDateTime::currentDateTimeUtc());
cabuilder.setExpirationTime(QDateTime::currentDateTimeUtc().addYears(10));
cabuilder.setBasicConstraints(true);
cabuilder.setKeyUsage(CertificateBuilder::UsageCrlSign|CertificateBuilder::UsageKeyCertSign);
cabuilder.addSubjectKeyIdentifier();
QSslCertificate cacert = cabuilder.signedCertificate(cakey);
save_certificate("ca.crt", cacert);
//
// Now make an intermediate
//
QSslKey interkey = KeyBuilder::generate(QSsl::Rsa, KeyBuilder::StrengthNormal);
save_key("inter.key", interkey);
CertificateRequestBuilder interreqbuilder;
interreqbuilder.setVersion(1);
interreqbuilder.setKey(interkey);
interreqbuilder.addNameEntry(Certificate::EntryCountryName, "GB");
interreqbuilder.addNameEntry(Certificate::EntryOrganizationName, "Westpoint Intermediate Key");
CertificateRequest interreq = interreqbuilder.signedRequest(interkey);
save_request("inter.req", interreq);
CertificateBuilder interbuilder;
interbuilder.setRequest(interreq);
interbuilder.setVersion(3);
interbuilder.setSerial(RandomGenerator::getPositiveBytes(16));
interbuilder.setActivationTime(QDateTime::currentDateTimeUtc());
interbuilder.setExpirationTime(QDateTime::currentDateTimeUtc().addYears(10));
interbuilder.copyRequestExtensions(interreq);
interbuilder.setBasicConstraints(true);
interbuilder.setKeyUsage(CertificateBuilder::UsageCrlSign|CertificateBuilder::UsageKeyCertSign);
interbuilder.addSubjectKeyIdentifier();
interbuilder.addAuthorityKeyIdentifier(cacert);
QSslCertificate intercert = interbuilder.signedCertificate(cacert, cakey);
save_certificate("inter.crt", intercert);
//
// Create the leaf
//
QSslKey leafkey = KeyBuilder::generate(QSsl::Rsa, KeyBuilder::StrengthNormal);
save_key("leaf.key", leafkey);
CertificateRequestBuilder leafreqbuilder;
leafreqbuilder.setVersion(1);
leafreqbuilder.setKey(leafkey);
leafreqbuilder.addNameEntry(Certificate::EntryCountryName, "GB");
leafreqbuilder.addNameEntry(Certificate::EntryOrganizationName, "Westpoint");
leafreqbuilder.addNameEntry(Certificate::EntryCommonName, "127.0.0.1");
leafreqbuilder.addSubjectAlternativeNameEntry(QSsl::DnsEntry, "127.0.0.1");
CertificateRequest leafreq = leafreqbuilder.signedRequest(leafkey);
save_request("leaf.req", leafreq);
CertificateBuilder leafbuilder;
leafbuilder.setRequest(leafreq);
leafbuilder.setVersion(3);
leafbuilder.setSerial(RandomGenerator::getPositiveBytes(16));
leafbuilder.setActivationTime(QDateTime::currentDateTimeUtc());
leafbuilder.setExpirationTime(QDateTime::currentDateTimeUtc().addYears(10));
leafbuilder.copyRequestExtensions(leafreq);
leafbuilder.setBasicConstraints(false);
leafbuilder.addKeyPurpose(CertificateBuilder::PurposeWebServer);
leafbuilder.setKeyUsage(CertificateBuilder::UsageKeyAgreement|CertificateBuilder::UsageKeyEncipherment);
leafbuilder.addSubjectKeyIdentifier();
leafbuilder.addAuthorityKeyIdentifier(intercert);
QSslCertificate leafcert = leafbuilder.signedCertificate(intercert, interkey);
save_certificate("leaf.crt", leafcert);
}

View File

@@ -0,0 +1,4 @@
ca.*
leaf.*
create_signed_certificate

View File

@@ -0,0 +1,9 @@
TEMPLATE = app
TARGET = create_signed_certificate
QT += network
LIBS += -Wl,-rpath,../../src/certificate -L../../src/certificate -lcertificate
INCLUDEPATH += ../../src/certificate
SOURCES = main.cpp

View File

@@ -0,0 +1,111 @@
#include <QByteArray>
#include <QFile>
#include <QDateTime>
#include <QDebug>
#include <QSslKey>
#include <QSslCertificate>
#include "keybuilder.h"
#include "certificaterequestbuilder.h"
#include "certificaterequest.h"
#include "certificatebuilder.h"
#include "randomgenerator.h"
#include "certificate.h"
QT_USE_NAMESPACE_CERTIFICATE
void save_key(const QString &filename, const QSslKey &key)
{
QFile k(filename);
k.open(QIODevice::WriteOnly);
k.write(key.toPem());
k.close();
}
void save_request(const QString &filename, CertificateRequest &req)
{
QFile k(filename);
k.open(QIODevice::WriteOnly);
k.write(req.toPem());
k.close();
}
void save_certificate(const QString &filename, const QSslCertificate &crt)
{
QFile k(filename);
k.open(QIODevice::WriteOnly);
k.write(crt.toPem());
k.close();
}
int main(int argc, char **argv)
{
//
// Create the CA key
//
QSslKey cakey = KeyBuilder::generate(QSsl::Rsa, KeyBuilder::StrengthNormal);
save_key("ca.key", cakey);
CertificateRequestBuilder careqbuilder;
careqbuilder.setVersion(1);
careqbuilder.setKey(cakey);
careqbuilder.addNameEntry(Certificate::EntryCountryName, "GB");
careqbuilder.addNameEntry(Certificate::EntryOrganizationName, "Westpoint CA Key");
careqbuilder.addNameEntry(Certificate::EntryOrganizationName, "Westpoint");
// Sign the request
CertificateRequest careq = careqbuilder.signedRequest(cakey);
save_request("ca.req", careq);
//
// Now make a certificate
//
CertificateBuilder cabuilder;
cabuilder.setRequest(careq);
cabuilder.setVersion(3);
cabuilder.setSerial(RandomGenerator::getPositiveBytes(16));
cabuilder.setActivationTime(QDateTime::currentDateTimeUtc());
cabuilder.setExpirationTime(QDateTime::currentDateTimeUtc());
cabuilder.setBasicConstraints(true);
cabuilder.setKeyUsage(CertificateBuilder::UsageCrlSign|CertificateBuilder::UsageKeyCertSign);
cabuilder.addSubjectKeyIdentifier();
QSslCertificate cacert = cabuilder.signedCertificate(cakey);
save_certificate("ca.crt", cacert);
//
// Create the leaf
//
QSslKey leafkey = KeyBuilder::generate(QSsl::Rsa, KeyBuilder::StrengthNormal);
save_key("leaf.key", leafkey);
CertificateRequestBuilder leafreqbuilder;
leafreqbuilder.setVersion(1);
leafreqbuilder.setKey(leafkey);
leafreqbuilder.addNameEntry(Certificate::EntryCountryName, "GB");
leafreqbuilder.addNameEntry(Certificate::EntryOrganizationName, "Westpoint");
leafreqbuilder.addNameEntry(Certificate::EntryCommonName, "www.example.com");
leafreqbuilder.addSubjectAlternativeNameEntry(QSsl::DnsEntry, "www.example.com");
leafreqbuilder.addSubjectAlternativeNameEntry(QSsl::EmailEntry, "test@example.com");
CertificateRequest leafreq = leafreqbuilder.signedRequest(leafkey);
save_request("leaf.req", leafreq);
CertificateBuilder leafbuilder;
leafbuilder.setRequest(leafreq);
leafbuilder.setVersion(3);
leafbuilder.setSerial(RandomGenerator::getPositiveBytes(16));
leafbuilder.setActivationTime(QDateTime::currentDateTimeUtc());
leafbuilder.setExpirationTime(QDateTime::currentDateTimeUtc());
leafbuilder.copyRequestExtensions(leafreq);
leafbuilder.setBasicConstraints(false);
leafbuilder.addKeyPurpose(CertificateBuilder::PurposeWebServer);
leafbuilder.setKeyUsage(CertificateBuilder::UsageKeyAgreement|CertificateBuilder::UsageKeyEncipherment);
leafbuilder.addSubjectKeyIdentifier();
leafbuilder.addAuthorityKeyIdentifier(cacert);
QSslCertificate leafcert = leafbuilder.signedCertificate(cacert, cakey);
save_certificate("leaf.crt", leafcert);
}

View File

@@ -0,0 +1,8 @@
TEMPLATE = subdirs
SUBDIRS = create_certificate \
create_signed_certificate \
create_certificate_chain

View File

@@ -0,0 +1,9 @@
include(doc/doc.pri)
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS = src \
tests \
examples

View File

@@ -0,0 +1 @@
add_subdirectory( certificate )

View File

@@ -0,0 +1,26 @@
list(APPEND qtcertificateaddon_INCLUDE_DIRECTORIES
${QT_INCLUDES}
${QT_QTCORE_INCLUDE_DIR}
${QT_QTNETWORK_INCLUDE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
list(APPEND qtcertificateaddon_SOURCES
certificatebuilder.cpp
keybuilder.cpp
certificaterequestbuilder.cpp
randomgenerator.cpp
certificaterequest.cpp
utils.cpp
)
include_directories(${qtcertificateaddon_INCLUDE_DIRECTORIES})
add_library(qtcertificateaddon STATIC ${qtcertificateaddon_SOURCES})
set_target_properties(
qtcertificateaddon
PROPERTIES
AUTOMOC TRUE
)
qt5_use_modules(qtcertificateaddon Core Network)

View File

@@ -0,0 +1,59 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef CERTIFICATE_H
#define CERTIFICATE_H
QT_BEGIN_NAMESPACE_CERTIFICATE
namespace Certificate {
enum EntryType {
EntryCountryName,
EntryOrganizationName,
EntryOrganizationalUnitName,
EntryCommonName,
EntryLocalityName,
EntryStateOrProvinceName,
EntryEmail
};
};
QT_END_NAMESPACE_CERTIFICATE
#endif // CERTIFICATE_H

View File

@@ -0,0 +1,20 @@
QT += network
TEMPLATE = lib
TARGET = certificate
LIBS += -lgnutls
DEFINES += QT_CERTIFICATE_LIB
CONFIG += debug
# Input
SOURCES += certificatebuilder.cpp \
certificaterequestbuilder.cpp \
certificaterequest.cpp \
keybuilder.cpp \
utils.cpp \
randomgenerator.cpp

View File

@@ -0,0 +1,68 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef CERTIFICATE_GLOBAL_H
#define CERTIFICATE_GLOBAL_H
#include "qglobal.h"
#if defined(QT_CERTIFICATE_LIB)
# define Q_CERTIFICATE_EXPORT Q_DECL_EXPORT
#else
# define Q_CERTIFICATE_EXPORT Q_DECL_IMPORT
#endif
#if defined(QT_NAMESPACE)
# define QT_BEGIN_NAMESPACE_CERTIFICATE namespace QT_NAMESPACE { namespace QtAddOn { namespace Certificate {
# define QT_END_NAMESPACE_CERTIFICATE } } }
# define QT_USE_NAMESPACE_CERTIFICATE using namespace QT_NAMESPACE::QtAddOn::Certificate;
# define QT_PREPEND_NAMESPACE_CERTIFICATE(name) ::QT_NAMESPACE::QtAddOn::Certificate::name
#else
# define QT_BEGIN_NAMESPACE_CERTIFICATE namespace QtAddOn { namespace Certificate {
# define QT_END_NAMESPACE_CERTIFICATE } }
# define QT_USE_NAMESPACE_CERTIFICATE using namespace QtAddOn::Certificate;
# define QT_PREPEND_NAMESPACE_CERTIFICATE(name) ::QtAddOn::Certificate::name
#endif
// a workaround for moc - if there is a header file that doesn't use certificate
// namespace, we still force moc to do "using namespace" but the namespace have to
// be defined, so let's define an empty namespace here
QT_BEGIN_NAMESPACE_CERTIFICATE
QT_END_NAMESPACE_CERTIFICATE
#endif // CERTIFICATE_GLOBAL_H

View File

@@ -0,0 +1,379 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QDateTime>
#include <QSslKey>
extern "C" {
#include <gnutls/abstract.h>
};
#include "certificaterequest_p.h"
#include "utils_p.h"
#include "certificatebuilder_p.h"
QT_BEGIN_NAMESPACE_CERTIFICATE
/*!
\class CertificateBuilder
\brief The CertificateBuilder class is a tool for creating X.509 certificates.
*/
/*!
Creates a new CertificateBuilder.
*/
CertificateBuilder::CertificateBuilder()
: d(new CertificateBuilderPrivate)
{
ensure_gnutls_init();
d->errno = gnutls_x509_crt_init(&d->crt);
}
/*!
Cleans up a CertificateBuilder.
*/
CertificateBuilder::~CertificateBuilder()
{
gnutls_x509_crt_deinit(d->crt);
delete d;
}
/*!
Returns the last error that occurred when using this object. The values
used are those of gnutls. If there has not been an error then it is
guaranteed to be 0.
*/
int CertificateBuilder::error() const
{
return d->errno;
}
/*!
Returns a string describing the last error that occurred when using
this object.
*/
QString CertificateBuilder::errorString() const
{
return QString::fromUtf8(gnutls_strerror(d->errno));
}
/*!
Set the request that the certificate will be generated from.
*/
bool CertificateBuilder::setRequest(const CertificateRequest &crq)
{
d->errno = gnutls_x509_crt_set_crq(d->crt, crq.d->crq);
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Set the version of the X.509 certificate. In general the version will be 3.
*/
bool CertificateBuilder::setVersion(int version)
{
d->errno = gnutls_x509_crt_set_version(d->crt, version);
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Set the serial number of the certificate. This should be a random value
containing a large amount of entropy.
*/
bool CertificateBuilder::setSerial(const QByteArray &serial)
{
d->errno = gnutls_x509_crt_set_serial(d->crt, serial.constData(), serial.size());
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Set the time at which the certificate will become valid.
*/
bool CertificateBuilder::setActivationTime(const QDateTime &date)
{
d->errno = gnutls_x509_crt_set_activation_time(d->crt, date.toTime_t());
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Set the time after which the certificate is no longer valid.
*/
bool CertificateBuilder::setExpirationTime(const QDateTime &date)
{
d->errno = gnutls_x509_crt_set_expiration_time(d->crt, date.toTime_t());
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Copies the extensions from the request to the certificate being created. This
should only be done after checking that the request is safe, since otherwise
you could potentially copy extensions that grant the generated certificate
facilities you did not intend.
*/
bool CertificateBuilder::copyRequestExtensions(const CertificateRequest &crq)
{
d->errno = gnutls_x509_crt_set_crq_extensions(d->crt, crq.d->crq);
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Add the basic constraints extension. This allows you to specify if the
certificate being created is a CA (ie. may sign certificates), and the
maximum length of the chain that is allowed if you grant it that
permission. By default the pathLength is unlimited.
*/
bool CertificateBuilder::setBasicConstraints(bool ca, int pathLength)
{
d->errno = gnutls_x509_crt_set_basic_constraints (d->crt, ca, pathLength);
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Adds the specified purpose to the list of those this certificate may be
used for. This method may be called multiple times to add a series of
different purposes.
*/
bool CertificateBuilder::addKeyPurpose(KeyPurpose purpose, bool critical)
{
QByteArray ba;
switch(purpose) {
case PurposeWebServer:
ba = QByteArray(GNUTLS_KP_TLS_WWW_SERVER);
break;
case PurposeWebClient:
ba = QByteArray(GNUTLS_KP_TLS_WWW_CLIENT);
break;
case PurposeCodeSigning:
ba = QByteArray(GNUTLS_KP_CODE_SIGNING);
break;
case PurposeEmailProtection:
ba = QByteArray(GNUTLS_KP_EMAIL_PROTECTION);
break;
case PurposeTimeStamping:
ba = QByteArray(GNUTLS_KP_TIME_STAMPING);
break;
case PurposeOcspSigning:
ba = QByteArray(GNUTLS_KP_OCSP_SIGNING);
break;
case PurposeIpsecIke:
ba = QByteArray(GNUTLS_KP_IPSEC_IKE);
break;
case PurposeAny:
ba = QByteArray(GNUTLS_KP_ANY);
break;
default:
qWarning("Unknown Purpose %d", int(purpose));
return false;
}
return addKeyPurpose(ba, critical);
}
/*!
Adds the specified purpose to the list of those this certificate may be
used for. This method may be called multiple times to add a series of
different purposes. This method differs from the one above by allowing
arbitrary OIDs to be used, not just those for which there is built in
support.
*/
bool CertificateBuilder::addKeyPurpose(const QByteArray &oid, bool critical)
{
d->errno = gnutls_x509_crt_set_key_purpose_oid(d->crt, oid.constData(), critical);
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Sets the key usage flags for the certificate. If you call this method more
than once then only the last value will be used by the created certificate.
*/
bool CertificateBuilder::setKeyUsage(KeyUsageFlags usages)
{
uint usage = 0;
if (usages & UsageEncipherOnly)
usage |= GNUTLS_KEY_ENCIPHER_ONLY;
if (usages & UsageCrlSign)
usage |= GNUTLS_KEY_CRL_SIGN;
if (usages & UsageKeyCertSign)
usage |= GNUTLS_KEY_KEY_CERT_SIGN;
if (usages & UsageKeyAgreement)
usage |= GNUTLS_KEY_KEY_AGREEMENT;
if (usages & UsageDataEncipherment)
usage |= GNUTLS_KEY_DATA_ENCIPHERMENT;
if (usages & UsageKeyEncipherment)
usage |= GNUTLS_KEY_KEY_ENCIPHERMENT;
if (usages & UsageNonRepudiation)
usage |= GNUTLS_KEY_NON_REPUDIATION;
if (usages & UsageDigitalSignature)
usage |= GNUTLS_KEY_DIGITAL_SIGNATURE;
if (usages & UsageDecipherOnly)
usage |= GNUTLS_KEY_DECIPHER_ONLY;
d->errno = gnutls_x509_crt_set_key_usage(d->crt, usage);
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Adds the subject key identifier extension to the certificate. The key
is extracted automatically from the certificate being created.
*/
bool CertificateBuilder::addSubjectKeyIdentifier()
{
QByteArray ba(128, 0); // Normally 20 bytes (SHA1)
size_t size = ba.size();
d->errno = gnutls_x509_crt_get_key_id(d->crt, 0, reinterpret_cast<unsigned char *>(ba.data()), &size);
if (GNUTLS_E_SUCCESS != d->errno)
return false;
d->errno = gnutls_x509_crt_set_subject_key_id (d->crt, ba.constData(), size);
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Adds the authority key identifier extension to the certificate. The key
is extracted the specified certificate which must be the one later used
to sign the certificate.
*/
bool CertificateBuilder::addAuthorityKeyIdentifier(const QSslCertificate &qcacert)
{
gnutls_x509_crt_t cacrt = qsslcert_to_crt(qcacert, &d->errno);
if (GNUTLS_E_SUCCESS != d->errno)
return false;
QByteArray ba(128, 0); // Normally 20 bytes (SHA1)
size_t size = ba.size();
// Try using the subject keyid
d->errno = gnutls_x509_crt_get_subject_key_id(cacrt, reinterpret_cast<unsigned char *>(ba.data()), &size, NULL);
// Or fallback to creating it
if (GNUTLS_E_SUCCESS != d->errno) {
d->errno = gnutls_x509_crt_get_key_id(cacrt, 0, reinterpret_cast<unsigned char *>(ba.data()), &size);
if (GNUTLS_E_SUCCESS != d->errno) {
gnutls_x509_crt_deinit(cacrt);
return false;
}
}
gnutls_x509_crt_deinit(cacrt);
d->errno = gnutls_x509_crt_set_authority_key_id(d->crt, reinterpret_cast<const unsigned char *>(ba.constData()), size);
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Creates a self-signed certificate by signing the certificate with the specified
key.
*/
QSslCertificate CertificateBuilder::signedCertificate(const QSslKey &qkey)
{
gnutls_x509_privkey_t key = qsslkey_to_key(qkey, &d->errno);
if (GNUTLS_E_SUCCESS != d->errno) {
gnutls_x509_privkey_deinit(key);
return QSslCertificate();
};
gnutls_privkey_t abstractKey;
d->errno = gnutls_privkey_init(&abstractKey);
if (GNUTLS_E_SUCCESS != d->errno) {
gnutls_x509_privkey_deinit(key);
return QSslCertificate();
}
gnutls_privkey_import_x509(abstractKey, key, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
d->errno = gnutls_x509_crt_privkey_sign(d->crt, d->crt, abstractKey, GNUTLS_DIG_SHA1, 0);
gnutls_x509_privkey_deinit(key);
if (GNUTLS_E_SUCCESS != d->errno)
return QSslCertificate();
return crt_to_qsslcert(d->crt, &d->errno);
}
/*!
Creates a certificate signed by the specified CA certificate using the
CA key.
*/
QSslCertificate CertificateBuilder::signedCertificate(const QSslCertificate &qcacert, const QSslKey &qcakey)
{
//
// Extract the CA key
//
gnutls_x509_privkey_t key = qsslkey_to_key(qcakey, &d->errno);
if (GNUTLS_E_SUCCESS != d->errno) {
gnutls_x509_privkey_deinit(key);
return QSslCertificate();
};
gnutls_privkey_t abstractKey;
d->errno = gnutls_privkey_init(&abstractKey);
if (GNUTLS_E_SUCCESS != d->errno) {
gnutls_x509_privkey_deinit(key);
return QSslCertificate();
}
gnutls_privkey_import_x509(abstractKey, key, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
//
// Extract the CA cert
//
gnutls_x509_crt_t cacrt = qsslcert_to_crt(qcacert, &d->errno);
if (GNUTLS_E_SUCCESS != d->errno) {
gnutls_x509_privkey_deinit(key);
return QSslCertificate();
}
//
// Sign the cert
//
d->errno = gnutls_x509_crt_privkey_sign(d->crt, cacrt, abstractKey, GNUTLS_DIG_SHA1, 0);
gnutls_x509_crt_deinit(cacrt);
gnutls_x509_privkey_deinit(key);
if (GNUTLS_E_SUCCESS != d->errno)
return QSslCertificate();
return crt_to_qsslcert(d->crt, &d->errno);
}
QT_END_NAMESPACE_CERTIFICATE

View File

@@ -0,0 +1,122 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef CERTIFICATEBUILDER_H
#define CERTIFICATEBUILDER_H
#include <QString>
#include <QFlags>
#include <QtNetwork/QSslCertificate>
#include "certificate_global.h"
class QDateTime;
QT_BEGIN_NAMESPACE_CERTIFICATE
class CertificateRequest;
class Q_CERTIFICATE_EXPORT CertificateBuilder
{
public:
enum KeyPurpose {
PurposeWebServer,
PurposeWebClient,
PurposeCodeSigning,
PurposeEmailProtection,
PurposeTimeStamping,
PurposeOcspSigning,
PurposeIpsecIke,
PurposeAny
};
enum KeyUsageFlag {
UsageEncipherOnly = 0x1,
UsageCrlSign = 0x2,
UsageKeyCertSign = 0x4,
UsageKeyAgreement = 0x8,
UsageDataEncipherment = 0x10,
UsageKeyEncipherment = 0x20,
UsageNonRepudiation = 0x40,
UsageDigitalSignature = 0x80,
UsageDecipherOnly = 0x100
};
Q_DECLARE_FLAGS(KeyUsageFlags, KeyUsageFlag)
CertificateBuilder();
~CertificateBuilder();
int error() const;
QString errorString() const;
bool setRequest(const CertificateRequest &crq);
bool setVersion(int version=3);
bool setSerial(const QByteArray &serial);
bool setActivationTime(const QDateTime &date);
bool setExpirationTime(const QDateTime &date);
// Extensions
bool copyRequestExtensions(const CertificateRequest &crq);
bool setBasicConstraints(bool ca=false, int pathLength=-1);
// Extended usage
bool addKeyPurpose(KeyPurpose purpose, bool critical=false);
bool addKeyPurpose(const QByteArray &oid, bool critical=false);
// Usage
bool setKeyUsage(KeyUsageFlags usage);
// Key identifiers
bool addSubjectKeyIdentifier();
bool addAuthorityKeyIdentifier(const QSslCertificate &cacert);
QSslCertificate signedCertificate(const QSslKey &key);
QSslCertificate signedCertificate(const QSslCertificate &cacert, const QSslKey &cakey);
private:
struct CertificateBuilderPrivate *d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(CertificateBuilder::KeyUsageFlags)
QT_END_NAMESPACE_CERTIFICATE
#endif // CERTIFICATEBUILDER_H

View File

@@ -0,0 +1,58 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef CERTIFICATEBUILDER_P_H
#define CERTIFICATEBUILDER_P_H
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "certificatebuilder.h"
QT_BEGIN_NAMESPACE_CERTIFICATE
struct CertificateBuilderPrivate
{
int errno;
gnutls_x509_crt_t crt;
};
QT_END_NAMESPACE_CERTIFICATE
#endif // CERTIFICATEBUILDER_P_H

View File

@@ -0,0 +1,255 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QByteArray>
#include <QIODevice>
#include <QStringList>
#include <QDebug>
#include "utils_p.h"
#include "certificaterequest_p.h"
QT_BEGIN_NAMESPACE_CERTIFICATE
/*!
\class CertificateRequest
\brief The CertificateRequest class provides a convenient interface for an X.509
certificate signing request.
*/
/*!
\internal
Convert a crq to a PEM or DER encoded QByteArray.
*/
static QByteArray request_to_bytearray(gnutls_x509_crq_t crq, gnutls_x509_crt_fmt_t format, int *errno)
{
QByteArray ba(4096, 0);
size_t size = ba.size();
*errno = gnutls_x509_crq_export(crq, format, ba.data(), &size);
if (GNUTLS_E_SUCCESS != *errno)
return QByteArray();
ba.resize(size); // size has now been updated
return ba;
}
CertificateRequestPrivate::CertificateRequestPrivate()
: null(true)
{
ensure_gnutls_init();
gnutls_x509_crq_init(&crq);
errno = GNUTLS_E_SUCCESS;
}
CertificateRequestPrivate::~CertificateRequestPrivate()
{
gnutls_x509_crq_deinit(crq);
}
/*!
Create a null CertificateRequest.
*/
CertificateRequest::CertificateRequest()
: d(new CertificateRequestPrivate)
{
}
/*!
Create a CertificateRequest that is a copy of other.
*/
CertificateRequest::CertificateRequest(const CertificateRequest &other)
: d(other.d)
{
}
/*!
Load a CertificateRequest from the specified QIODevice using the specified format.
*/
CertificateRequest::CertificateRequest(QIODevice *io, QSsl::EncodingFormat format)
: d(new CertificateRequestPrivate)
{
QByteArray buf = io->readAll();
// Setup a datum
gnutls_datum_t buffer;
buffer.data = (unsigned char *)(buf.data());
buffer.size = buf.size();
d->errno = gnutls_x509_crq_import(d->crq, &buffer, (QSsl::Pem == format) ? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER);
if (GNUTLS_E_SUCCESS == d->errno)
d->null = false;
}
/*!
Clean up.
*/
CertificateRequest::~CertificateRequest()
{
}
/*!
Returns true if this CertificateRequest is null (uninitialised).
*/
bool CertificateRequest::isNull() const
{
return d->null;
}
/*!
Returns the last error that occurred when using this object. The values
used are those of gnutls. If there has not been an error then it is
guaranteed to be 0.
*/
int CertificateRequest::error() const
{
return d->errno;
}
/*!
Returns a string describing the last error that occurred when using
this object.
*/
QString CertificateRequest::errorString() const
{
return QString::fromUtf8(gnutls_strerror(d->errno));
}
/*!
Returns the version of the certificate signing request.
*/
int CertificateRequest::version() const
{
return gnutls_x509_crq_get_version(d->crq);
}
/*!
Returns the list of attributes that are present in this requests
distinguished name. The attributes are returned as OIDs.
*/
QList<QByteArray> CertificateRequest::nameEntryAttributes()
{
QList<QByteArray> result;
int index = 0;
do {
QByteArray buffer(1024, 0);
size_t size = buffer.size();
d->errno = gnutls_x509_crq_get_dn_oid(d->crq, index, buffer.data(), &size);
if (GNUTLS_E_SUCCESS == d->errno) {
buffer.resize(size);
result << buffer;
}
index++;
} while(GNUTLS_E_SUCCESS == d->errno);
return result;
}
/*!
Returns the list of entries for the attribute specified.
*/
QStringList CertificateRequest::nameEntryInfo(Certificate::EntryType attribute)
{
return nameEntryInfo(entrytype_to_oid(attribute));
}
/*!
Returns the list of entries for the attribute specified by the oid.
*/
QStringList CertificateRequest::nameEntryInfo(const QByteArray &oid)
{
QStringList result;
if (oid.isNull())
return result;
int index = 0;
do {
QByteArray buffer(1024, 0);
size_t size = buffer.size();
d->errno = gnutls_x509_crq_get_dn_by_oid(d->crq, oid.constData(), index, false, buffer.data(), &size);
if (GNUTLS_E_SUCCESS == d->errno)
result << QString::fromUtf8(buffer);
index++;
} while(GNUTLS_E_SUCCESS == d->errno);
return result;
}
/*!
Returns a QByteArray containing this request encoded as PEM.
*/
QByteArray CertificateRequest::toPem()
{
return request_to_bytearray(d->crq, GNUTLS_X509_FMT_PEM, &d->errno);
}
/*!
Returns a QByteArray containing this request encoded as DER.
*/
QByteArray CertificateRequest::toDer()
{
return request_to_bytearray(d->crq, GNUTLS_X509_FMT_DER, &d->errno);
}
/*!
Returns a QString containing this request as a human readable string.
*/
QString CertificateRequest::toText()
{
gnutls_datum_t datum;
d->errno = gnutls_x509_crq_print(d->crq, GNUTLS_CRT_PRINT_FULL, &datum);
if (GNUTLS_E_SUCCESS != d->errno)
return QString();
QString result = QString::fromUtf8(reinterpret_cast<const char *>(datum.data), datum.size);
gnutls_free(datum.data);
return result;
}
QT_END_NAMESPACE_CERTIFICATE

View File

@@ -0,0 +1,96 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef CERTIFICATEREQUEST_H
#define CERTIFICATEREQUEST_H
#include <QtNetwork/QSsl>
#include <QtCore/qshareddata.h>
#include "certificate_global.h"
#include "certificate.h"
class QIODevice;
QT_BEGIN_NAMESPACE_CERTIFICATE
class CertificateRequestPrivate;
class CertificateRequestBuilder;
class Q_CERTIFICATE_EXPORT CertificateRequest
{
public:
CertificateRequest();
CertificateRequest(const CertificateRequest &other);
CertificateRequest(QIODevice *io, QSsl::EncodingFormat format=QSsl::Pem);
~CertificateRequest();
CertificateRequest &operator=(const CertificateRequest &other);
void swap(CertificateRequest &other) { qSwap(d, other.d); }
bool isNull() const;
int error() const;
QString errorString() const;
// TODO: Include accessors for the fields
int version() const;
QList<QByteArray> nameEntryAttributes();
// TODO: QList<QByteArray>?
QStringList nameEntryInfo(Certificate::EntryType attribute);
QStringList nameEntryInfo(const QByteArray &attribute);
QByteArray toPem();
QByteArray toDer();
QString toText();
private:
friend class CertificateRequestPrivate;
friend class CertificateRequestBuilder;
friend class CertificateBuilder;
QSharedDataPointer<CertificateRequestPrivate> d;
};
QT_END_NAMESPACE_CERTIFICATE
#endif // CERTIFICATEREQUEST_H

View File

@@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef CERTIFICATEREQUEST_P_H
#define CERTIFICATEREQUEST_P_H
#include "certificaterequest.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
QT_BEGIN_NAMESPACE_CERTIFICATE
class CertificateRequestPrivate : public QSharedData
{
public:
CertificateRequestPrivate();
~CertificateRequestPrivate();
bool null;
int errno;
gnutls_x509_crq_t crq;
};
QT_END_NAMESPACE_CERTIFICATE
#endif // CERTIFICATEREQUEST_P_H

View File

@@ -0,0 +1,265 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QIODevice>
#include "certificaterequest_p.h"
#include "utils_p.h"
#include "certificaterequestbuilder_p.h"
QT_BEGIN_NAMESPACE_CERTIFICATE
/*!
\class CertificateRequestBuilder
\brief The CertificateRequestBuilder class is a tool for creating certificate
signing requests.
*/
/*!
Create a new CertificateRequestBuilder.
*/
CertificateRequestBuilder::CertificateRequestBuilder()
: d(new CertificateRequestBuilderPrivate)
{
ensure_gnutls_init();
gnutls_x509_crq_init(&d->crq);
d->errno = GNUTLS_E_SUCCESS;
}
/*!
Cleans up a CertificateRequestBuilder.
*/
CertificateRequestBuilder::~CertificateRequestBuilder()
{
gnutls_x509_crq_deinit(d->crq);
delete d;
}
/*!
Returns the last error that occurred when using this object. The values
used are those of gnutls. If there has not been an error then it is
guaranteed to be 0.
*/
int CertificateRequestBuilder::error() const
{
return d->errno;
}
/*!
Returns a string describing the last error that occurred when using
this object.
*/
QString CertificateRequestBuilder::errorString() const
{
return QString::fromUtf8(gnutls_strerror(d->errno));
}
/*!
Set the version of the certificate signing request. This should
generally be set to 1.
*/
bool CertificateRequestBuilder::setVersion(int version)
{
d->errno = gnutls_x509_crq_set_version(d->crq, version);
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Returns the version of the certificate signing request.
*/
int CertificateRequestBuilder::version() const
{
int ver = gnutls_x509_crq_get_version(d->crq);
if (ver < 0)
d->errno = ver;
return ver;
}
/*!
Sets the key that will be used for the reqest.
*/
bool CertificateRequestBuilder::setKey(const QSslKey &qkey)
{
gnutls_x509_privkey_t key = qsslkey_to_key(qkey, &d->errno);
if (GNUTLS_E_SUCCESS != d->errno) {
gnutls_x509_privkey_deinit(key);
return false;
};
d->errno = gnutls_x509_crq_set_key(d->crq, key);
gnutls_x509_privkey_deinit(key);
return GNUTLS_E_SUCCESS == d->errno;
}
/*!
Returns the list of attributes that are present in this requests
distinguished name. The attributes are returned as OIDs.
*/
QList<QByteArray> CertificateRequestBuilder::nameEntryAttributes()
{
QList<QByteArray> result;
int index = 0;
do {
QByteArray buffer(1024, 0);
size_t size = buffer.size();
d->errno = gnutls_x509_crq_get_dn_oid(d->crq, index, buffer.data(), &size);
if (GNUTLS_E_SUCCESS == d->errno) {
buffer.resize(size);
result << buffer;
}
index++;
} while(GNUTLS_E_SUCCESS == d->errno);
return result;
}
/*!
Returns the list of entries for the attribute specified.
*/
QStringList CertificateRequestBuilder::nameEntryInfo(Certificate::EntryType attribute)
{
return nameEntryInfo(entrytype_to_oid(attribute));
}
/*!
Returns the list of entries for the attribute specified by the oid.
*/
QStringList CertificateRequestBuilder::nameEntryInfo(const QByteArray &oid)
{
QStringList result;
if (oid.isNull())
return result;
int index = 0;
do {
QByteArray buffer(1024, 0);
size_t size = buffer.size();
d->errno = gnutls_x509_crq_get_dn_by_oid(d->crq, oid.constData(), index, false, buffer.data(), &size);
if (GNUTLS_E_SUCCESS == d->errno)
result << QString::fromUtf8(buffer);
index++;
} while(GNUTLS_E_SUCCESS == d->errno);
return result;
}
/*!
Adds an entry to the distinguished name of the certificate signing request. The
\a type parameter specifies the field that will be added, and the \a value
parameter specifies the value. This method can be called multiple times with the
same \a type and will add additional entries.
*/
bool CertificateRequestBuilder::addNameEntry(Certificate::EntryType type, const QByteArray &value)
{
QByteArray oid = entrytype_to_oid(type);
if (oid.isNull())
return false;
return addNameEntry(oid, value);
}
/*!
Adds an entry to the distinguished name of the certificate signing request. The
\a oid parameter specifies the ASN.1 OID of the field that will be added, and
the \a value parameter specifies the value. If the \a raw flag is set to true
then OIDs not understood by GNUTLS may be added, and the value must be DER
encoded. This method can be called multiple times with the same \a type and
will add additional entries.
*/
bool CertificateRequestBuilder::addNameEntry(const QByteArray &oid, const QByteArray &value, bool raw)
{
d->errno = gnutls_x509_crq_set_dn_by_oid(d->crq, oid.constData(), raw,
value.constData(), qstrlen(value.constData()));
return GNUTLS_E_SUCCESS == d->errno;
}
#if QT_VERSION >= 0x050000
bool CertificateRequestBuilder::addSubjectAlternativeNameEntry(QSsl::AlternativeNameEntryType qtype, const QByteArray &value)
{
gnutls_x509_subject_alt_name_t type = qssl_altnameentrytype_to_altname(qtype);
d->errno = gnutls_x509_crq_set_subject_alt_name(d->crq, type, value.constData(), value.size(), GNUTLS_FSAN_APPEND);
return GNUTLS_E_SUCCESS == d->errno;
}
#else
bool CertificateRequestBuilder::addSubjectAlternativeNameEntry(QSsl::AlternateNameEntryType qtype, const QByteArray &value)
{
gnutls_x509_subject_alt_name_t type = qssl_altnameentrytype_to_altname(qtype);
d->errno = gnutls_x509_crq_set_subject_alt_name(d->crq, type, value.constData(), value.size(), GNUTLS_FSAN_APPEND);
return GNUTLS_E_SUCCESS == d->errno;
}
#endif
/*!
Signs the request with the specified key and returns the signed request.
*/
CertificateRequest CertificateRequestBuilder::signedRequest(const QSslKey &qkey)
{
CertificateRequest result;
gnutls_x509_privkey_t key = qsslkey_to_key(qkey, &d->errno);
if (GNUTLS_E_SUCCESS != d->errno) {
gnutls_x509_privkey_deinit(key);
return result;
};
d->errno = gnutls_x509_crq_sign2(d->crq, key, GNUTLS_DIG_SHA1, 0);
gnutls_x509_privkey_deinit(key);
if (GNUTLS_E_SUCCESS != d->errno)
return result;
gnutls_x509_crq_t crqsave = result.d->crq;
result.d->crq = d->crq;
d->crq = crqsave;
return result;
}
QT_END_NAMESPACE_CERTIFICATE

View File

@@ -0,0 +1,91 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef CERTIFICATEREQUESTBUILDER_H
#define CERTIFICATEREQUESTBUILDER_H
#include <QSslKey>
#include <QStringList>
#include "certificaterequest.h"
#include "certificate.h"
#include "certificate_global.h"
class QIODevice;
class QByteArray;
QT_BEGIN_NAMESPACE_CERTIFICATE
class Q_CERTIFICATE_EXPORT CertificateRequestBuilder
{
public:
CertificateRequestBuilder();
~CertificateRequestBuilder();
int error() const;
QString errorString() const;
bool setVersion(int version);
int version() const;
bool setKey(const QSslKey &key);
bool addNameEntry(Certificate::EntryType type, const QByteArray &value);
bool addNameEntry(const QByteArray &oid, const QByteArray &value, bool raw=false);
QList<QByteArray> nameEntryAttributes();
QStringList nameEntryInfo(Certificate::EntryType attribute);
QStringList nameEntryInfo(const QByteArray &attribute);
#if QT_VERSION >= 0x050000
bool addSubjectAlternativeNameEntry(QSsl::AlternativeNameEntryType type, const QByteArray &value);
#else
bool addSubjectAlternativeNameEntry(QSsl::AlternateNameEntryType type, const QByteArray &value);
#endif
CertificateRequest signedRequest(const QSslKey &key);
private:
struct CertificateRequestBuilderPrivate *d;
};
QT_END_NAMESPACE_CERTIFICATE
#endif // CERTIFICATEREQUESTBUILDER_H

View File

@@ -0,0 +1,57 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef CERTIFICATEREQUESTBUILDER_P_H
#define CERTIFICATEREQUESTBUILDER_P_H
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "certificaterequestbuilder.h"
QT_BEGIN_NAMESPACE_CERTIFICATE
struct CertificateRequestBuilderPrivate
{
int errno;
gnutls_x509_crq_t crq;
};
QT_END_NAMESPACE_CERTIFICATE
#endif // CERTIFICATEREQUESTBUILDER_P_H

View File

@@ -0,0 +1,108 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "utils_p.h"
#include "keybuilder.h"
QT_BEGIN_NAMESPACE_CERTIFICATE
/*!
\class KeyBuilder
\brief The KeyBuilder class is a tool for creating QSslKeys.
The KeyBuilder class provides an easy way to generate a new private
key for an X.509 certificate.
*/
/*!
Generates a new key using the specified algorithm and strength. The algorithm
will generally be RSA. The various strengths allow you to specify the trade-off
between the security of the key and the time involved in creating it.
Note that this method can take a considerable length of time to execute, so in
gui applications it should be run in a worker thread.
*/
QSslKey KeyBuilder::generate( QSsl::KeyAlgorithm algo, KeyStrength strength )
{
ensure_gnutls_init();
gnutls_sec_param_t sec;
switch(strength) {
case StrengthLow:
sec = GNUTLS_SEC_PARAM_LOW;
break;
case StrengthNormal:
sec = GNUTLS_SEC_PARAM_NORMAL;
break;
case StrengthHigh:
sec = GNUTLS_SEC_PARAM_HIGH;
break;
case StrengthUltra:
sec = GNUTLS_SEC_PARAM_ULTRA;
break;
default:
qWarning("Unhandled strength %d passed to generate", uint(strength));
sec = GNUTLS_SEC_PARAM_NORMAL;
}
uint bits = gnutls_sec_param_to_pk_bits((algo == QSsl::Rsa) ? GNUTLS_PK_RSA : GNUTLS_PK_DSA, sec);
gnutls_x509_privkey_t key;
gnutls_x509_privkey_init(&key);
int errno = gnutls_x509_privkey_generate(key, (algo == QSsl::Rsa) ? GNUTLS_PK_RSA : GNUTLS_PK_DSA, bits, 0);
if (GNUTLS_E_SUCCESS != errno) {
qWarning("Failed to generate key %s", gnutls_strerror(errno));
gnutls_x509_privkey_deinit(key);
return QSslKey();
}
QSslKey qkey = key_to_qsslkey(key, algo, &errno);
if (GNUTLS_E_SUCCESS != errno) {
qWarning("Failed to convert key to bytearray %s", gnutls_strerror(errno));
gnutls_x509_privkey_deinit(key);
return QSslKey();
}
return qkey;
}
QT_END_NAMESPACE_CERTIFICATE

View File

@@ -0,0 +1,71 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef KEYBUILDER_H
#define KEYBUILDER_H
#include <QtNetwork/QSslKey>
#include <QtNetwork/QSsl>
#include "certificate_global.h"
QT_BEGIN_NAMESPACE_CERTIFICATE
class Q_CERTIFICATE_EXPORT KeyBuilder
{
public:
enum KeyStrength {
StrengthLow,
StrengthNormal,
StrengthHigh,
StrengthUltra
};
static QSslKey generate( QSsl::KeyAlgorithm algo, KeyStrength strength );
private:
KeyBuilder() {}
~KeyBuilder() {}
private:
struct KeyBuilderPrivate *d;
};
QT_END_NAMESPACE_CERTIFICATE
#endif // KEYBUILDER_H

View File

@@ -0,0 +1,80 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include "randomgenerator.h"
QT_BEGIN_NAMESPACE_CERTIFICATE
/*!
\class RandomGenerator
\brief The RandomGenerator class is a tool for creating hard random numbers.
The RandomGenerator class provides a source of secure random numbers using
the gnutls rnd API. The numbers are suitable for uses such as certificate
serial numbers.
*/
/*!
Generates a set of random bytes of the specified size. In order to allow
these to be conveniently used as serial numbers, this method ensures that
the value returned is positive (ie. that the first bit is 0). This means
that you get one less bit of entropy than requested, but avoids
interoperability issues.
Note that this method will either return the number of bytes requested,
or a null QByteArray. It will never return a smaller number.
*/
QByteArray RandomGenerator::getPositiveBytes(int size)
{
QByteArray result(size, 0);
int errno = gnutls_rnd(GNUTLS_RND_RANDOM, result.data(), size);
if (GNUTLS_E_SUCCESS != errno)
return QByteArray();
// Clear the top bit to ensure the number is positive
char *data = result.data();
*data = *data & 0x07f;
return result;
}
QT_END_NAMESPACE_CERTIFICATE

View File

@@ -0,0 +1,61 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef RANDOMGENERATOR_H
#define RANDOMGENERATOR_H
#include <QByteArray>
#include "certificate_global.h"
QT_BEGIN_NAMESPACE_CERTIFICATE
class Q_CERTIFICATE_EXPORT RandomGenerator
{
public:
static QByteArray getPositiveBytes(int size);
private:
RandomGenerator() {}
~RandomGenerator() {}
};
QT_END_NAMESPACE_CERTIFICATE
#endif // RANDOMGENERATOR_H

View File

@@ -0,0 +1,186 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <gnutls/gnutls.h>
#include <QByteArray>
#include <QSslKey>
#include <QSslCertificate>
#include "utils_p.h"
QT_BEGIN_NAMESPACE_CERTIFICATE
using namespace Certificate;
void ensure_gnutls_init()
{
static bool done = false;
// TODO: protect with a mutex
if (!done) {
gnutls_global_init();
done = true;
}
}
QByteArray entrytype_to_oid(Certificate::EntryType type)
{
QByteArray oid;
// TODO: More common name entry types
switch(type) {
case EntryCountryName:
oid = QByteArray(GNUTLS_OID_X520_COUNTRY_NAME);
break;
case EntryOrganizationName:
oid = QByteArray(GNUTLS_OID_X520_ORGANIZATION_NAME);
break;
case EntryOrganizationalUnitName:
oid = QByteArray(GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME);
break;
case EntryCommonName:
oid = QByteArray(GNUTLS_OID_X520_COMMON_NAME);
break;
case EntryLocalityName:
oid = QByteArray(GNUTLS_OID_X520_LOCALITY_NAME);
break;
case EntryStateOrProvinceName:
oid = QByteArray(GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME);
break;
case EntryEmail:
oid = QByteArray(GNUTLS_OID_PKCS9_EMAIL);
break;
default:
qWarning("Unhandled name entry type %d", int(type));
}
return oid;
}
gnutls_x509_privkey_t qsslkey_to_key(const QSslKey &qkey, int *errno)
{
gnutls_x509_privkey_t key;
*errno = gnutls_x509_privkey_init(&key);
if (GNUTLS_E_SUCCESS != *errno)
return 0;
QByteArray buf(qkey.toPem());
// Setup a datum
gnutls_datum_t buffer;
buffer.data = (unsigned char *)(buf.data());
buffer.size = buf.size();
*errno = gnutls_x509_privkey_import(key, &buffer, GNUTLS_X509_FMT_PEM);
return key;
}
gnutls_x509_crt_t qsslcert_to_crt(const QSslCertificate &qcert, int *errno)
{
gnutls_x509_crt_t cert;
*errno = gnutls_x509_crt_init(&cert);
if (GNUTLS_E_SUCCESS != *errno)
return 0;
QByteArray buf(qcert.toPem());
// Setup a datum
gnutls_datum_t buffer;
buffer.data = (unsigned char *)(buf.data());
buffer.size = buf.size();
// Import the cert
*errno = gnutls_x509_crt_import(cert, &buffer, GNUTLS_X509_FMT_PEM);
return cert;
}
QSslCertificate crt_to_qsslcert(gnutls_x509_crt_t crt, int *errno)
{
QByteArray ba(4096, 0);
size_t size = ba.size();
*errno = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, ba.data(), &size);
if (GNUTLS_E_SUCCESS != *errno)
return QSslCertificate();
return QSslCertificate(ba);
}
QSslKey key_to_qsslkey(gnutls_x509_privkey_t key, QSsl::KeyAlgorithm algo, int *errno)
{
QByteArray ba(4096, 0);
size_t size = ba.size();
*errno = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, ba.data(), &size);
if (GNUTLS_E_SUCCESS != *errno)
return QSslKey();
return QSslKey(ba, algo);
}
#if QT_VERSION >= 0x050000
gnutls_x509_subject_alt_name_t qssl_altnameentrytype_to_altname(QSsl::AlternativeNameEntryType qtype)
{
switch(qtype) {
case QSsl::EmailEntry:
return GNUTLS_SAN_RFC822NAME;
case QSsl::DnsEntry:
return GNUTLS_SAN_DNSNAME;
default:
qWarning("Unknown alternative name type %d", int(qtype));
}
}
#else
gnutls_x509_subject_alt_name_t qssl_altnameentrytype_to_altname(QSsl::AlternateNameEntryType qtype)
{
switch(qtype) {
case QSsl::EmailEntry:
return GNUTLS_SAN_RFC822NAME;
case QSsl::DnsEntry:
return GNUTLS_SAN_DNSNAME;
default:
qWarning("Unknown alternative name type %d", int(qtype));
}
}
#endif
QT_END_NAMESPACE_CERTIFICATE

View File

@@ -0,0 +1,73 @@
/****************************************************************************
**
** Copyright (C) 2012-2013 Richard J. Moore <rich@kde.org>
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef UTILS_P_H
#define UTILS_P_H
#include <gnutls/x509.h>
#include <QtNetwork/QSsl>
#include <QtCore/QByteArray>
#include "certificate_global.h"
#include "certificate.h"
class QSslKey;
class QSslCertificate;
QT_BEGIN_NAMESPACE_CERTIFICATE
void ensure_gnutls_init();
QByteArray entrytype_to_oid(Certificate::EntryType type);
gnutls_x509_privkey_t qsslkey_to_key(const QSslKey &qkey, int *errno);
gnutls_x509_crt_t qsslcert_to_crt(const QSslCertificate &qcert, int *errno);
QSslCertificate crt_to_qsslcert(gnutls_x509_crt_t crt, int *errno);
QSslKey key_to_qsslkey(gnutls_x509_privkey_t key, QSsl::KeyAlgorithm algo, int *errno);
#if QT_VERSION >= 0x050000
gnutls_x509_subject_alt_name_t qssl_altnameentrytype_to_altname(QSsl::AlternativeNameEntryType qtype);
#else
gnutls_x509_subject_alt_name_t qssl_altnameentrytype_to_altname(QSsl::AlternateNameEntryType qtype);
#endif
QT_END_NAMESPACE_CERTIFICATE
#endif // UTILS_P_H

View File

@@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS = certificate

View File

@@ -0,0 +1,7 @@
TEMPLATE = subdirs
SUBDIRS += keybuilder \
certificaterequest \
certificaterequestbuilder

View File

@@ -0,0 +1 @@
tst_certificaterequest

View File

@@ -0,0 +1,11 @@
TEMPLATE = app
TARGET = tst_certificaterequest
CONFIG += testcase
QT += testlib network
LIBS += -Wl,-rpath,../../../src/certificate -L../../../src/certificate -lcertificate
INCLUDEPATH += ../../../src/certificate
SOURCES += tst_certificaterequest.cpp

View File

@@ -0,0 +1,12 @@
-----BEGIN NEW CERTIFICATE REQUEST-----
MIIBtTCCAR4CAQAwdTEUMBIGA1UEAxMLZXhhbXBsZS5jb20xEzARBgNVBAgTCkxh
bmNhc2hpcmUxCzAJBgNVBAYTAlVLMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1w
bGUuY29tMRowGAYDVQQKExFTb21lIG9yZ2FuaXNhdGlvbjCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEAl8mSJ4GnTGSCojDWB7dX4JzqzetTvuq2tUdm0GhUJaft
IVzc/dpB9sfANa6Xcv2Lryk9OFpnizmKzoYlDzintTizjoHw6nmZy/UjZFXzS6S2
I2Qp6rrzKVKnfzLcDbbZ1OYT3gFBhpotj7sMGIgJrNRq6cuKF4qFCaauphwF6VUC
AwEAAaAAMA0GCSqGSIb3DQEBBQUAA4GBAIubgGHRO9Whcf0caMrZ7aUtGfVj8Okj
RVOBlqUlVADhWUrWKHR1yV3j4+HDwpzQ5JemMcvLKH46m+c9OCnM6L904RxK0ZrJ
qPcRhHGadYGsF6Naj8PFRgIEzjsIi/OGXoAWLE3/cglnW1pxTbO2ZWJF+8pGAqaC
rEhokeHr2+06
-----END NEW CERTIFICATE REQUEST-----

View File

@@ -0,0 +1,117 @@
#include <QtTest/QtTest>
#include "certificaterequest.h"
QT_USE_NAMESPACE_CERTIFICATE
class tst_CertificateRequest : public QObject
{
Q_OBJECT
private slots:
void checkNull();
void loadCrq();
void checkEntryAttributes();
void checkEntries();
void checkToText();
};
void tst_CertificateRequest::checkNull()
{
CertificateRequest csr;
QVERIFY(csr.isNull());
}
void tst_CertificateRequest::loadCrq()
{
QFile f("requests/test-ocsp-good-req.pem");
f.open(QIODevice::ReadOnly);
CertificateRequest csr(&f);
f.close();
QVERIFY(!csr.isNull());
QVERIFY(csr.version() == 1);
QFile f2("requests/test-ocsp-good-req.pem");
f2.open(QIODevice::ReadOnly);
QByteArray filePem = f2.readAll();
f2.close();
QVERIFY(filePem == csr.toPem());
}
void tst_CertificateRequest::checkEntryAttributes()
{
QFile f("requests/test-ocsp-good-req.pem");
f.open(QIODevice::ReadOnly);
CertificateRequest csr(&f);
f.close();
QList<QByteArray> attrs;
attrs << "2.5.4.3" << "2.5.4.8" << "2.5.4.6" << "1.2.840.113549.1.9.1" << "2.5.4.10";
QCOMPARE(attrs, csr.nameEntryAttributes());
}
void tst_CertificateRequest::checkEntries()
{
QFile f("requests/test-ocsp-good-req.pem");
f.open(QIODevice::ReadOnly);
CertificateRequest csr(&f);
f.close();
QStringList commonName;
commonName << "example.com";
QVERIFY(commonName == csr.nameEntryInfo(Certificate::EntryCommonName));
QStringList organizationName;
organizationName << "Some organisation";
QVERIFY(organizationName == csr.nameEntryInfo(Certificate::EntryOrganizationName));
QStringList countryName;
countryName << "UK";
QVERIFY(countryName == csr.nameEntryInfo(Certificate::EntryCountryName));
QStringList email;
email << "test@example.com";
QVERIFY(email == csr.nameEntryInfo(Certificate::EntryEmail));
QStringList stateOrProvinceName;
stateOrProvinceName << "Lancashire";
QVERIFY(stateOrProvinceName == csr.nameEntryInfo(Certificate::EntryStateOrProvinceName));
QStringList localityName;
QVERIFY(localityName == csr.nameEntryInfo(Certificate::EntryLocalityName));
}
void tst_CertificateRequest::checkToText()
{
QFile f("requests/test-ocsp-good-req.pem");
f.open(QIODevice::ReadOnly);
CertificateRequest csr(&f);
f.close();
QLatin1String text("PKCS #10 Certificate Request Information:\n" \
"\tVersion: 1\n" \
"\tSubject: CN=example.com,ST=Lancashire,C=UK,EMAIL=test@example.com,O=Some organisation\n" \
"\tSubject Public Key Algorithm: RSA\n" \
"\t\tModulus (bits 1024):\n" \
"\t\t\t97:c9:92:27:81:a7:4c:64:82:a2:30:d6:07:b7:57:e0\n" \
"\t\t\t9c:ea:cd:eb:53:be:ea:b6:b5:47:66:d0:68:54:25:a7\n" \
"\t\t\ted:21:5c:dc:fd:da:41:f6:c7:c0:35:ae:97:72:fd:8b\n" \
"\t\t\taf:29:3d:38:5a:67:8b:39:8a:ce:86:25:0f:38:a7:b5\n" \
"\t\t\t38:b3:8e:81:f0:ea:79:99:cb:f5:23:64:55:f3:4b:a4\n" \
"\t\t\tb6:23:64:29:ea:ba:f3:29:52:a7:7f:32:dc:0d:b6:d9\n" \
"\t\t\td4:e6:13:de:01:41:86:9a:2d:8f:bb:0c:18:88:09:ac\n" \
"\t\t\td4:6a:e9:cb:8a:17:8a:85:09:a6:ae:a6:1c:05:e9:55\n" \
"\t\tExponent:\n" \
"\t\t\t01:00:01\n" \
"Other Information:\n" \
"\tPublic Key Id:\n" \
"\t\tad19b31110ef2ef08ed382e1f4a1766bcbf9d562\n");
QCOMPARE(text, csr.toText());
}
QTEST_MAIN(tst_CertificateRequest)
#include "tst_certificaterequest.moc"

View File

@@ -0,0 +1 @@
tst_certificaterequestbuilder

View File

@@ -0,0 +1,11 @@
TEMPLATE = app
TARGET = tst_certificaterequestbuilder
CONFIG += testcase
QT += testlib network
LIBS += -Wl,-rpath,../../../src/certificate -L../../../src/certificate -lcertificate
INCLUDEPATH += ../../../src/certificate
SOURCES += tst_certificaterequestbuilder.cpp

View File

@@ -0,0 +1,32 @@
-----BEGIN RSA PRIVATE KEY-----
MIIFfQIBAAKCATEA1v37hlwn7Co4FclSTACM53kt2tKXUcK6czCYdljKCMeFlm4+
us89sETF1entTWkKQSgSnoT6xNWlueayt9pFbkFxma7tDHdFImpTkxiJ7qf3ccLX
UY16qSMeU/vCV/Yj1uxm2XU6nXaMDfKMQGsqMslOkacls3nRhfPLrmH4kXNrueR6
VnSSEiTvxP4h9DBhBkgOhxEi9LQQFd8nl9MaGnKAiUlRhJMFuIluu9FzzpOLEBHO
75JFBCYmCvnfZVgLczogmzz4MS/N4V/wah1rdAuW4KeH9AOhcbncga2KmAqjY9e3
n2o5JFhtAMrpYgNgvzLtz1sYrgY9kulm11cDXqhbC7GL+gQEIjCgDKtGHtnzBsps
Az8UJh13HvRhGMna4w/et3/3a9+SEXXU0BdFMQIDAQABAoIBMQCwyoJ/ZmDd74nX
QIoQPZOg9SEkBHCypzKzbo6xIypgNdJAdb/X1nuf663Tzl15fpsUIWPOPwQHwLhb
Or5UOYVGuUI1YodD7QBI4K6BE3i5bB4qylJNmc34MAzMewbBVoL6RcP9pkzhF47s
GTwD7RvyT1/wnkZ+Y/pL8MLZT28cDJHVd3Cyj4FeskkI8QHyz6W5iJ+JqinYloeS
v7e6uaFyd6qssIg786iVd1rK6bz4JTu4wllNiH145XII0t04UksTPiUyfB6G55CW
bjr/m68TLxO4EA3OgLEZZqb3VOHM0BVJxAbJQmcwyQBKJdEtkdQNj0DBwG16UUIy
vcdEa80ZwruWPqd30w4pb6rNkVD0PKeUqk7amEXjevdVjhsPzrBv3vMnYlVW72/j
j5w3dKORAoGZAO4DJDEumdEMvdlU1AgURecpjZiQs9YyJSYa+oKrK0y7jAJ6dwSI
HRExLNdvlrb6yD+oSaddVNghI+lrJ+5YE3kP1FpNd70BN+hYTdCyOOWbZlVfglJZ
8M2amY2Fck4rRFBCkxyfpnArv0ZMkebqljJ/cMEWsoauvd4wQ0m1P671H5P17TP7
MaVkhIAAa5IsL1Uy9TfuP8r/AoGZAOc9d4QvQ62WUTwTZnYz4PG/uLR4DE5s0sbv
lwM6YVTPzJKTjAqsqo3Zp6Dp+dDwwYvqFi79qjy5C0Cp3b2uCL8zvo4NFoDMVwY9
+uERcN0Hn8tE6OxeJtJ1A7apjfhY2O9KOAfkyv+EFVjNqu7FsXjNzAfJvKLCEnyd
cKOe9wN4eCUqyczY/iXh4mYnBrr5oNCHyMxtUt/PAoGZAOZvviur3ZprhqeTHJIR
5rfvIDs05hichiEFf8LhLFPnRJ/lp7OIgPPzM2IFlNrlpNkU+vKCRzHVrCpC5+83
8OqF6+feFu6z7kgSrow+8R1EPmirxsYqdBzr8Hz3VXrfIw291yagX4k8obzTR3NV
bkPH5QfdDM2fAw7KlWsYg2bFxmP/dz+blS53Sl2PipaEFvObGZWkIrlLAoGZAOcc
C8NU6bMoNPByA0nH994l25ijEsmfAdpJwwg65OQ6+x7T0Hcqsxsqmdq9fixRM19/
CcTVSbt+xbxPCYt10NAoCx81/XOkxqU6dO9U2xRNdmtV5+W1A9/7i0aYl4fKZKZj
6zQYerp9bEhg5aHWe9Vc+boe6iVRCeD6CYW+bupNEOc0qJPPm9KIvBmUj6l3rD4+
N3X5HYcJAoGYalXnKjKXEum6KzzIvm2xM5z8FHURJ8CMk6nYDKH0RWv9qPTtvoLM
wkPu9wTii+L/9TEWpwPVGcvuFxwjgF9zulGhkDafzH+kO677AxGeukSTM0es6JIw
V+MwMb00tjhP+NBD7QP8YXkxA+QE4loReKONz9xVarc+meYwaPf/CnMCNHH+KKqZ
dWRkdDcn3oyRsAG3KcIt0j0=
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,73 @@
#include <QtTest/QtTest>
#include "certificaterequest.h"
#include "certificaterequestbuilder.h"
QT_USE_NAMESPACE_CERTIFICATE
class tst_CertificateRequestBuilder : public QObject
{
Q_OBJECT
private slots:
void version();
void entries();
};
void tst_CertificateRequestBuilder::version()
{
CertificateRequestBuilder builder;
builder.setVersion(1);
QCOMPARE(builder.version(), 1);
}
void tst_CertificateRequestBuilder::entries()
{
CertificateRequestBuilder builder;
builder.setVersion(1);
builder.addNameEntry(Certificate::EntryCountryName, "GB");
builder.addNameEntry(Certificate::EntryOrganizationName, "Westpoint");
builder.addNameEntry(Certificate::EntryOrganizationName, "West");
builder.addNameEntry(Certificate::EntryOrganizationalUnitName, "My Unit");
builder.addNameEntry(Certificate::EntryLocalityName, "My Locality");
builder.addNameEntry(Certificate::EntryStateOrProvinceName, "My State");
builder.addNameEntry(Certificate::EntryEmail, "test@example.com");
builder.addNameEntry(Certificate::EntryCommonName, "www.example.com");
QFile f("keys/leaf.key");
f.open(QIODevice::ReadOnly);
QSslKey key(&f, QSsl::Rsa);
f.close();
builder.setKey(key);
CertificateRequest req = builder.signedRequest(key);
QStringList countryName;
countryName << "GB";
QCOMPARE(countryName, req.nameEntryInfo(Certificate::EntryCountryName));
QStringList organizationName;
organizationName << "Westpoint";
organizationName << "West";
QCOMPARE(organizationName, req.nameEntryInfo(Certificate::EntryOrganizationName));
QStringList organizationalUnitName;
organizationalUnitName << "My Unit";
QCOMPARE(organizationalUnitName, req.nameEntryInfo(Certificate::EntryOrganizationalUnitName));
QStringList stateOrProvinceName;
stateOrProvinceName << "My State";
QCOMPARE(stateOrProvinceName, req.nameEntryInfo(Certificate::EntryStateOrProvinceName));
QStringList email;
email << "test@example.com";
QCOMPARE(email, req.nameEntryInfo(Certificate::EntryEmail));
QStringList commonName;
commonName << "www.example.com";
QCOMPARE(commonName, req.nameEntryInfo(Certificate::EntryCommonName));
}
QTEST_MAIN(tst_CertificateRequestBuilder)
#include "tst_certificaterequestbuilder.moc"

View File

@@ -0,0 +1 @@
tst_keybuilder

View File

@@ -0,0 +1,11 @@
TEMPLATE = app
TARGET = tst_keybuilder
CONFIG += testcase
QT += testlib network
LIBS += -Wl,-rpath,../../../src/certificate -L../../../src/certificate -lcertificate
INCLUDEPATH += ../../../src/certificate
SOURCES += tst_keybuilder.cpp

View File

@@ -0,0 +1,46 @@
#include <QSslKey>
#include <QtTest/QtTest>
#include "keybuilder.h"
QT_USE_NAMESPACE_CERTIFICATE
class tst_KeyBuilder : public QObject
{
Q_OBJECT
private slots:
void checkKeyLengths();
void checkKeyChanges();
};
void tst_KeyBuilder::checkKeyLengths()
{
QSslKey keyl = KeyBuilder::generate( QSsl::Rsa, KeyBuilder::StrengthLow );
QVERIFY(keyl.length() >= 1248);
QSslKey keyn = KeyBuilder::generate( QSsl::Rsa, KeyBuilder::StrengthNormal );
QVERIFY(keyn.length() >= 2322);
QVERIFY(keyn.length() > keyl.length());
#ifdef ENABLE_SLOW_TESTS
QSslKey keyh = KeyBuilder::generate( QSsl::Rsa, KeyBuilder::StrengthHigh );
QVERIFY(keyh.length() >= 3248);
QVERIFY(keyh.length() > keyn.length());
QSslKey keyu = KeyBuilder::generate( QSsl::Rsa, KeyBuilder::StrengthUltra );
QVERIFY(keyu.length() >= 15424);
QVERIFY(keyu.length() > keyh.length());
#endif // ENABLE_SLOW_TESTS
}
void tst_KeyBuilder::checkKeyChanges()
{
QSslKey key1 = KeyBuilder::generate( QSsl::Rsa, KeyBuilder::StrengthLow );
QSslKey key2 = KeyBuilder::generate( QSsl::Rsa, KeyBuilder::StrengthLow );
QVERIFY(key1.toPem() != key2.toPem());
}
QTEST_MAIN(tst_KeyBuilder)
#include "tst_keybuilder.moc"

View File

@@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS += auto

View File

@@ -197,8 +197,13 @@ bool QxtSslServer::autoEncrypt() const
/*!
* \reimp
*/
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
void QxtSslServer::incomingConnection(qintptr socketDescriptor)
#else
void QxtSslServer::incomingConnection(int socketDescriptor)
#endif
{
qWarning() << Q_FUNC_INFO << socketDescriptor;
QSslSocket* socket = new QSslSocket(this);
if(socket->setSocketDescriptor(socketDescriptor)) {
socket->setLocalCertificate(qxt_d().localCertificate);

View File

@@ -61,7 +61,11 @@ public:
bool autoEncrypt() const;
protected:
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
virtual void incomingConnection(qintptr socketDescriptor);
#else
virtual void incomingConnection(int socketDescriptor);
#endif
private:
QXT_DECLARE_PRIVATE(QxtSslServer)