commit c663e43e7172bb80a8fb779e4dc74f579a60ec45 Author: Darrell Anderson Date: Tue Apr 17 19:51:44 2012 -0500 Added tqca package to the sources tree. This module is from the original qca-1.0 sources with the TQt layer added. This resolves bug report 817. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + + Copyright (C) + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..8dd3409 --- /dev/null +++ b/INSTALL @@ -0,0 +1,12 @@ +Installing QCA +-------------- + +Installation should be straightforward: + + ./configure + make + make install + +NOTE: You may also need to run '/sbin/ldconfig' or a similar tool to + get the new library files recognized by the system. If you are + using Linux, just run it for good measure. diff --git a/README b/README new file mode 100644 index 0000000..b909bc3 --- /dev/null +++ b/README @@ -0,0 +1,29 @@ +Qt Cryptographic Architecture +----------------------------- +Version: API v1.0, Plugin v1 +Author: Justin Karneges +Date: September 10th 2003 + +This library provides an easy API for the following features: + + SSL/TLS + X509 + SASL + RSA + Hashing (SHA1, MD5) + Ciphers (BlowFish, 3DES, AES) + +Functionality is supplied via plugins. This is useful for avoiding +dependence on a particular crypto library and makes upgrading easier, +as there is no need to recompile your application when adding or +upgrading a crypto plugin. Also, by pushing crypto functionality into +plugins, your application is free of legal issues, such as export +regulation. + +And of course, you get a very simple crypto API for Qt, where you can +do things like: + + TQString hash = QCA::SHA1::hashToString(blockOfData); + +Have fun! + diff --git a/TODO b/TODO new file mode 100644 index 0000000..bc8247e --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +* plugins: thread safety ? + +* dsa +* diffie-hellman +* entropy + diff --git a/configure b/configure new file mode 100755 index 0000000..111a180 --- /dev/null +++ b/configure @@ -0,0 +1,492 @@ +#!/bin/sh + +show_usage() { +cat <$1/modules.cpp <$1/modules_new.cpp <$1/conf.cpp < +#include +#include +#include +#include +#include +#include +#include +#include + +class Conf; + +class ConfObj +{ +public: + ConfObj(Conf *c); + virtual ~ConfObj(); + + virtual TQString name() const=0; + virtual TQString shortname() const=0; + virtual bool exec()=0; + + Conf *conf; + bool required; + bool disabled; +}; + +typedef TQPtrList ConfObjList; +typedef TQPtrListIterator ConfObjListIt; + +class Conf +{ +public: + Conf() : vars(17) + { + list.setAutoDelete(true); + vars.setAutoDelete(true); + + vars.insert("QMAKE_INCDIR_X11", new TQString(X11_INC)); + vars.insert("QMAKE_LIBDIR_X11", new TQString(X11_LIBDIR)); + vars.insert("QMAKE_LIBS_X11", new TQString(X11_LIB)); + vars.insert("QMAKE_CC", new TQString(CC)); + } + + ~Conf() + { + } + + void added(ConfObj *o) + { + list.append(o); + } + + TQString getenv(const TQString &var) + { + char *p = ::getenv(var.latin1()); + if(!p) + return TQString::null; + return TQString(p); + } + + bool exec() + { + ConfObjListIt it(list); + for(ConfObj *o; (o = it.current()); ++it) { + // if this was a disabled-by-default option, check if it was enabled + if(o->disabled) { + TQString v = TQString("QC_ENABLE_") + o->shortname(); + if(getenv(v) != "Y") + continue; + } + // and the opposite? + else { + TQString v = TQString("QC_DISABLE_") + o->shortname(); + if(getenv(v) == "Y") + continue; + } + + printf("Checking for %s ...", o->name().latin1()); + fflush(stdout); + bool ok = o->exec(); + if(ok) + printf(" yes\n"); + else + printf(" no\n"); + if(!ok && o->required) { + printf("\nError: need %s!\n", o->name().latin1()); + return false; + } + } + return true; + } + + const TQString & qvar(const TQString &s) + { + TQString *p = vars.find(s); + if(p) + return *p; + else + return blank; + } + + TQString expandIncludes(const TQString &inc) + { + return TQString("-I") + inc; + } + + TQString expandLibs(const TQString &lib) + { + return TQString("-L") + lib; + } + + int doCommand(const TQString &s) + { + //printf("[%s]\n", s.latin1()); + int r = system((s + " 1>/dev/null 2>/dev/null").latin1()); + //printf("returned: %d\n", r); + return r; + } + + bool doCompileAndLink(const TQString &filedata, const TQString &flags, int *retcode=0) + { + TQDir dir("."); + TQString fname = "atest.c"; + TQString out = "atest"; + TQFile f(fname); + TQCString cs = filedata.latin1(); + if(!f.open(IO_WriteOnly | IO_Truncate)) + return false; + f.writeBlock(cs.data(), cs.length()); + f.close(); + + TQString str = qvar("QMAKE_CC") + ' ' + fname + " -o " + out + ' ' + flags; + int r = doCommand(str); + if(r == 0 && retcode) + *retcode = doCommand(TQString("./") + out); + dir.remove(fname); + dir.remove(out); + if(r != 0) + return false; + return true; + } + + bool checkHeader(const TQString &path, const TQString &h) + { + TQFileInfo fi(path + '/' + h); + if(fi.exists()) + return true; + return false; + } + + bool findHeader(const TQString &h, const TQStringList &ext, TQString *inc) + { + if(checkHeader("/usr/include", h)) { + *inc = ""; + return true; + } + TQStringList dirs; + dirs += "/usr/local/include"; + dirs += ext; + for(TQStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) { + if(checkHeader(*it, h)) { + *inc = *it; + return true; + } + } + return false; + } + + bool checkLibrary(const TQString &path, const TQString &name) + { + TQString str = + "int main()\n" + "{\n" + " return 0;\n" + "}\n"; + + TQString extra; + if(!path.isEmpty()) + extra += TQString("-L") + path + ' '; + extra += TQString("-l") + name; + if(!doCompileAndLink(str, extra)) + return false; + return true; + } + + bool findLibrary(const TQString &name, TQString *lib) + { + if(checkLibrary("", name)) { + *lib = ""; + return true; + } + if(checkLibrary("/usr/local/lib", name)) { + *lib = "/usr/local/lib"; + return true; + } + return false; + } + + void addDefine(const TQString &str) + { + if(DEFINES.isEmpty()) + DEFINES = str; + else + DEFINES += TQString(" ") + str; + } + + void addLib(const TQString &str) + { + if(LIBS.isEmpty()) + LIBS = str; + else + LIBS += TQString(" ") + str; + } + + void addIncludePath(const TQString &str) + { + if(INCLUDEPATH.isEmpty()) + INCLUDEPATH = str; + else + INCLUDEPATH += TQString(" ") + str; + } + + void addExtra(const TQString &str) + { + extra += str + '\n'; + } + + TQString DEFINES; + TQString INCLUDEPATH; + TQString LIBS; + TQString extra; + +private: + ConfObjList list; + TQDict vars; + TQString blank; +}; + +ConfObj::ConfObj(Conf *c) +{ + conf = c; + conf->added(this); + required = false; + disabled = false; +} + +ConfObj::~ConfObj() +{ +} + +#include"modules.cpp" + +//---------------------------------------------------------------------------- +// main +//---------------------------------------------------------------------------- +int main() +{ + Conf *conf = new Conf; + ConfObj *o; + o = 0; +#include"modules_new.cpp" + + printf("ok\n"); + bool success = false; + if(conf->exec()) { + TQFile f("conf.pri"); + if(!f.open(IO_WriteOnly | IO_Truncate)) { + printf("Error writing %s\n", f.name().latin1()); + return 1; + } + + TQString str; + str += "# qconf\n"; + str += "QT_PATH_PLUGINS = " + TQString(tqInstallPathPlugins()) + '\n'; + if(!conf->DEFINES.isEmpty()) + str += "DEFINES += " + conf->DEFINES + '\n'; + if(!conf->INCLUDEPATH.isEmpty()) + str += "INCLUDEPATH += " + conf->INCLUDEPATH + '\n'; + if(!conf->LIBS.isEmpty()) + str += "LIBS += " + conf->LIBS + '\n'; + if(!conf->extra.isEmpty()) + str += conf->extra; + str += '\n'; + + char *p = getenv("BINDIR"); + if(p) { + str += TQString("target.path = ") + p + '\n'; + str += "INSTALLS += target\n"; + } + + TQCString cs = str.latin1(); + f.writeBlock(cs.data(), cs.length()); + f.close(); + success = true; + } + delete conf; + + if(success) + return 0; + else + return 1; +} + +EOT +cat >$1/conf.pro </dev/null + QTDIR=$QTDIR make clean >/dev/null 2>&1 + QTDIR=$QTDIR make >../conf.log 2>&1 +) + +if [ "$?" != "0" ]; then + rm -rf .qconftemp + echo fail + echo + echo "There was an error compiling 'conf'. Be sure you have a proper" + echo "TQt 3.x Multithreaded (MT) build environment set up." + if [ ! -f "$QTDIR/lib/libtqt-mt.so.3" ]; then + echo + echo "One possible reason is that you don't have" + echo "libtqt-mt.so.3 installed in $QTDIR/lib/." + fi + echo + exit 1; +fi + +.qconftemp/conf +ret="$?" +if [ "$ret" = "1" ]; then + rm -rf .qconftemp + echo + exit 1; +else + if [ "$ret" != "0" ]; then + rm -rf .qconftemp + echo fail + echo + echo Unexpected error launching 'conf' + echo + exit 1; + fi +fi +rm -rf .qconftemp + +if [ -x "./qcextra" ]; then + ./qcextra +fi +# run qmake +$qm qca.pro +if [ "$?" != "0" ]; then + echo + exit 1; +fi +cat >Makefile.tmp <> Makefile.tmp +rm -f Makefile +cp -f Makefile.tmp Makefile +rm -f Makefile.tmp + +echo +echo Good, your configure finished. Now run \'make\'. +echo diff --git a/examples/certtest/certtest.cpp b/examples/certtest/certtest.cpp new file mode 100644 index 0000000..db82993 --- /dev/null +++ b/examples/certtest/certtest.cpp @@ -0,0 +1,65 @@ +#include +#include +#include"base64.h" +#include"qca.h" + +TQCA::Cert readCertXml(const TQDomElement &e) +{ + TQCA::Cert cert; + // there should be one child data tag + TQDomElement data = e.elementsByTagName("data").item(0).toElement(); + if(!data.isNull()) + cert.fromDER(Base64::stringToArray(data.text())); + return cert; +} + +void showCertInfo(const TQCA::Cert &cert) +{ + printf(" CN: %s\n", cert.subject()["CN"].latin1()); + printf(" Valid from: %s, until %s\n", + cert.notBefore().toString().latin1(), + cert.notAfter().toString().latin1()); + printf(" PEM:\n%s\n", cert.toPEM().latin1()); +} + +int main() +{ + if(!TQCA::isSupported(TQCA::CAP_X509)) { + printf("X509 not supported!\n"); + return 1; + } + + // open the Psi rootcerts file + TQFile f("/usr/local/share/psi/certs/rootcert.xml"); + if(!f.open(IO_ReadOnly)) { + printf("unable to open %s\n", f.name().latin1()); + return 1; + } + TQDomDocument doc; + doc.setContent(&f); + f.close(); + + TQDomElement base = doc.documentElement(); + if(base.tagName() != "store") { + printf("wrong format of %s\n", f.name().latin1()); + return 1; + } + TQDomNodeList cl = base.elementsByTagName("certificate"); + if(cl.count() == 0) { + printf("no certs found in %s\n", f.name().latin1()); + return 1; + } + + for(int n = 0; n < (int)cl.count(); ++n) { + printf("-- Cert %d --\n", n); + TQCA::Cert cert = readCertXml(cl.item(n).toElement()); + if(cert.isNull()) { + printf("error reading cert\n"); + continue; + } + showCertInfo(cert); + } + + return 0; +} + diff --git a/examples/certtest/certtest.pro b/examples/certtest/certtest.pro new file mode 100644 index 0000000..75d4141 --- /dev/null +++ b/examples/certtest/certtest.pro @@ -0,0 +1,8 @@ +TEMPLATE = app +CONFIG += thread console +TARGET = certtest + +INCLUDEPATH += ../common +HEADERS += ../common/base64.h +SOURCES += ../common/base64.cpp certtest.cpp +include(../examples.pri) diff --git a/examples/ciphertest/ciphertest.cpp b/examples/ciphertest/ciphertest.cpp new file mode 100644 index 0000000..3f2107e --- /dev/null +++ b/examples/ciphertest/ciphertest.cpp @@ -0,0 +1,89 @@ +#include"qca.h" +#include + +static TQCString arrayToCString(const TQByteArray &); +static TQByteArray cstringToArray(const TQCString &); +static void doDynTest(TQCA::Cipher *c, const TQString &name, const TQCString &cs); + +int main(int argc, char **argv) +{ + TQCA::init(); + TQCString cs = (argc >= 2) ? argv[1] : "hello"; + + // AES128 test + if(!TQCA::isSupported(TQCA::CAP_AES128)) + printf("AES128 not supported!\n"); + else { + // encrypt + TQByteArray key = TQCA::AES128::generateKey(); + TQByteArray iv = TQCA::AES128::generateIV(); + printf("aes128:key:%s\n", TQCA::arrayToHex(key).latin1()); + printf("aes128:iv:%s\n", TQCA::arrayToHex(iv).latin1()); + TQCA::AES128 c(TQCA::Encrypt, TQCA::CBC, key, iv); + c.update(cstringToArray(cs)); + TQByteArray f = c.final(); + TQString result = TQCA::arrayToHex(f); + printf(">aes128(\"%s\") = [%s]\n", cs.data(), result.latin1()); + + // decrypt + TQCA::AES128 d(TQCA::Decrypt, TQCA::CBC, key, iv); + d.update(f); + TQCString dec = arrayToCString(d.final()); + printf("dyn_generateKey(); + TQByteArray iv = c->dyn_generateIV(); + printf("%s:key:%s\n", name.latin1(), TQCA::arrayToHex(key).latin1()); + printf("%s:iv:%s\n", name.latin1(), TQCA::arrayToHex(iv).latin1()); + c->reset(TQCA::Encrypt, TQCA::CBC, key, iv); + c->update(cstringToArray(cs)); + TQByteArray f = c->final(); + TQString result = TQCA::arrayToHex(f); + printf(">%s(\"%s\") = [%s]\n", name.latin1(), cs.data(), result.latin1()); + + // decrypt + c->reset(TQCA::Decrypt, TQCA::CBC, key, iv); + c->update(f); + TQCString dec = arrayToCString(c->final()); + printf("<%s(\"%s\") = [%s]\n", name.latin1(), result.latin1(), dec.data()); + delete c; +} + diff --git a/examples/ciphertest/ciphertest.pro b/examples/ciphertest/ciphertest.pro new file mode 100644 index 0000000..c4119c5 --- /dev/null +++ b/examples/ciphertest/ciphertest.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +CONFIG += thread console +TARGET = ciphertest + +SOURCES += ciphertest.cpp +include(../examples.pri) diff --git a/examples/common/base64.cpp b/examples/common/base64.cpp new file mode 100644 index 0000000..5938680 --- /dev/null +++ b/examples/common/base64.cpp @@ -0,0 +1,173 @@ +/* + * base64.cpp - Base64 converting functions + * Copyright (C) 2003 Justin Karneges + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include"base64.h" + +//! \class Base64 base64.h +//! \brief Base64 conversion functions. +//! +//! Converts Base64 data between arrays and strings. +//! +//! \code +//! #include "base64.h" +//! +//! ... +//! +//! // encode a block of data into base64 +//! TQByteArray block(1024); +//! TQByteArray enc = Base64::encode(block); +//! +//! \endcode + +//! +//! Encodes array \a s and returns the result. +TQByteArray Base64::encode(const TQByteArray &s) +{ + int i; + int len = s.size(); + char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + int a, b, c; + + TQByteArray p((len+2)/3*4); + int at = 0; + for( i = 0; i < len; i += 3 ) { + a = ((unsigned char)s[i] & 3) << 4; + if(i + 1 < len) { + a += (unsigned char)s[i + 1] >> 4; + b = ((unsigned char)s[i + 1] & 0xF) << 2; + if(i + 2 < len) { + b += (unsigned char)s[i + 2] >> 6; + c = (unsigned char)s[i + 2] & 0x3F; + } + else + c = 64; + } + else + b = c = 64; + + p[at++] = tbl[(unsigned char)s[i] >> 2]; + p[at++] = tbl[a]; + p[at++] = tbl[b]; + p[at++] = tbl[c]; + } + return p; +} + +//! +//! Decodes array \a s and returns the result. +TQByteArray Base64::decode(const TQByteArray &s) +{ + // return value + TQByteArray p; + + // -1 specifies invalid + // 64 specifies eof + // everything else specifies data + + char tbl[] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, + 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,64,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, + 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, + -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, + 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + }; + + // this should be a multiple of 4 + int len = s.size(); + + if(len % 4) + return p; + + p.resize(len / 4 * 3); + + int i; + int at = 0; + + int a, b, c, d; + c = d = 0; + + for( i = 0; i < len; i += 4 ) { + a = tbl[(int)s[i]]; + b = tbl[(int)s[i + 1]]; + c = tbl[(int)s[i + 2]]; + d = tbl[(int)s[i + 3]]; + if((a == 64 || b == 64) || (a < 0 || b < 0 || c < 0 || d < 0)) { + p.resize(0); + return p; + } + p[at++] = ((a & 0x3F) << 2) | ((b >> 4) & 0x03); + p[at++] = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F); + p[at++] = ((c & 0x03) << 6) | ((d >> 0) & 0x3F); + } + + if(c & 64) + p.resize(at - 2); + else if(d & 64) + p.resize(at - 1); + + return p; +} + +//! +//! Encodes array \a a and returns the result as a string. +TQString Base64::arrayToString(const TQByteArray &a) +{ + TQByteArray b = encode(a); + TQCString c; + c.resize(b.size()+1); + memcpy(c.data(), b.data(), b.size()); + return TQString::fromLatin1(c); +} + +//! +//! Decodes string \a s and returns the result as an array. +TQByteArray Base64::stringToArray(const TQString &s) +{ + if(s.isEmpty()) + return TQByteArray(); + const char *c = s.latin1(); + int len = strlen(c); + TQByteArray b(len); + memcpy(b.data(), c, len); + TQByteArray a = decode(b); + return a; +} + +//! +//! Encodes string \a s and returns the result as a string. +TQString Base64::encodeString(const TQString &s) +{ + TQCString c = s.utf8(); + int len = c.length(); + TQByteArray b(len); + memcpy(b.data(), c.data(), len); + return arrayToString(b); +} diff --git a/examples/common/base64.h b/examples/common/base64.h new file mode 100644 index 0000000..93c6023 --- /dev/null +++ b/examples/common/base64.h @@ -0,0 +1,36 @@ +/* + * base64.h - Base64 converting functions + * Copyright (C) 2003 Justin Karneges + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef CS_BASE64_H +#define CS_BASE64_H + +#include + +class Base64 +{ +public: + static TQByteArray encode(const TQByteArray &); + static TQByteArray decode(const TQByteArray &); + static TQString arrayToString(const TQByteArray &); + static TQByteArray stringToArray(const TQString &); + static TQString encodeString(const TQString &); +}; + +#endif diff --git a/examples/examples.pri b/examples/examples.pri new file mode 100644 index 0000000..b1c4f91 --- /dev/null +++ b/examples/examples.pri @@ -0,0 +1,7 @@ +# change/remove these entries, depending on the installation prefix +INCLUDEPATH += /usr/local/include +LIBS += -L/usr/local/lib + +# link +LIBS += -lqca + diff --git a/examples/examples.pro b/examples/examples.pro new file mode 100644 index 0000000..457b282 --- /dev/null +++ b/examples/examples.pro @@ -0,0 +1,11 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + hashtest \ + ciphertest \ + rsatest \ + certtest \ + ssltest \ + sslservtest \ + sasltest + diff --git a/examples/hashtest/hashtest.cpp b/examples/hashtest/hashtest.cpp new file mode 100644 index 0000000..917c396 --- /dev/null +++ b/examples/hashtest/hashtest.cpp @@ -0,0 +1,25 @@ +#include"qca.h" +#include + +int main(int argc, char **argv) +{ + TQCA::init(); + TQCString cs = (argc >= 2) ? argv[1] : "hello"; + + if(!TQCA::isSupported(TQCA::CAP_SHA1)) + printf("SHA1 not supported!\n"); + else { + TQString result = TQCA::SHA1::hashToString(cs); + printf("sha1(\"%s\") = [%s]\n", cs.data(), result.latin1()); + } + + if(!TQCA::isSupported(TQCA::CAP_MD5)) + printf("MD5 not supported!\n"); + else { + TQString result = TQCA::MD5::hashToString(cs); + printf("md5(\"%s\") = [%s]\n", cs.data(), result.latin1()); + } + + return 0; +} + diff --git a/examples/hashtest/hashtest.pro b/examples/hashtest/hashtest.pro new file mode 100644 index 0000000..d642131 --- /dev/null +++ b/examples/hashtest/hashtest.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +CONFIG += thread console +TARGET = hashtest + +SOURCES += hashtest.cpp +include(../examples.pri) diff --git a/examples/rsatest/rsatest.cpp b/examples/rsatest/rsatest.cpp new file mode 100644 index 0000000..bd513fd --- /dev/null +++ b/examples/rsatest/rsatest.cpp @@ -0,0 +1,86 @@ +#include +#include +#include"qca.h" +#include + +//#define USE_FILE + +TQCA::RSAKey readKeyFile(const TQString &name) +{ + TQCA::RSAKey k; + TQFile f(name); + if(!f.open(IO_ReadOnly)) { + printf("Unable to open %s\n", name.latin1()); + return k; + } + TQByteArray der = f.readAll(); + f.close(); + printf("Read %s [%d bytes]\n", name.latin1(), der.size()); + + if(!k.fromDER(der)) { + printf("%s: Error importing DER format.\n", name.latin1()); + return k; + } + char *yes = "yes"; + char *no = "no"; + printf("Successfully imported %s (enc=%s, dec=%s)\n", + name.latin1(), + k.havePublic() ? yes : no, + k.havePrivate() ? yes : no); + + printf("Converting to DER: %d bytes\n", k.toDER().size()); + printf("Converting to PEM:\n%s\n", k.toPEM().latin1()); + return k; +} + +int main(int argc, char **argv) +{ + TQCA::init(); + TQCString cs = (argc >= 2) ? argv[1] : "hello"; + + if(!TQCA::isSupported(TQCA::CAP_RSA)) + printf("RSA not supported!\n"); + else { +#ifdef USE_FILE + TQCA::RSAKey pubkey = readKeyFile("keypublic.der"); + if(pubkey.isNull()) + return 1; + TQCA::RSAKey seckey = readKeyFile("keyprivate.der"); + if(seckey.isNull()) + return 1; +#else + TQCA::RSAKey seckey = TQCA::RSA::generateKey(1024); + if(seckey.isNull()) + return 1; + TQCA::RSAKey pubkey = seckey; +#endif + // encrypt some data + TQByteArray a(cs.length()); + memcpy(a.data(), cs.data(), a.size()); + + TQCA::RSA op; + op.setKey(pubkey); + TQByteArray result; + if(!op.encrypt(a, &result)) { + printf("Error encrypting.\n"); + return 1; + } + TQString rstr = TQCA::arrayToHex(result); + printf(">rsa(\"%s\") = [%s]\n", cs.data(), rstr.latin1()); + + // now decrypt it + op.setKey(seckey); + TQByteArray dec; + if(!op.decrypt(result, &dec)) { + printf("Error decrypting.\n"); + return 1; + } + TQCString dstr; + dstr.resize(dec.size()+1); + memcpy(dstr.data(), dec.data(), dec.size()); + printf(" +#include +#include +#include +#include + +#ifdef Q_OS_UNIX +#include +#endif + +#include"base64.h" +#include"qca.h" + +#define PROTO_NAME "foo" +#define PROTO_PORT 8001 + +static TQString prompt(const TQString &s) +{ + printf("* %s ", s.latin1()); + fflush(stdout); + char line[256]; + fgets(line, 255, stdin); + TQString result = line; + if(result[result.length()-1] == '\n') + result.truncate(result.length()-1); + return result; +} + +class ClientTest : public TQObject +{ + Q_OBJECT +public: + ClientTest() + { + sock = new TQSocket; + connect(sock, SIGNAL(connected()), SLOT(sock_connected())); + connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); + connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); + connect(sock, SIGNAL(error(int)), SLOT(sock_error(int))); + + sasl = new QCA::SASL; + connect(sasl, SIGNAL(clientFirstStep(const TQString &, const TQByteArray *)), SLOT(sasl_clientFirstStep(const TQString &, const TQByteArray *))); + connect(sasl, SIGNAL(nextStep(const TQByteArray &)), SLOT(sasl_nextStep(const TQByteArray &))); + connect(sasl, SIGNAL(needParams(bool, bool, bool, bool)), SLOT(sasl_needParams(bool, bool, bool, bool))); + connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated())); + connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead())); + connect(sasl, SIGNAL(readyReadOutgoing(int)), SLOT(sasl_readyReadOutgoing(int))); + connect(sasl, SIGNAL(error(int)), SLOT(sasl_error(int))); + } + + ~ClientTest() + { + delete sock; + delete sasl; + } + + void start(const TQString &_host, int port, const TQString &user="", const TQString &pass="") + { + mode = 0; + host = _host; + sock->connectToHost(host, port); + sasl->setMinimumSSF(0); + sasl->setMaximumSSF(256); + + if(!user.isEmpty()) { + sasl->setUsername(user); + sasl->setAuthzid(user); + } + if(!pass.isEmpty()) + sasl->setPassword(pass); + } + +signals: + void quit(); + +private slots: + void sock_connected() + { + printf("Connected to server. Awaiting mechanism list...\n"); + } + + void sock_connectionClosed() + { + printf("Connection closed by peer.\n"); + quit(); + } + + void sock_error(int x) + { + TQString s; + if(x == TQSocket::ErrConnectionRefused) + s = "connection refused or timed out"; + else if(x == TQSocket::ErrHostNotFound) + s = "host not found"; + else if(x == TQSocket::ErrSocketRead) + s = "read error"; + + printf("Socket error: %s\n", s.latin1()); + quit(); + } + + void sock_readyRead() + { + if(mode == 2) { + int avail = sock->bytesAvailable(); + TQByteArray a(avail); + int n = sock->readBlock(a.data(), a.size()); + a.resize(n); + printf("Read %d bytes\n", a.size()); + sasl->writeIncoming(a); + } + else { + if(sock->canReadLine()) { + TQString line = sock->readLine(); + line.truncate(line.length()-1); // chop the newline + handleLine(line); + } + } + } + + void sasl_clientFirstStep(const TQString &mech, const TQByteArray *clientInit) + { + printf("Choosing mech: %s\n", mech.latin1()); + TQString line = mech; + if(clientInit) { + TQCString cs(clientInit->data(), clientInit->size()+1); + line += ' '; + line += cs; + } + sendLine(line); + } + + void sasl_nextStep(const TQByteArray &stepData) + { + TQCString cs(stepData.data(), stepData.size()+1); + TQString line = "C"; + if(!stepData.isEmpty()) { + line += ','; + line += cs; + } + sendLine(line); + } + + void sasl_needParams(bool user, bool authzid, bool pass, bool realm) + { + TQString username; + if(user || authzid) + username = prompt("Username:"); + if(user) { + sasl->setUsername(username); + } + if(authzid) { + sasl->setAuthzid(username); + } + if(pass) { + sasl->setPassword(prompt("Password (not hidden!) :")); + } + if(realm) { + sasl->setRealm(prompt("Realm:")); + } + sasl->continueAfterParams(); + } + + void sasl_authenticated() + { + printf("SASL success!\n"); + printf("SSF: %d\n", sasl->ssf()); + } + + void sasl_readyRead() + { + TQByteArray a = sasl->read(); + int oldsize = inbuf.size(); + inbuf.resize(oldsize + a.size()); + memcpy(inbuf.data() + oldsize, a.data(), a.size()); + processInbuf(); + } + + void sasl_readyReadOutgoing(int) + { + TQByteArray a = sasl->readOutgoing(); + sock->writeBlock(a.data(), a.size()); + } + + void sasl_error(int) + { + printf("SASL error!\n"); + quit(); + return; + } + +private: + TQSocket *sock; + QCA::SASL *sasl; + int mode; + TQString host; + TQByteArray inbuf; + + void processInbuf() + { + TQStringList list; + for(int n = 0; n < (int)inbuf.size(); ++n) { + if(inbuf[n] == '\n') { + TQCString cs(inbuf.data(), n+1); + char *p = inbuf.data(); + ++n; + int x = inbuf.size() - n; + memmove(p, p + n, x); + inbuf.resize(x); + list += TQString::fromUtf8(cs); + // start over, basically + n = -1; + } + } + + for(TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it) + handleLine(*it); + } + + void handleLine(const TQString &line) + { + printf("Reading: [%s]\n", line.latin1()); + if(mode == 0) { + // first line is the method list + TQStringList mechlist = TQStringList::split(' ', line); + ++mode; + + // kick off the client + sasl->setAllowAnonymous(false); + if(!sasl->startClient(PROTO_NAME, host, mechlist)) { + printf("Error starting client!\n"); + quit(); + } + } + else if(mode == 1) { + TQString type, rest; + int n = line.find(','); + if(n != -1) { + type = line.mid(0, n); + rest = line.mid(n+1); + } + else { + type = line; + rest = ""; + } + + if(type == "C") { + TQCString cs = rest.latin1(); + TQByteArray buf(cs.length()); + memcpy(buf.data(), cs.data(), buf.size()); + sasl->putStep(buf); + } + else if(type == "E") { + printf("Authentication failed.\n"); + quit(); + return; + } + else if(type == "A") { + printf("Authentication success.\n"); + ++mode; + sock_readyRead(); // any extra data? + return; + } + else { + printf("Bad format from peer, closing.\n"); + quit(); + return; + } + } + else { + } + } + + void sendLine(const TQString &line) + { + printf("Writing: {%s}\n", line.latin1()); + TQString s = line + '\n'; + TQCString cs = s.latin1(); + if(mode == 2) { + TQByteArray a(cs.length()); + memcpy(a.data(), cs.data(), a.size()); + sasl->write(a); + } + else + sock->writeBlock(cs.data(), cs.length()); + } +}; + +class ServerTest : public QServerSocket +{ + Q_OBJECT +public: + ServerTest(const TQString &_str, int _port) : QServerSocket(_port), port(_port) + { + sock = 0; + sasl = 0; + realm = TQString::null; + str = _str; + } + + ~ServerTest() + { + delete sock; + delete sasl; + } + + void start() + { + if(!ok()) { + printf("Error binding to port %d!\n", port); + TTQTimer::singleShot(0, this, SIGNAL(quit())); + return; + } + char myhostname[256]; + int r = gethostname(myhostname, sizeof(myhostname)-1); + if(r == -1) { + printf("Error getting hostname!\n"); + TTQTimer::singleShot(0, this, SIGNAL(quit())); + return; + } + host = myhostname; + printf("Listening on %s:%d ...\n", host.latin1(), port); + } + + void newConnection(int s) + { + // Note: only 1 connection supported at a time in this example! + if(sock) { + TQSocket tmp; + tmp.setSocket(s); + printf("Connection ignored, already have one active.\n"); + return; + } + + printf("Connection received! Starting SASL handshake...\n"); + + sock = new TQSocket; + connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); + connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); + connect(sock, SIGNAL(error(int)), SLOT(sock_error(int))); + connect(sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int))); + + sasl = new QCA::SASL; + connect(sasl, SIGNAL(authCheck(const TQString &, const TQString &)), SLOT(sasl_authCheck(const TQString &, const TQString &))); + connect(sasl, SIGNAL(nextStep(const TQByteArray &)), SLOT(sasl_nextStep(const TQByteArray &))); + connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated())); + connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead())); + connect(sasl, SIGNAL(readyReadOutgoing(int)), SLOT(sasl_readyReadOutgoing(int))); + connect(sasl, SIGNAL(error(int)), SLOT(sasl_error(int))); + + sock->setSocket(s); + mode = 0; + inbuf.resize(0); + + sasl->setMinimumSSF(0); + sasl->setMaximumSSF(256); + + TQStringList mechlist; + if(!sasl->startServer(PROTO_NAME, host, realm, &mechlist)) { + printf("Error starting server!\n"); + quit(); + } + TQString str; + bool first = true; + for(TQStringList::ConstIterator it = mechlist.begin(); it != mechlist.end(); ++it) { + if(!first) + str += ' '; + str += *it; + first = false; + } + sendLine(str); + } + +signals: + void quit(); + +private slots: + void sock_connectionClosed() + { + printf("Connection closed by peer.\n"); + close(); + } + + void sock_error(int x) + { + TQString s; + if(x == TQSocket::ErrConnectionRefused) + s = "connection refused or timed out"; + else if(x == TQSocket::ErrHostNotFound) + s = "host not found"; + else if(x == TQSocket::ErrSocketRead) + s = "read error"; + + printf("Socket error: %s\n", s.latin1()); + close(); + } + + void sock_readyRead() + { + if(sock->canReadLine()) { + TQString line = sock->readLine(); + line.truncate(line.length()-1); // chop the newline + handleLine(line); + } + } + + void sock_bytesWritten(int x) + { + if(mode == 2) { + toWrite -= x; + if(toWrite <= 0) { + printf("Sent, closing.\n"); + close(); + } + } + } + + void sasl_nextStep(const TQByteArray &stepData) + { + TQCString cs(stepData.data(), stepData.size()+1); + TQString line = "C"; + if(!stepData.isEmpty()) { + line += ','; + line += cs; + } + sendLine(line); + } + + void sasl_authCheck(const TQString &user, const TQString &authzid) + { + printf("AuthCheck: User: [%s], Authzid: [%s]\n", user.latin1(), authzid.latin1()); + sasl->continueAfterAuthCheck(); + } + + void sasl_authenticated() + { + sendLine("A"); + printf("Authentication success.\n"); + ++mode; + printf("SSF: %d\n", sasl->ssf()); + sendLine(str); + } + + void sasl_readyRead() + { + TQByteArray a = sasl->read(); + int oldsize = inbuf.size(); + inbuf.resize(oldsize + a.size()); + memcpy(inbuf.data() + oldsize, a.data(), a.size()); + processInbuf(); + } + + void sasl_readyReadOutgoing(int) + { + TQByteArray a = sasl->readOutgoing(); + toWrite = a.size(); + sock->writeBlock(a.data(), a.size()); + } + + void sasl_error(int x) + { + if(x == QCA::SASL::ErrAuth) { + sendLine("E"); + printf("Authentication failed.\n"); + close(); + } + else { + printf("SASL security layer error!\n"); + close(); + } + } + +private: + TQSocket *sock; + QCA::SASL *sasl; + TQString host, realm; + int port; + int mode; + TQString str; + TQByteArray inbuf; + int toWrite; + + void processInbuf() + { + } + + void handleLine(const TQString &line) + { + printf("Reading: [%s]\n", line.latin1()); + if(mode == 0) { + int n = line.find(' '); + if(n != -1) { + TQString mech = line.mid(0, n); + TQCString cs = line.mid(n+1).latin1(); + TQByteArray clientInit(cs.length()); + memcpy(clientInit.data(), cs.data(), clientInit.size()); + sasl->putServerFirstStep(mech, clientInit); + } + else + sasl->putServerFirstStep(line); + ++mode; + } + else if(mode == 1) { + TQString type, rest; + int n = line.find(','); + if(n != -1) { + type = line.mid(0, n); + rest = line.mid(n+1); + } + else { + type = line; + rest = ""; + } + + if(type == "C") { + TQCString cs = rest.latin1(); + TQByteArray buf(cs.length()); + memcpy(buf.data(), cs.data(), buf.size()); + sasl->putStep(buf); + } + else { + printf("Bad format from peer, closing.\n"); + close(); + return; + } + } + } + + void sendLine(const TQString &line) + { + printf("Writing: {%s}\n", line.latin1()); + TQString s = line + '\n'; + TQCString cs = s.latin1(); + if(mode == 2) { + TQByteArray a(cs.length()); + memcpy(a.data(), cs.data(), a.size()); + sasl->write(a); + } + else + sock->writeBlock(cs.data(), cs.length()); + } + + void close() + { + sock->deleteLater(); + sock = 0; + delete sasl; + sasl = 0; + } +}; + +#include"sasltest.moc" + +void usage() +{ + printf("usage: sasltest client [host] [user] [pass]\n"); + printf(" sasltest server [string]\n\n"); +} + +int main(int argc, char **argv) +{ + TQApplication app(argc, argv, false); + + TQString host, user, pass; + TQString str = "Hello, World"; + bool server; + if(argc < 2) { + usage(); + return 0; + } + TQString arg = argv[1]; + if(arg == "client") { + if(argc < 3) { + usage(); + return 0; + } + host = argv[2]; + if(argc >= 4) + user = argv[3]; + if(argc >= 5) + pass = argv[4]; + server = false; + } + else if(arg == "server") { + if(argc >= 3) + str = argv[2]; + server = true; + } + else { + usage(); + return 0; + } + + if(!QCA::isSupported(QCA::CAP_SASL)) { + printf("SASL not supported!\n"); + return 1; + } + + if(server) { + ServerTest *s = new ServerTest(str, PROTO_PORT); + TQObject::connect(s, SIGNAL(quit()), &app, SLOT(quit())); + s->start(); + app.exec(); + delete s; + } + else { + ClientTest *c = new ClientTest; + TQObject::connect(c, SIGNAL(quit()), &app, SLOT(quit())); + c->start(host, PROTO_PORT, user, pass); + app.exec(); + delete c; + } + + return 0; +} diff --git a/examples/sasltest/sasltest.pro b/examples/sasltest/sasltest.pro new file mode 100644 index 0000000..f7d1c98 --- /dev/null +++ b/examples/sasltest/sasltest.pro @@ -0,0 +1,8 @@ +TEMPLATE = app +CONFIG += thread console +TARGET = sasltest + +INCLUDEPATH += ../common +HEADERS += ../common/base64.h +SOURCES += ../common/base64.cpp sasltest.cpp +include(../examples.pri) diff --git a/examples/sslservtest/sslservtest.cpp b/examples/sslservtest/sslservtest.cpp new file mode 100644 index 0000000..384558f --- /dev/null +++ b/examples/sslservtest/sslservtest.cpp @@ -0,0 +1,294 @@ +#include +#include +#include +#include +#include +#include +#include"qca.h" + +char pemdata_cert[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIDbjCCAtegAwIBAgIBADANBgkqhkiG9w0BAQQFADCBhzELMAkGA1UEBhMCVVMx\n" + "EzARBgNVBAgTCkNhbGlmb3JuaWExDzANBgNVBAcTBklydmluZTEYMBYGA1UEChMP\n" + "RXhhbXBsZSBDb21wYW55MRQwEgYDVQQDEwtleGFtcGxlLmNvbTEiMCAGCSqGSIb3\n" + "DQEJARYTZXhhbXBsZUBleGFtcGxlLmNvbTAeFw0wMzA3MjQwNzMwMDBaFw0wMzA4\n" + "MjMwNzMwMDBaMIGHMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEP\n" + "MA0GA1UEBxMGSXJ2aW5lMRgwFgYDVQQKEw9FeGFtcGxlIENvbXBhbnkxFDASBgNV\n" + "BAMTC2V4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu\n" + "Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCobzCF268K2sRp473gvBTT\n" + "4AgSL1kjeF8N57vxS1P8zWrWMXNs4LuH0NRZmKTajeboy0br8xw+smIy3AbaKAwW\n" + "WZToesxebu3m9VeA8dqWyOaUMjoxAcgVYesgVaMpjRe7fcWdJnX1wJoVVPuIcO8m\n" + "a+AAPByfTORbzpSTmXAQAwIDAQABo4HnMIHkMB0GA1UdDgQWBBTvFierzLmmYMq0\n" + "cB/+5rK1bNR56zCBtAYDVR0jBIGsMIGpgBTvFierzLmmYMq0cB/+5rK1bNR566GB\n" + "jaSBijCBhzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDzANBgNV\n" + "BAcTBklydmluZTEYMBYGA1UEChMPRXhhbXBsZSBDb21wYW55MRQwEgYDVQQDEwtl\n" + "eGFtcGxlLmNvbTEiMCAGCSqGSIb3DQEJARYTZXhhbXBsZUBleGFtcGxlLmNvbYIB\n" + "ADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAGqGhXf7xNOnYNtFO7gz\n" + "K6RdZGHFI5q1DAEz4hhNBC9uElh32XGX4wN7giz3zLC8v9icL/W4ff/K5NDfv3Gf\n" + "gQe/+Wo9Be3H3ul6uwPPFnx4+PIOF2a5TW99H9smyxWdNjnFtcUte4al3RszcMWG\n" + "x3iqsWosGtj6F+ridmKoqKLu\n" + "-----END CERTIFICATE-----\n"; + +char pemdata_privkey[] = + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIICXAIBAAKBgQCobzCF268K2sRp473gvBTT4AgSL1kjeF8N57vxS1P8zWrWMXNs\n" + "4LuH0NRZmKTajeboy0br8xw+smIy3AbaKAwWWZToesxebu3m9VeA8dqWyOaUMjox\n" + "AcgVYesgVaMpjRe7fcWdJnX1wJoVVPuIcO8ma+AAPByfTORbzpSTmXAQAwIDAQAB\n" + "AoGAP83u+aYghuIcaWhmM03MLf69z/WztKYSi/fu0BcS977w67bL3MC9CVPoPRB/\n" + "0nLSt/jZIuRzHKUCYfXLerSU7v0oXDTy6GPzWMh/oXIrpF0tYNbwWF7LSq2O2gGZ\n" + "XtA9MSmUNNJaKzQQeXjqdVFOY8A0Pho+k2KByBiCi+ChkcECQQDRUuyX0+PKJtA2\n" + "M36BOTFpy61BAv+JRlXUnHuevOfQWl6NR6YGygqCyH1sWtP1sa9S4wWys3DFH+5A\n" + "DkuAqk7zAkEAzf4eUH2hp5CIMsXH+WpIzKj09oY1it2CAKjVq4rUELf8iXvmGoFl\n" + "000spua4MjHNUYm7LR0QaKesKrMyGZUesQJAL8aLdYPJI+SD9Tr/jqLtIkZ4frQe\n" + "eshw4pvsoyheiHF3zyshO791crAr4EVCx3sMlxB1xnmqLXPCPyCEHxO//QJBAIBY\n" + "IYkjDZJ6ofGIe1UyXJNvfdkPu9J+ut4wU5jjEcgs6mK62J6RGuFxhy2iOQfFMdjo\n" + "yL+OCUg7mDCun7uCxrECQAtSvnLOFMjO5qExRjFtwi+b1rcSekd3Osk/izyRFSzg\n" + "Or+AL56/EKfiogNnFipgaXIbb/xj785Cob6v96XoW1I=\n" + "-----END RSA PRIVATE KEY-----\n"; + +class LayerTracker +{ +public: + struct Item + { + int plain; + int encoded; + }; + + LayerTracker() + { + p = 0; + } + + void reset() + { + p = 0; + list.clear(); + } + + void addPlain(int plain) + { + p += plain; + } + + void specifyEncoded(int encoded, int plain) + { + // can't specify more bytes than we have + if(plain > p) + plain = p; + p -= plain; + Item i; + i.plain = plain; + i.encoded = encoded; + list += i; + } + + int finished(int encoded) + { + int plain = 0; + for(TQValueList::Iterator it = list.begin(); it != list.end();) { + Item &i = *it; + + // not enough? + if(encoded < i.encoded) { + i.encoded -= encoded; + break; + } + + encoded -= i.encoded; + plain += i.plain; + it = list.remove(it); + } + return plain; + } + + int p; + TQValueList list; +}; + +class SecureServerTest : public QServerSocket +{ + Q_OBJECT +public: + enum { Idle, Handshaking, Active, Closing }; + + SecureServerTest(int _port) : QServerSocket(_port), port(_port) + { + sock = new TQSocket; + connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); + connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); + connect(sock, SIGNAL(error(int)), SLOT(sock_error(int))); + connect(sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int))); + + ssl = new QCA::TLS; + connect(ssl, SIGNAL(handshaken()), SLOT(ssl_handshaken())); + connect(ssl, SIGNAL(readyRead()), SLOT(ssl_readyRead())); + connect(ssl, SIGNAL(readyReadOutgoing(int)), SLOT(ssl_readyReadOutgoing(int))); + connect(ssl, SIGNAL(closed()), SLOT(ssl_closed())); + connect(ssl, SIGNAL(error(int)), SLOT(ssl_error(int))); + + cert.fromPEM(pemdata_cert); + privkey.fromPEM(pemdata_privkey); + + mode = Idle; + } + + ~SecureServerTest() + { + delete ssl; + delete sock; + } + + void start() + { + if(cert.isNull() || privkey.isNull()) { + printf("Error loading cert and/or private key!\n"); + TTQTimer::singleShot(0, this, SIGNAL(quit())); + return; + } + if(!ok()) { + printf("Error binding to port %d!\n", port); + TTQTimer::singleShot(0, this, SIGNAL(quit())); + return; + } + printf("Listening on port %d ...\n", port); + } + + void newConnection(int s) + { + // Note: only 1 connection supported at a time in this example! + if(sock->isOpen()) { + TQSocket tmp; + tmp.setSocket(s); + printf("throwing away extra connection\n"); + return; + } + mode = Handshaking; + sock->setSocket(s); + printf("Connection received! Starting TLS handshake...\n"); + ssl->setCertificate(cert, privkey); + ssl->startServer(); + } + +signals: + void quit(); + +private slots: + void sock_readyRead() + { + TQByteArray buf(sock->bytesAvailable()); + int num = sock->readBlock(buf.data(), buf.size()); + if(num < (int)buf.size()) + buf.resize(num); + ssl->writeIncoming(buf); + } + + void sock_connectionClosed() + { + printf("Connection closed.\n"); + } + + void sock_bytesWritten(int x) + { + if(mode == Active && sent) { + int bytes = layer.finished(x); + bytesLeft -= bytes; + + if(bytesLeft == 0) { + mode = Closing; + printf("SSL shutdown\n"); + ssl->close(); + } + } + } + + void sock_error(int) + { + printf("Socket error.\n"); + } + + void ssl_handshaken() + { + printf("Successful SSL handshake. Waiting for newline.\n"); + layer.reset(); + bytesLeft = 0; + sent = false; + mode = Active; + } + + void ssl_readyRead() + { + TQByteArray a = ssl->read(); + TQString str = + "\n" + "Test\n" + "this is only a test\n" + "\n"; + TQCString cs = str.latin1(); + TQByteArray b(cs.length()); + memcpy(b.data(), cs.data(), b.size()); + + printf("Sending test response...\n"); + sent = true; + layer.addPlain(b.size()); + ssl->write(b); + } + + void ssl_readyReadOutgoing(int plainBytes) + { + TQByteArray a = ssl->readOutgoing(); + layer.specifyEncoded(a.size(), plainBytes); + sock->writeBlock(a.data(), a.size()); + } + + void ssl_closed() + { + printf("Closing.\n"); + sock->close(); + } + + void ssl_error(int x) + { + if(x == QCA::TLS::ErrHandshake) { + printf("SSL Handshake Error! Closing.\n"); + sock->close(); + } + else { + printf("SSL Error! Closing.\n"); + sock->close(); + } + } + +private: + int port; + TQSocket *sock; + QCA::TLS *ssl; + QCA::Cert cert; + QCA::RSAKey privkey; + + bool sent; + int mode; + int bytesLeft; + LayerTracker layer; +}; + +#include"sslservtest.moc" + +int main(int argc, char **argv) +{ + TQApplication app(argc, argv, false); + int port = argc > 1 ? TQString(argv[1]).toInt() : 8000; + + if(!QCA::isSupported(QCA::CAP_TLS)) { + printf("TLS not supported!\n"); + return 1; + } + + SecureServerTest *s = new SecureServerTest(port); + TQObject::connect(s, SIGNAL(quit()), &app, SLOT(quit())); + s->start(); + app.exec(); + delete s; + + return 0; +} diff --git a/examples/sslservtest/sslservtest.pro b/examples/sslservtest/sslservtest.pro new file mode 100644 index 0000000..028d5ab --- /dev/null +++ b/examples/sslservtest/sslservtest.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +CONFIG += thread console +TARGET = sslservtest + +SOURCES += sslservtest.cpp +include(../examples.pri) diff --git a/examples/ssltest/ssltest.cpp b/examples/ssltest/ssltest.cpp new file mode 100644 index 0000000..f26f293 --- /dev/null +++ b/examples/ssltest/ssltest.cpp @@ -0,0 +1,276 @@ +#include +#include +#include +#include +#include +#include"base64.h" +#include"qca.h" + +TQCA::Cert readCertXml(const TQDomElement &e) +{ + TQCA::Cert cert; + // there should be one child data tag + TQDomElement data = e.elementsByTagName("data").item(0).toElement(); + if(!data.isNull()) + cert.fromDER(Base64::stringToArray(data.text())); + return cert; +} + +void showCertInfo(const TQCA::Cert &cert) +{ + printf("-- Cert --\n"); + printf(" CN: %s\n", cert.subject()["CN"].latin1()); + printf(" Valid from: %s, until %s\n", + cert.notBefore().toString().latin1(), + cert.notAfter().toString().latin1()); + printf(" PEM:\n%s\n", cert.toPEM().latin1()); +} + +TQPtrList getRootCerts(const TQString &store) +{ + TQPtrList list; + + // open the Psi rootcerts file + TQFile f(store); + if(!f.open(IO_ReadOnly)) { + printf("unable to open %s\n", f.name().latin1()); + return list; + } + TQDomDocument doc; + doc.setContent(&f); + f.close(); + + TQDomElement base = doc.documentElement(); + if(base.tagName() != "store") { + printf("wrong format of %s\n", f.name().latin1()); + return list; + } + TQDomNodeList cl = base.elementsByTagName("certificate"); + if(cl.count() == 0) { + printf("no certs found in %s\n", f.name().latin1()); + return list; + } + + int num = 0; + for(int n = 0; n < (int)cl.count(); ++n) { + TQCA::Cert *cert = new TQCA::Cert(readCertXml(cl.item(n).toElement())); + if(cert->isNull()) { + printf("error reading cert\n"); + delete cert; + continue; + } + + ++num; + list.append(cert); + } + printf("imported %d root certs\n", num); + + return list; +} + +TQString resultToString(int result) +{ + TQString s; + switch(result) { + case TQCA::TLS::NoCert: + s = TQObject::tr("No certificate presented."); + break; + case TQCA::TLS::Valid: + break; + case TQCA::TLS::HostMismatch: + s = TQObject::tr("Hostname mismatch."); + break; + case TQCA::TLS::Rejected: + s = TQObject::tr("Root CA rejects the specified purpose."); + break; + case TQCA::TLS::Untrusted: + s = TQObject::tr("Not trusted for the specified purpose."); + break; + case TQCA::TLS::SignatureFailed: + s = TQObject::tr("Invalid signature."); + break; + case TQCA::TLS::InvalidCA: + s = TQObject::tr("Invalid CA certificate."); + break; + case TQCA::TLS::InvalidPurpose: + s = TQObject::tr("Invalid certificate purpose."); + break; + case TQCA::TLS::SelfSigned: + s = TQObject::tr("Certificate is self-signed."); + break; + case TQCA::TLS::Revoked: + s = TQObject::tr("Certificate has been revoked."); + break; + case TQCA::TLS::PathLengthExceeded: + s = TQObject::tr("Maximum cert chain length exceeded."); + break; + case TQCA::TLS::Expired: + s = TQObject::tr("Certificate has expired."); + break; + case TQCA::TLS::Unknown: + default: + s = TQObject::tr("General validation error."); + break; + } + return s; +} + +class SecureTest : public TQObject +{ + Q_OBJECT +public: + SecureTest() + { + sock = new TQSocket; + connect(sock, SIGNAL(connected()), SLOT(sock_connected())); + connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); + connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); + connect(sock, SIGNAL(error(int)), SLOT(sock_error(int))); + + ssl = new TQCA::TLS; + connect(ssl, SIGNAL(handshaken()), SLOT(ssl_handshaken())); + connect(ssl, SIGNAL(readyRead()), SLOT(ssl_readyRead())); + connect(ssl, SIGNAL(readyReadOutgoing(int)), SLOT(ssl_readyReadOutgoing(int))); + connect(ssl, SIGNAL(closed()), SLOT(ssl_closed())); + connect(ssl, SIGNAL(error(int)), SLOT(ssl_error(int))); + + rootCerts.setAutoDelete(true); + rootCerts = getRootCerts("/usr/local/share/psi/certs/rootcert.xml"); + } + + ~SecureTest() + { + delete ssl; + delete sock; + } + + void start(const TQString &_host) + { + int n = _host.find(':'); + int port; + if(n != -1) { + host = _host.mid(0, n); + port = _host.mid(n+1).toInt(); + } + else { + host = _host; + port = 443; + } + + printf("Trying %s:%d...\n", host.latin1(), port); + sock->connectToHost(host, port); + } + +signals: + void quit(); + +private slots: + void sock_connected() + { + printf("Connected, starting TLS handshake...\n"); + ssl->setCertificateStore(rootCerts); + ssl->startClient(host); + } + + void sock_readyRead() + { + TQByteArray buf(sock->bytesAvailable()); + int num = sock->readBlock(buf.data(), buf.size()); + if(num < (int)buf.size()) + buf.resize(num); + ssl->writeIncoming(buf); + } + + void sock_connectionClosed() + { + printf("\nConnection closed.\n"); + quit(); + } + + void sock_error(int) + { + printf("\nSocket error.\n"); + quit(); + } + + void ssl_handshaken() + { + cert = ssl->peerCertificate(); + int vr = ssl->certificateValidityResult(); + + printf("Successful SSL handshake.\n"); + if(!cert.isNull()) + showCertInfo(cert); + if(vr == TQCA::TLS::Valid) + printf("Valid certificate.\n"); + else + printf("Invalid certificate: %s\n", resultToString(vr).latin1()); + + printf("Let's try a GET request now.\n"); + TQString req = "GET / HTTP/1.0\nHost: " + host + "\n\n"; + TQCString cs = req.latin1(); + TQByteArray buf(cs.length()); + memcpy(buf.data(), cs.data(), buf.size()); + ssl->write(buf); + } + + void ssl_readyRead() + { + TQByteArray a = ssl->read(); + TQCString cs; + cs.resize(a.size()+1); + memcpy(cs.data(), a.data(), a.size()); + printf("%s", cs.data()); + } + + void ssl_readyReadOutgoing(int) + { + TQByteArray a = ssl->readOutgoing(); + sock->writeBlock(a.data(), a.size()); + } + + void ssl_closed() + { + printf("SSL session closed\n"); + } + + void ssl_error(int x) + { + if(x == TQCA::TLS::ErrHandshake) { + printf("SSL Handshake Error!\n"); + quit(); + } + else { + printf("SSL Error!\n"); + quit(); + } + } + +private: + TQString host; + TQSocket *sock; + TQCA::TLS *ssl; + TQCA::Cert cert; + TQPtrList rootCerts; +}; + +#include"ssltest.moc" + +int main(int argc, char **argv) +{ + TQApplication app(argc, argv, false); + TQString host = argc > 1 ? argv[1] : "andbit.net"; + + if(!TQCA::isSupported(TQCA::CAP_TLS)) { + printf("TLS not supported!\n"); + return 1; + } + + SecureTest *s = new SecureTest; + TQObject::connect(s, SIGNAL(quit()), &app, SLOT(quit())); + s->start(host); + app.exec(); + delete s; + + return 0; +} diff --git a/examples/ssltest/ssltest.pro b/examples/ssltest/ssltest.pro new file mode 100644 index 0000000..44ae325 --- /dev/null +++ b/examples/ssltest/ssltest.pro @@ -0,0 +1,8 @@ +TEMPLATE = app +CONFIG += thread console +TARGET = ssltest + +INCLUDEPATH += ../common +HEADERS += ../common/base64.h +SOURCES += ../common/base64.cpp ssltest.cpp +include(../examples.pri) diff --git a/qca.pro b/qca.pro new file mode 100644 index 0000000..1aa5c87 --- /dev/null +++ b/qca.pro @@ -0,0 +1,33 @@ +# qca qmake profile + +TEMPLATE = lib +CONFIG += qt thread release +TARGET = qca + +MOC_DIR = .moc +OBJECTS_DIR = .obj +UI_DIR = .ui + +VER_MAJ = 1 +VER_MIN = 0 + +# make DLL +win32:{ + CONFIG += dll + DEFINES += QCA_MAKEDLL +} + +QCA_CPP = src +INCLUDEPATH += $$QCA_CPP +INCLUDEPATH += /usr/include/tqt + +HEADERS += \ + $$QCA_CPP/qca.h \ + $$QCA_CPP/qcaprovider.h + +SOURCES += \ + $$QCA_CPP/qca.cpp + +include(conf.pri) +include(extra.pri) + diff --git a/qca.qc b/qca.qc new file mode 100644 index 0000000..cbe4cae --- /dev/null +++ b/qca.qc @@ -0,0 +1,5 @@ + + Qt Cryptographic Architecture (QCA) + qca.pro + + diff --git a/qcextra b/qcextra new file mode 100755 index 0000000..c02ba66 --- /dev/null +++ b/qcextra @@ -0,0 +1,13 @@ +#!/bin/sh + +cat >extra.pri < +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include"qcaprovider.h" + +#if defined(Q_OS_WIN32) +#define PLUGIN_EXT "dll" +#elif defined(Q_OS_MAC) +#define PLUGIN_EXT "dylib" +#else +#define PLUGIN_EXT "so" +#endif + +using namespace TQCA; + +class ProviderItem +{ +public: + TQCAProvider *p; + TQString fname; + + static ProviderItem *load(const TQString &fname) + { + TQLibrary *lib = new TQLibrary(fname); + if(!lib->load()) { + delete lib; + return 0; + } + void *s = lib->resolve("createProvider"); + if(!s) { + delete lib; + return 0; + } + TQCAProvider *(*createProvider)() = (TQCAProvider *(*)())s; + TQCAProvider *p = createProvider(); + if(!p) { + delete lib; + return 0; + } + ProviderItem *i = new ProviderItem(lib, p); + i->fname = fname; + return i; + } + + static ProviderItem *fromClass(TQCAProvider *p) + { + ProviderItem *i = new ProviderItem(0, p); + return i; + } + + ~ProviderItem() + { + delete p; + delete lib; + } + + void ensureInit() + { + if(init_done) + return; + init_done = true; + p->init(); + } + +private: + TQLibrary *lib; + bool init_done; + + ProviderItem(TQLibrary *_lib, TQCAProvider *_p) + { + lib = _lib; + p = _p; + init_done = false; + } +}; + +static TQPtrList providerList; +static bool qca_init = false; + +static bool plugin_have(const TQString &fname) +{ + TQPtrListIterator it(providerList); + for(ProviderItem *i; (i = it.current()); ++it) { + if(i->fname == fname) + return true; + } + return false; +} + +static void plugin_scan() +{ + TQStringList dirs = TQApplication::libraryPaths(); + for(TQStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) { + TQDir libpath(*it); + TQDir dir(libpath.filePath("crypto")); + if(!dir.exists()) + continue; + + TQStringList list = dir.entryList(); + for(TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it) { + TQFileInfo fi(dir.filePath(*it)); + if(fi.isDir()) + continue; + if(fi.extension() != PLUGIN_EXT) + continue; + TQString fname = fi.filePath(); + + // don't load the same plugin again! + if(plugin_have(fname)) + continue; + //printf("f=[%s]\n", fname.latin1()); + + ProviderItem *i = ProviderItem::load(fname); + if(!i) + continue; + if(i->p->qcaVersion() != TQCA_PLUGIN_VERSION) { + delete i; + continue; + } + + providerList.append(i); + } + } +} + +static void plugin_addClass(TQCAProvider *p) +{ + ProviderItem *i = ProviderItem::fromClass(p); + providerList.prepend(i); +} + +static void plugin_unloadall() +{ + providerList.clear(); +} + +static int plugin_caps() +{ + int caps = 0; + TQPtrListIterator it(providerList); + for(ProviderItem *i; (i = it.current()); ++it) + caps |= i->p->capabilities(); + return caps; +} + +TQString TQCA::arrayToHex(const TQByteArray &a) +{ + TQString out; + for(int n = 0; n < (int)a.size(); ++n) { + TQString str; + str.sprintf("%02x", (uchar)a[n]); + out.append(str); + } + return out; +} + +TQByteArray TQCA::hexToArray(const TQString &str) +{ + TQByteArray out(str.length() / 2); + int at = 0; + for(int n = 0; n + 1 < (int)str.length(); n += 2) { + uchar a = str[n]; + uchar b = str[n+1]; + uchar c = ((a & 0x0f) << 4) + (b & 0x0f); + out[at++] = c; + } + return out; +} + +void TQCA::init() +{ + if(qca_init) + return; + qca_init = true; + providerList.setAutoDelete(true); +} + +bool TQCA::isSupported(int capabilities) +{ + init(); + + int caps = plugin_caps(); + if(caps & capabilities) + return true; + + // ok, try scanning for new stuff + plugin_scan(); + caps = plugin_caps(); + if(caps & capabilities) + return true; + + return false; +} + +void TQCA::insertProvider(TQCAProvider *p) +{ + plugin_addClass(p); +} + +void TQCA::unloadAllPlugins() +{ + plugin_unloadall(); +} + +static void *getContext(int cap) +{ + init(); + + // this call will also trip a scan for new plugins if needed + if(!TQCA::isSupported(cap)) + return 0; + + TQPtrListIterator it(providerList); + for(ProviderItem *i; (i = it.current()); ++it) { + if(i->p->capabilities() & cap) { + i->ensureInit(); + return i->p->context(cap); + } + } + return 0; +} + + +//---------------------------------------------------------------------------- +// Hash +//---------------------------------------------------------------------------- +class Hash::Private +{ +public: + Private() + { + c = 0; + } + + ~Private() + { + delete c; + } + + void reset() + { + c->reset(); + } + + TQCA_HashContext *c; +}; + +Hash::Hash(TQCA_HashContext *c) +{ + d = new Private; + d->c = c; +} + +Hash::Hash(const Hash &from) +{ + d = new Private; + *this = from; +} + +Hash & Hash::operator=(const Hash &from) +{ + delete d->c; + d->c = from.d->c->clone(); + return *this; +} + +Hash::~Hash() +{ + delete d; +} + +void Hash::clear() +{ + d->reset(); +} + +void Hash::update(const TQByteArray &a) +{ + d->c->update(a.data(), a.size()); +} + +TQByteArray Hash::final() +{ + TQByteArray buf; + d->c->final(&buf); + return buf; +} + + +//---------------------------------------------------------------------------- +// Cipher +//---------------------------------------------------------------------------- +class Cipher::Private +{ +public: + Private() + { + c = 0; + } + + ~Private() + { + delete c; + } + + void reset() + { + dir = Encrypt; + key.resize(0); + iv.resize(0); + err = false; + } + + TQCA_CipherContext *c; + int dir; + int mode; + TQByteArray key, iv; + bool err; +}; + +Cipher::Cipher(TQCA_CipherContext *c, int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad) +{ + d = new Private; + d->c = c; + reset(dir, mode, key, iv, pad); +} + +Cipher::Cipher(const Cipher &from) +{ + d = new Private; + *this = from; +} + +Cipher & Cipher::operator=(const Cipher &from) +{ + delete d->c; + d->c = from.d->c->clone(); + d->dir = from.d->dir; + d->mode = from.d->mode; + d->key = from.d->key.copy(); + d->iv = from.d->iv.copy(); + d->err = from.d->err; + return *this; +} + +Cipher::~Cipher() +{ + delete d; +} + +TQByteArray Cipher::dyn_generateKey(int size) const +{ + TQByteArray buf; + if(size != -1) + buf.resize(size); + else + buf.resize(d->c->keySize()); + if(!d->c->generateKey(buf.data(), size)) + return TQByteArray(); + return buf; +} + +TQByteArray Cipher::dyn_generateIV() const +{ + TQByteArray buf(d->c->blockSize()); + if(!d->c->generateIV(buf.data())) + return TQByteArray(); + return buf; +} + +void Cipher::reset(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad) +{ + d->reset(); + + d->dir = dir; + d->mode = mode; + d->key = key.copy(); + d->iv = iv.copy(); + if(!d->c->setup(d->dir, d->mode, d->key.isEmpty() ? 0: d->key.data(), d->key.size(), d->iv.isEmpty() ? 0 : d->iv.data(), pad)) { + d->err = true; + return; + } +} + +bool Cipher::update(const TQByteArray &a) +{ + if(d->err) + return false; + + if(!a.isEmpty()) { + if(!d->c->update(a.data(), a.size())) { + d->err = true; + return false; + } + } + return true; +} + +TQByteArray Cipher::final(bool *ok) +{ + if(ok) + *ok = false; + if(d->err) + return TQByteArray(); + + TQByteArray out; + if(!d->c->final(&out)) { + d->err = true; + return TQByteArray(); + } + if(ok) + *ok = true; + return out; +} + + +//---------------------------------------------------------------------------- +// SHA1 +//---------------------------------------------------------------------------- +SHA1::SHA1() +:Hash((TQCA_HashContext *)getContext(CAP_SHA1)) +{ +} + + +//---------------------------------------------------------------------------- +// SHA256 +//---------------------------------------------------------------------------- +SHA256::SHA256() +:Hash((TQCA_HashContext *)getContext(CAP_SHA256)) +{ +} + + +//---------------------------------------------------------------------------- +// MD5 +//---------------------------------------------------------------------------- +MD5::MD5() +:Hash((TQCA_HashContext *)getContext(CAP_MD5)) +{ +} + + +//---------------------------------------------------------------------------- +// BlowFish +//---------------------------------------------------------------------------- +BlowFish::BlowFish(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad) +:Cipher((TQCA_CipherContext *)getContext(CAP_BlowFish), dir, mode, key, iv, pad) +{ +} + + +//---------------------------------------------------------------------------- +// TripleDES +//---------------------------------------------------------------------------- +TripleDES::TripleDES(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad) +:Cipher((TQCA_CipherContext *)getContext(CAP_TripleDES), dir, mode, key, iv, pad) +{ +} + + +//---------------------------------------------------------------------------- +// AES128 +//---------------------------------------------------------------------------- +AES128::AES128(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad) +:Cipher((TQCA_CipherContext *)getContext(CAP_AES128), dir, mode, key, iv, pad) +{ +} + + +//---------------------------------------------------------------------------- +// AES256 +//---------------------------------------------------------------------------- +AES256::AES256(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad) +:Cipher((TQCA_CipherContext *)getContext(CAP_AES256), dir, mode, key, iv, pad) +{ +} + + +//---------------------------------------------------------------------------- +// RSAKey +//---------------------------------------------------------------------------- +class RSAKey::Private +{ +public: + Private() + { + c = 0; + } + + ~Private() + { + delete c; + } + + TQCA_RSAKeyContext *c; +}; + +RSAKey::RSAKey() +{ + d = new Private; + d->c = (TQCA_RSAKeyContext *)getContext(CAP_RSA); +} + +RSAKey::RSAKey(const RSAKey &from) +{ + d = new Private; + *this = from; +} + +RSAKey & RSAKey::operator=(const RSAKey &from) +{ + delete d->c; + d->c = from.d->c->clone(); + return *this; +} + +RSAKey::~RSAKey() +{ + delete d; +} + +bool RSAKey::isNull() const +{ + return d->c->isNull(); +} + +bool RSAKey::havePublic() const +{ + return d->c->havePublic(); +} + +bool RSAKey::havePrivate() const +{ + return d->c->havePrivate(); +} + +TQByteArray RSAKey::toDER(bool publicOnly) const +{ + TQByteArray out; + if(!d->c->toDER(&out, publicOnly)) + return TQByteArray(); + return out; +} + +bool RSAKey::fromDER(const TQByteArray &a) +{ + return d->c->createFromDER(a.data(), a.size()); +} + +TQString RSAKey::toPEM(bool publicOnly) const +{ + TQByteArray out; + if(!d->c->toPEM(&out, publicOnly)) + return TQByteArray(); + + TQCString cs; + cs.resize(out.size()+1); + memcpy(cs.data(), out.data(), out.size()); + return TQString::fromLatin1(cs); +} + +bool RSAKey::fromPEM(const TQString &str) +{ + TQCString cs = str.latin1(); + TQByteArray a(cs.length()); + memcpy(a.data(), cs.data(), a.size()); + return d->c->createFromPEM(a.data(), a.size()); +} + +bool RSAKey::fromNative(void *p) +{ + return d->c->createFromNative(p); +} + +bool RSAKey::encrypt(const TQByteArray &a, TQByteArray *b, bool oaep) const +{ + TQByteArray out; + if(!d->c->encrypt(a, &out, oaep)) + return false; + *b = out; + return true; +} + +bool RSAKey::decrypt(const TQByteArray &a, TQByteArray *b, bool oaep) const +{ + TQByteArray out; + if(!d->c->decrypt(a, &out, oaep)) + return false; + *b = out; + return true; +} + +bool RSAKey::generate(unsigned int bits) +{ + return d->c->generate(bits); +} + + +//---------------------------------------------------------------------------- +// RSA +//---------------------------------------------------------------------------- +RSA::RSA() +{ +} + +RSA::~RSA() +{ +} + +RSAKey RSA::key() const +{ + return v_key; +} + +void RSA::setKey(const RSAKey &k) +{ + v_key = k; +} + +bool RSA::encrypt(const TQByteArray &a, TQByteArray *b, bool oaep) const +{ + if(v_key.isNull()) + return false; + return v_key.encrypt(a, b, oaep); +} + +bool RSA::decrypt(const TQByteArray &a, TQByteArray *b, bool oaep) const +{ + if(v_key.isNull()) + return false; + return v_key.decrypt(a, b, oaep); +} + +RSAKey RSA::generateKey(unsigned int bits) +{ + RSAKey k; + k.generate(bits); + return k; +} + + +//---------------------------------------------------------------------------- +// Cert +//---------------------------------------------------------------------------- +class Cert::Private +{ +public: + Private() + { + c = 0; + } + + ~Private() + { + delete c; + } + + TQCA_CertContext *c; +}; + +Cert::Cert() +{ + d = new Private; + d->c = (TQCA_CertContext *)getContext(CAP_X509); +} + +Cert::Cert(const Cert &from) +{ + d = new Private; + *this = from; +} + +Cert & Cert::operator=(const Cert &from) +{ + delete d->c; + d->c = from.d->c->clone(); + return *this; +} + +Cert::~Cert() +{ + delete d; +} + +void Cert::fromContext(TQCA_CertContext *ctx) +{ + delete d->c; + d->c = ctx; +} + +bool Cert::isNull() const +{ + return d->c->isNull(); +} + +TQString Cert::commonName() const +{ + CertProperties props = subject(); + return props["CN"]; +} + +TQString Cert::serialNumber() const +{ + return d->c->serialNumber(); +} + +TQString Cert::subjectString() const +{ + return d->c->subjectString(); +} + +TQString Cert::issuerString() const +{ + return d->c->issuerString(); +} + +CertProperties Cert::subject() const +{ + TQValueList list = d->c->subject(); + CertProperties props; + for(TQValueList::ConstIterator it = list.begin(); it != list.end(); ++it) + props[(*it).var] = (*it).val; + return props; +} + +CertProperties Cert::issuer() const +{ + TQValueList list = d->c->issuer(); + CertProperties props; + for(TQValueList::ConstIterator it = list.begin(); it != list.end(); ++it) + props[(*it).var] = (*it).val; + return props; +} + +TQDateTime Cert::notBefore() const +{ + return d->c->notBefore(); +} + +TQDateTime Cert::notAfter() const +{ + return d->c->notAfter(); +} + +TQByteArray Cert::toDER() const +{ + TQByteArray out; + if(!d->c->toDER(&out)) + return TQByteArray(); + return out; +} + +bool Cert::fromDER(const TQByteArray &a) +{ + return d->c->createFromDER(a.data(), a.size()); +} + +TQString Cert::toPEM() const +{ + TQByteArray out; + if(!d->c->toPEM(&out)) + return TQByteArray(); + + TQCString cs; + cs.resize(out.size()+1); + memcpy(cs.data(), out.data(), out.size()); + return TQString::fromLatin1(cs); +} + +bool Cert::fromPEM(const TQString &str) +{ + TQCString cs = str.latin1(); + TQByteArray a(cs.length()); + memcpy(a.data(), cs.data(), a.size()); + return d->c->createFromPEM(a.data(), a.size()); +} + + +//---------------------------------------------------------------------------- +// TLS +//---------------------------------------------------------------------------- +class TLS::Private +{ +public: + Private() + { + c = (TQCA_TLSContext *)getContext(CAP_TLS); + } + + ~Private() + { + delete c; + } + + void reset() + { + handshaken = false; + closing = false; + in.resize(0); + out.resize(0); + from_net.resize(0); + to_net.resize(0); + host = ""; + hostMismatch = false; + cert = Cert(); + bytesEncoded = 0; + tryMore = false; + } + + void appendArray(TQByteArray *a, const TQByteArray &b) + { + int oldsize = a->size(); + a->resize(oldsize + b.size()); + memcpy(a->data() + oldsize, b.data(), b.size()); + } + + Cert cert; + TQCA_TLSContext *c; + TQByteArray in, out, to_net, from_net; + int bytesEncoded; + bool tryMore; + bool handshaken; + TQString host; + bool hostMismatch; + bool closing; + + Cert ourCert; + RSAKey ourKey; + TQPtrList store; +}; + +TLS::TLS(TQObject *parent) +:TQObject(parent) +{ + d = new Private; +} + +TLS::~TLS() +{ + delete d; +} + +void TLS::setCertificate(const Cert &cert, const RSAKey &key) +{ + d->ourCert = cert; + d->ourKey = key; +} + +void TLS::setCertificateStore(const TQPtrList &store) +{ + // convert the cert list into a context list + d->store.clear(); + TQPtrListIterator it(store); + for(Cert *cert; (cert = it.current()); ++it) + d->store.append(cert->d->c); +} + +void TLS::reset() +{ + d->reset(); +} + +bool TLS::startClient(const TQString &host) +{ + d->reset(); + d->host = host; + + if(!d->c->startClient(d->store, *d->ourCert.d->c, *d->ourKey.d->c)) + return false; + TQTimer::singleShot(0, this, SLOT(update())); + return true; +} + +bool TLS::startServer() +{ + d->reset(); + + if(!d->c->startServer(d->store, *d->ourCert.d->c, *d->ourKey.d->c)) + return false; + TQTimer::singleShot(0, this, SLOT(update())); + return true; +} + +void TLS::close() +{ + if(!d->handshaken || d->closing) + return; + + d->closing = true; + TQTimer::singleShot(0, this, SLOT(update())); +} + +bool TLS::isHandshaken() const +{ + return d->handshaken; +} + +void TLS::write(const TQByteArray &a) +{ + d->appendArray(&d->out, a); + update(); +} + +TQByteArray TLS::read() +{ + TQByteArray a = d->in.copy(); + d->in.resize(0); + return a; +} + +void TLS::writeIncoming(const TQByteArray &a) +{ + d->appendArray(&d->from_net, a); + update(); +} + +TQByteArray TLS::readOutgoing() +{ + TQByteArray a = d->to_net.copy(); + d->to_net.resize(0); + return a; +} + +TQByteArray TLS::readUnprocessed() +{ + TQByteArray a = d->from_net.copy(); + d->from_net.resize(0); + return a; +} + +const Cert & TLS::peerCertificate() const +{ + return d->cert; +} + +int TLS::certificateValidityResult() const +{ + if(d->hostMismatch) + return TQCA::TLS::HostMismatch; + else + return d->c->validityResult(); +} + +void TLS::update() +{ + bool force_read = false; + bool eof = false; + bool done = false; + TQGuardedPtr self = this; + + if(d->closing) { + TQByteArray a; + int r = d->c->shutdown(d->from_net, &a); + d->from_net.resize(0); + if(r == TQCA_TLSContext::Error) { + reset(); + error(ErrHandshake); + return; + } + if(r == TQCA_TLSContext::Success) { + d->from_net = d->c->unprocessed().copy(); + done = true; + } + d->appendArray(&d->to_net, a); + } + else { + if(!d->handshaken) { + TQByteArray a; + int r = d->c->handshake(d->from_net, &a); + d->from_net.resize(0); + if(r == TQCA_TLSContext::Error) { + reset(); + error(ErrHandshake); + return; + } + d->appendArray(&d->to_net, a); + if(r == TQCA_TLSContext::Success) { + TQCA_CertContext *cc = d->c->peerCertificate(); + if(cc && !d->host.isEmpty() && d->c->validityResult() == TQCA::TLS::Valid) { + if(!cc->matchesAddress(d->host)) + d->hostMismatch = true; + } + d->cert.fromContext(cc); + d->handshaken = true; + handshaken(); + if(!self) + return; + + // there is a teeny tiny possibility that incoming data awaits. let us get it. + force_read = true; + } + } + + if(d->handshaken) { + if(!d->out.isEmpty() || d->tryMore) { + d->tryMore = false; + TQByteArray a; + int enc; + bool more = false; + bool ok = d->c->encode(d->out, &a, &enc); + eof = d->c->eof(); + if(ok && enc < (int)d->out.size()) + more = true; + d->out.resize(0); + if(!eof) { + if(!ok) { + reset(); + error(ErrCrypt); + return; + } + d->bytesEncoded += enc; + if(more) + d->tryMore = true; + d->appendArray(&d->to_net, a); + } + } + if(!d->from_net.isEmpty() || force_read) { + TQByteArray a, b; + bool ok = d->c->decode(d->from_net, &a, &b); + eof = d->c->eof(); + d->from_net.resize(0); + if(!ok) { + reset(); + error(ErrCrypt); + return; + } + d->appendArray(&d->in, a); + d->appendArray(&d->to_net, b); + } + + if(!d->in.isEmpty()) { + readyRead(); + if(!self) + return; + } + } + } + + if(!d->to_net.isEmpty()) { + int bytes = d->bytesEncoded; + d->bytesEncoded = 0; + readyReadOutgoing(bytes); + if(!self) + return; + } + + if(eof) { + close(); + if(!self) + return; + return; + } + + if(d->closing && done) { + reset(); + closed(); + } +} + + +//---------------------------------------------------------------------------- +// SASL +//---------------------------------------------------------------------------- +TQString saslappname = "qca"; +class SASL::Private +{ +public: + Private() + { + c = (TQCA_SASLContext *)getContext(CAP_SASL); + } + + ~Private() + { + delete c; + } + + void setSecurityProps() + { + c->setSecurityProps(noPlain, noActive, noDict, noAnon, reqForward, reqCreds, reqMutual, ssfmin, ssfmax, ext_authid, ext_ssf); + } + + // security opts + bool noPlain, noActive, noDict, noAnon, reqForward, reqCreds, reqMutual; + int ssfmin, ssfmax; + TQString ext_authid; + int ext_ssf; + + bool tried; + TQCA_SASLContext *c; + TQHostAddress localAddr, remoteAddr; + int localPort, remotePort; + TQByteArray stepData; + bool allowCSF; + bool first, server; + + TQByteArray inbuf, outbuf; +}; + +SASL::SASL(TQObject *parent) +:TQObject(parent) +{ + d = new Private; + reset(); +} + +SASL::~SASL() +{ + delete d; +} + +void SASL::setAppName(const TQString &name) +{ + saslappname = name; +} + +void SASL::reset() +{ + d->localPort = -1; + d->remotePort = -1; + + d->noPlain = false; + d->noActive = false; + d->noDict = false; + d->noAnon = false; + d->reqForward = false; + d->reqCreds = false; + d->reqMutual = false; + d->ssfmin = 0; + d->ssfmax = 0; + d->ext_authid = ""; + d->ext_ssf = 0; + + d->inbuf.resize(0); + d->outbuf.resize(0); + + d->c->reset(); +} + +int SASL::errorCondition() const +{ + return d->c->errorCond(); +} + +void SASL::setAllowPlain(bool b) +{ + d->noPlain = !b; +} + +void SASL::setAllowAnonymous(bool b) +{ + d->noAnon = !b; +} + +void SASL::setAllowActiveVulnerable(bool b) +{ + d->noActive = !b; +} + +void SASL::setAllowDictionaryVulnerable(bool b) +{ + d->noDict = !b; +} + +void SASL::setRequireForwardSecrecy(bool b) +{ + d->reqForward = b; +} + +void SASL::setRequirePassCredentials(bool b) +{ + d->reqCreds = b; +} + +void SASL::setRequireMutualAuth(bool b) +{ + d->reqMutual = b; +} + +void SASL::setMinimumSSF(int x) +{ + d->ssfmin = x; +} + +void SASL::setMaximumSSF(int x) +{ + d->ssfmax = x; +} + +void SASL::setExternalAuthID(const TQString &authid) +{ + d->ext_authid = authid; +} + +void SASL::setExternalSSF(int x) +{ + d->ext_ssf = x; +} + +void SASL::setLocalAddr(const TQHostAddress &addr, Q_UINT16 port) +{ + d->localAddr = addr; + d->localPort = port; +} + +void SASL::setRemoteAddr(const TQHostAddress &addr, Q_UINT16 port) +{ + d->remoteAddr = addr; + d->remotePort = port; +} + +bool SASL::startClient(const TQString &service, const TQString &host, const TQStringList &mechlist, bool allowClientSendFirst) +{ + TQCA_SASLHostPort la, ra; + if(d->localPort != -1) { + la.addr = d->localAddr; + la.port = d->localPort; + } + if(d->remotePort != -1) { + ra.addr = d->remoteAddr; + ra.port = d->remotePort; + } + + d->allowCSF = allowClientSendFirst; + d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0); + d->setSecurityProps(); + + if(!d->c->clientStart(mechlist)) + return false; + d->first = true; + d->server = false; + d->tried = false; + TQTimer::singleShot(0, this, SLOT(tryAgain())); + return true; +} + +bool SASL::startServer(const TQString &service, const TQString &host, const TQString &realm, TQStringList *mechlist) +{ + TQCA_SASLHostPort la, ra; + if(d->localPort != -1) { + la.addr = d->localAddr; + la.port = d->localPort; + } + if(d->remotePort != -1) { + ra.addr = d->remoteAddr; + ra.port = d->remotePort; + } + + d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0); + d->setSecurityProps(); + + if(!d->c->serverStart(realm, mechlist, saslappname)) + return false; + d->first = true; + d->server = true; + d->tried = false; + return true; +} + +void SASL::putServerFirstStep(const TQString &mech) +{ + int r = d->c->serverFirstStep(mech, 0); + handleServerFirstStep(r); +} + +void SASL::putServerFirstStep(const TQString &mech, const TQByteArray &clientInit) +{ + int r = d->c->serverFirstStep(mech, &clientInit); + handleServerFirstStep(r); +} + +void SASL::handleServerFirstStep(int r) +{ + if(r == TQCA_SASLContext::Success) + authenticated(); + else if(r == TQCA_SASLContext::Continue) + nextStep(d->c->result()); + else if(r == TQCA_SASLContext::AuthCheck) + tryAgain(); + else + error(ErrAuth); +} + +void SASL::putStep(const TQByteArray &stepData) +{ + d->stepData = stepData.copy(); + tryAgain(); +} + +void SASL::setUsername(const TQString &user) +{ + d->c->setClientParams(&user, 0, 0, 0); +} + +void SASL::setAuthzid(const TQString &authzid) +{ + d->c->setClientParams(0, &authzid, 0, 0); +} + +void SASL::setPassword(const TQString &pass) +{ + d->c->setClientParams(0, 0, &pass, 0); +} + +void SASL::setRealm(const TQString &realm) +{ + d->c->setClientParams(0, 0, 0, &realm); +} + +void SASL::continueAfterParams() +{ + tryAgain(); +} + +void SASL::continueAfterAuthCheck() +{ + tryAgain(); +} + +void SASL::tryAgain() +{ + int r; + + if(d->server) { + if(!d->tried) { + r = d->c->nextStep(d->stepData); + d->tried = true; + } + else { + r = d->c->tryAgain(); + } + + if(r == TQCA_SASLContext::Error) { + error(ErrAuth); + return; + } + else if(r == TQCA_SASLContext::Continue) { + d->tried = false; + nextStep(d->c->result()); + return; + } + else if(r == TQCA_SASLContext::AuthCheck) { + authCheck(d->c->username(), d->c->authzid()); + return; + } + } + else { + if(d->first) { + if(!d->tried) { + r = d->c->clientFirstStep(d->allowCSF); + d->tried = true; + } + else + r = d->c->tryAgain(); + + if(r == TQCA_SASLContext::Error) { + error(ErrAuth); + return; + } + else if(r == TQCA_SASLContext::NeedParams) { + //d->tried = false; + TQCA_SASLNeedParams np = d->c->clientParamsNeeded(); + needParams(np.user, np.authzid, np.pass, np.realm); + return; + } + + TQString mech = d->c->mech(); + const TQByteArray *clientInit = d->c->clientInit(); + + d->first = false; + d->tried = false; + clientFirstStep(mech, clientInit); + } + else { + if(!d->tried) { + r = d->c->nextStep(d->stepData); + d->tried = true; + } + else + r = d->c->tryAgain(); + + if(r == TQCA_SASLContext::Error) { + error(ErrAuth); + return; + } + else if(r == TQCA_SASLContext::NeedParams) { + //d->tried = false; + TQCA_SASLNeedParams np = d->c->clientParamsNeeded(); + needParams(np.user, np.authzid, np.pass, np.realm); + return; + } + d->tried = false; + //else if(r == TQCA_SASLContext::Continue) { + nextStep(d->c->result()); + // return; + //} + } + } + + if(r == TQCA_SASLContext::Success) + authenticated(); + else if(r == TQCA_SASLContext::Error) + error(ErrAuth); +} + +int SASL::ssf() const +{ + return d->c->security(); +} + +void SASL::write(const TQByteArray &a) +{ + TQByteArray b; + if(!d->c->encode(a, &b)) { + error(ErrCrypt); + return; + } + int oldsize = d->outbuf.size(); + d->outbuf.resize(oldsize + b.size()); + memcpy(d->outbuf.data() + oldsize, b.data(), b.size()); + readyReadOutgoing(a.size()); +} + +TQByteArray SASL::read() +{ + TQByteArray a = d->inbuf.copy(); + d->inbuf.resize(0); + return a; +} + +void SASL::writeIncoming(const TQByteArray &a) +{ + TQByteArray b; + if(!d->c->decode(a, &b)) { + error(ErrCrypt); + return; + } + int oldsize = d->inbuf.size(); + d->inbuf.resize(oldsize + b.size()); + memcpy(d->inbuf.data() + oldsize, b.data(), b.size()); + readyRead(); +} + +TQByteArray SASL::readOutgoing() +{ + TQByteArray a = d->outbuf.copy(); + d->outbuf.resize(0); + return a; +} diff --git a/src/qca.h b/src/qca.h new file mode 100644 index 0000000..11a8b92 --- /dev/null +++ b/src/qca.h @@ -0,0 +1,466 @@ +/* + * qca.h - Qt Cryptographic Architecture + * Copyright (C) 2003 Justin Karneges + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef TQCA_H +#define TQCA_H + +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN32 +# ifndef TQCA_STATIC +# ifdef TQCA_MAKEDLL +# define TQCA_EXPORT __declspec(dllexport) +# else +# define TQCA_EXPORT __declspec(dllimport) +# endif +# endif +#endif +#ifndef TQCA_EXPORT +#define TQCA_EXPORT +#endif + +#ifdef Q_OS_WIN32 +# ifdef TQCA_PLUGIN_DLL +# define TQCA_PLUGIN_EXPORT extern "C" __declspec(dllexport) +# else +# define TQCA_PLUGIN_EXPORT extern "C" __declspec(dllimport) +# endif +#endif +#ifndef TQCA_PLUGIN_EXPORT +#define TQCA_PLUGIN_EXPORT extern "C" +#endif + +class TQHostAddress; +class TQStringList; + +class TQCAProvider; +class TQCA_HashContext; +class TQCA_CipherContext; +class TQCA_CertContext; + +namespace TQCA +{ + enum { + CAP_SHA1 = 0x0001, + CAP_SHA256 = 0x0002, + CAP_MD5 = 0x0004, + CAP_BlowFish = 0x0008, + CAP_TripleDES = 0x0010, + CAP_AES128 = 0x0020, + CAP_AES256 = 0x0040, + CAP_RSA = 0x0080, + CAP_X509 = 0x0100, + CAP_TLS = 0x0200, + CAP_SASL = 0x0400 + }; + + enum { + CBC = 0x0001, + CFB = 0x0002 + }; + + enum { + Encrypt = 0x0001, + Decrypt = 0x0002 + }; + + TQCA_EXPORT void init(); + TQCA_EXPORT bool isSupported(int capabilities); + TQCA_EXPORT void insertProvider(TQCAProvider *); + TQCA_EXPORT void unloadAllPlugins(); + + TQCA_EXPORT TQString arrayToHex(const TQByteArray &); + TQCA_EXPORT TQByteArray hexToArray(const TQString &); + + class TQCA_EXPORT Hash + { + public: + Hash(const Hash &); + Hash & operator=(const Hash &); + ~Hash(); + + void clear(); + void update(const TQByteArray &a); + TQByteArray final(); + + protected: + Hash(TQCA_HashContext *); + + private: + class Private; + Private *d; + }; + + template + class TQCA_EXPORT HashStatic + { + public: + HashStatic() {} + + static TQByteArray hash(const TQByteArray &a) + { + T obj; + obj.update(a); + return obj.final(); + } + + static TQByteArray hash(const TQCString &cs) + { + TQByteArray a(cs.length()); + memcpy(a.data(), cs.data(), a.size()); + return hash(a); + } + + static TQString hashToString(const TQByteArray &a) + { + return arrayToHex(hash(a)); + } + + static TQString hashToString(const TQCString &cs) + { + return arrayToHex(hash(cs)); + } + }; + + class TQCA_EXPORT Cipher + { + public: + Cipher(const Cipher &); + Cipher & operator=(const Cipher &); + ~Cipher(); + + TQByteArray dyn_generateKey(int size=-1) const; + TQByteArray dyn_generateIV() const; + void reset(int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad=true); + bool update(const TQByteArray &a); + TQByteArray final(bool *ok=0); + + protected: + Cipher(TQCA_CipherContext *, int dir, int mode, const TQByteArray &key, const TQByteArray &iv, bool pad); + + private: + class Private; + Private *d; + }; + + template + class TQCA_EXPORT CipherStatic + { + public: + CipherStatic() {} + + static TQByteArray generateKey(int size=-1) + { + T obj; + return obj.dyn_generateKey(size); + } + + static TQByteArray generateIV() + { + T obj; + return obj.dyn_generateIV(); + } + }; + + class TQCA_EXPORT SHA1 : public Hash, public HashStatic + { + public: + SHA1(); + }; + + class TQCA_EXPORT SHA256 : public Hash, public HashStatic + { + public: + SHA256(); + }; + + class TQCA_EXPORT MD5 : public Hash, public HashStatic + { + public: + MD5(); + }; + + class TQCA_EXPORT BlowFish : public Cipher, public CipherStatic + { + public: + BlowFish(int dir=Encrypt, int mode=CBC, const TQByteArray &key=TQByteArray(), const TQByteArray &iv=TQByteArray(), bool pad=true); + }; + + class TQCA_EXPORT TripleDES : public Cipher, public CipherStatic + { + public: + TripleDES(int dir=Encrypt, int mode=CBC, const TQByteArray &key=TQByteArray(), const TQByteArray &iv=TQByteArray(), bool pad=true); + }; + + class TQCA_EXPORT AES128 : public Cipher, public CipherStatic + { + public: + AES128(int dir=Encrypt, int mode=CBC, const TQByteArray &key=TQByteArray(), const TQByteArray &iv=TQByteArray(), bool pad=true); + }; + + class TQCA_EXPORT AES256 : public Cipher, public CipherStatic + { + public: + AES256(int dir=Encrypt, int mode=CBC, const TQByteArray &key=TQByteArray(), const TQByteArray &iv=TQByteArray(), bool pad=true); + }; + + class RSA; + class TQCA_EXPORT RSAKey + { + public: + RSAKey(); + RSAKey(const RSAKey &from); + RSAKey & operator=(const RSAKey &from); + ~RSAKey(); + + bool isNull() const; + bool havePublic() const; + bool havePrivate() const; + + TQByteArray toDER(bool publicOnly=false) const; + bool fromDER(const TQByteArray &a); + + TQString toPEM(bool publicOnly=false) const; + bool fromPEM(const TQString &); + + // only call if you know what you are doing + bool fromNative(void *); + + private: + class Private; + Private *d; + + friend class RSA; + friend class TLS; + bool encrypt(const TQByteArray &a, TQByteArray *out, bool oaep) const; + bool decrypt(const TQByteArray &a, TQByteArray *out, bool oaep) const; + bool generate(unsigned int bits); + }; + + class TQCA_EXPORT RSA + { + public: + RSA(); + ~RSA(); + + RSAKey key() const; + void setKey(const RSAKey &); + + bool encrypt(const TQByteArray &a, TQByteArray *out, bool oaep=false) const; + bool decrypt(const TQByteArray &a, TQByteArray *out, bool oaep=false) const; + + static RSAKey generateKey(unsigned int bits); + + private: + RSAKey v_key; + }; + + typedef TQMap CertProperties; + class TQCA_EXPORT Cert + { + public: + Cert(); + Cert(const Cert &); + Cert & operator=(const Cert &); + ~Cert(); + + bool isNull() const; + + TQString commonName() const; + TQString serialNumber() const; + TQString subjectString() const; + TQString issuerString() const; + CertProperties subject() const; + CertProperties issuer() const; + TQDateTime notBefore() const; + TQDateTime notAfter() const; + + TQByteArray toDER() const; + bool fromDER(const TQByteArray &a); + + TQString toPEM() const; + bool fromPEM(const TQString &); + + private: + class Private; + Private *d; + + friend class TLS; + void fromContext(TQCA_CertContext *); + }; + + class TQCA_EXPORT TLS : public TQObject + { + Q_OBJECT + public: + enum Validity { + NoCert, + Valid, + HostMismatch, + Rejected, + Untrusted, + SignatureFailed, + InvalidCA, + InvalidPurpose, + SelfSigned, + Revoked, + PathLengthExceeded, + Expired, + Unknown + }; + enum Error { ErrHandshake, ErrCrypt }; + + TLS(TQObject *parent=0); + ~TLS(); + + void setCertificate(const Cert &cert, const RSAKey &key); + void setCertificateStore(const TQPtrList &store); // note: store must persist + + void reset(); + bool startClient(const TQString &host=""); + bool startServer(); + void close(); + bool isHandshaken() const; + + // plain (application side) + void write(const TQByteArray &a); + TQByteArray read(); + + // encoded (socket side) + void writeIncoming(const TQByteArray &a); + TQByteArray readOutgoing(); + TQByteArray readUnprocessed(); + + // cert related + const Cert & peerCertificate() const; + int certificateValidityResult() const; + + signals: + void handshaken(); + void readyRead(); + void readyReadOutgoing(int plainBytes); + void closed(); + void error(int); + + private slots: + void update(); + + private: + class Private; + Private *d; + }; + + class TQCA_EXPORT SASL : public TQObject + { + Q_OBJECT + public: + enum Error { ErrAuth, ErrCrypt }; + enum ErrorCond { + NoMech, + BadProto, + BadServ, + BadAuth, + NoAuthzid, + TooWeak, + NeedEncrypt, + Expired, + Disabled, + NoUser, + RemoteUnavail + }; + SASL(TQObject *parent=0); + ~SASL(); + + static void setAppName(const TQString &name); + + void reset(); + int errorCondition() const; + + // options + void setAllowPlain(bool); + void setAllowAnonymous(bool); + void setAllowActiveVulnerable(bool); + void setAllowDictionaryVulnerable(bool); + void setRequireForwardSecrecy(bool); + void setRequirePassCredentials(bool); + void setRequireMutualAuth(bool); + + void setMinimumSSF(int); + void setMaximumSSF(int); + void setExternalAuthID(const TQString &authid); + void setExternalSSF(int); + + void setLocalAddr(const TQHostAddress &addr, TQ_UINT16 port); + void setRemoteAddr(const TQHostAddress &addr, TQ_UINT16 port); + + // initialize + bool startClient(const TQString &service, const TQString &host, const TQStringList &mechlist, bool allowClientSendFirst=true); + bool startServer(const TQString &service, const TQString &host, const TQString &realm, TQStringList *mechlist); + + // authentication + void putStep(const TQByteArray &stepData); + void putServerFirstStep(const TQString &mech); + void putServerFirstStep(const TQString &mech, const TQByteArray &clientInit); + void setUsername(const TQString &user); + void setAuthzid(const TQString &auth); + void setPassword(const TQString &pass); + void setRealm(const TQString &realm); + void continueAfterParams(); + void continueAfterAuthCheck(); + + // security layer + int ssf() const; + void write(const TQByteArray &a); + TQByteArray read(); + void writeIncoming(const TQByteArray &a); + TQByteArray readOutgoing(); + + signals: + // for authentication + void clientFirstStep(const TQString &mech, const TQByteArray *clientInit); + void nextStep(const TQByteArray &stepData); + void needParams(bool user, bool authzid, bool pass, bool realm); + void authCheck(const TQString &user, const TQString &authzid); + void authenticated(); + + // for security layer + void readyRead(); + void readyReadOutgoing(int plainBytes); + + // error + void error(int); + + private slots: + void tryAgain(); + + private: + class Private; + Private *d; + + void handleServerFirstStep(int r); + }; +}; + +#endif diff --git a/src/qcaprovider.h b/src/qcaprovider.h new file mode 100644 index 0000000..1b8277b --- /dev/null +++ b/src/qcaprovider.h @@ -0,0 +1,191 @@ +/* + * qcaprovider.h - QCA Plugin API + * Copyright (C) 2003 Justin Karneges + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef TQCAPROVIDER_H +#define TQCAPROVIDER_H + +#include +#include +#include +#include +#include +#include"qca.h" + +#define TQCA_PLUGIN_VERSION 1 + +class TQCAProvider +{ +public: + TQCAProvider() {} + virtual ~TQCAProvider() {} + + virtual void init()=0; + virtual int qcaVersion() const=0; + virtual int capabilities() const=0; + virtual void *context(int cap)=0; +}; + +class TQCA_HashContext +{ +public: + virtual ~TQCA_HashContext() {} + + virtual TQCA_HashContext *clone()=0; + virtual void reset()=0; + virtual void update(const char *in, unsigned int len)=0; + virtual void final(TQByteArray *out)=0; +}; + +class TQCA_CipherContext +{ +public: + virtual ~TQCA_CipherContext() {} + + virtual TQCA_CipherContext *clone()=0; + virtual int keySize()=0; + virtual int blockSize()=0; + virtual bool generateKey(char *out, int keysize=-1)=0; + virtual bool generateIV(char *out)=0; + + virtual bool setup(int dir, int mode, const char *key, int keysize, const char *iv, bool pad)=0; + virtual bool update(const char *in, unsigned int len)=0; + virtual bool final(TQByteArray *out)=0; +}; + +class TQCA_RSAKeyContext +{ +public: + virtual ~TQCA_RSAKeyContext() {} + + virtual TQCA_RSAKeyContext *clone() const=0; + virtual bool isNull() const=0; + virtual bool havePublic() const=0; + virtual bool havePrivate() const=0; + virtual bool createFromDER(const char *in, unsigned int len)=0; + virtual bool createFromPEM(const char *in, unsigned int len)=0; + virtual bool createFromNative(void *in)=0; + virtual bool generate(unsigned int bits)=0; + virtual bool toDER(TQByteArray *out, bool publicOnly)=0; + virtual bool toPEM(TQByteArray *out, bool publicOnly)=0; + + virtual bool encrypt(const TQByteArray &in, TQByteArray *out, bool oaep)=0; + virtual bool decrypt(const TQByteArray &in, TQByteArray *out, bool oaep)=0; +}; + +struct TQCA_CertProperty +{ + TQString var; + TQString val; +}; + +class TQCA_CertContext +{ +public: + virtual ~TQCA_CertContext() {} + + virtual TQCA_CertContext *clone() const=0; + virtual bool isNull() const=0; + virtual bool createFromDER(const char *in, unsigned int len)=0; + virtual bool createFromPEM(const char *in, unsigned int len)=0; + virtual bool toDER(TQByteArray *out)=0; + virtual bool toPEM(TQByteArray *out)=0; + + virtual TQString serialNumber() const=0; + virtual TQString subjectString() const=0; + virtual TQString issuerString() const=0; + virtual TQValueList subject() const=0; + virtual TQValueList issuer() const=0; + virtual TQDateTime notBefore() const=0; + virtual TQDateTime notAfter() const=0; + virtual bool matchesAddress(const TQString &realHost) const=0; +}; + +class TQCA_TLSContext +{ +public: + enum Result { Success, Error, Continue }; + virtual ~TQCA_TLSContext() {} + + virtual void reset()=0; + virtual bool startClient(const TQPtrList &store, const TQCA_CertContext &cert, const TQCA_RSAKeyContext &key)=0; + virtual bool startServer(const TQPtrList &store, const TQCA_CertContext &cert, const TQCA_RSAKeyContext &key)=0; + + virtual int handshake(const TQByteArray &in, TQByteArray *out)=0; + virtual int shutdown(const TQByteArray &in, TQByteArray *out)=0; + virtual bool encode(const TQByteArray &plain, TQByteArray *to_net, int *encoded)=0; + virtual bool decode(const TQByteArray &from_net, TQByteArray *plain, TQByteArray *to_net)=0; + virtual bool eof() const=0; + virtual TQByteArray unprocessed()=0; + + virtual TQCA_CertContext *peerCertificate() const=0; + virtual int validityResult() const=0; +}; + +struct TQCA_SASLHostPort +{ + TQHostAddress addr; + Q_UINT16 port; +}; + +struct TQCA_SASLNeedParams +{ + bool user, authzid, pass, realm; +}; + +class TQCA_SASLContext +{ +public: + enum Result { Success, Error, NeedParams, AuthCheck, Continue }; + virtual ~TQCA_SASLContext() {} + + // common + virtual void reset()=0; + virtual void setCoreProps(const TQString &service, const TQString &host, TQCA_SASLHostPort *local, TQCA_SASLHostPort *remote)=0; + virtual void setSecurityProps(bool noPlain, bool noActive, bool noDict, bool noAnon, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int ssfMax, const TQString &_ext_authid, int _ext_ssf)=0; + virtual int security() const=0; + virtual int errorCond() const=0; + + // init / first step + virtual bool clientStart(const TQStringList &mechlist)=0; + virtual int clientFirstStep(bool allowClientSendFirst)=0; + virtual bool serverStart(const TQString &realm, TQStringList *mechlist, const TQString &name)=0; + virtual int serverFirstStep(const TQString &mech, const TQByteArray *in)=0; + + // get / set params + virtual TQCA_SASLNeedParams clientParamsNeeded() const=0; + virtual void setClientParams(const TQString *user, const TQString *authzid, const TQString *pass, const TQString *realm)=0; + virtual TQString username() const=0; + virtual TQString authzid() const=0; + + // continue steps + virtual int nextStep(const TQByteArray &in)=0; + virtual int tryAgain()=0; + + // results + virtual TQString mech() const=0; + virtual const TQByteArray *clientInit() const=0; + virtual TQByteArray result() const=0; + + // security layer + virtual bool encode(const TQByteArray &in, TQByteArray *out)=0; + virtual bool decode(const TQByteArray &in, TQByteArray *out)=0; +}; + +#endif