00001 /* 00002 Copyright (C) 2007 Brad Hards <bradh@frogmouth.net> 00003 00004 Permission is hereby granted, free of charge, to any person obtaining a copy 00005 of this software and associated documentation files (the "Software"), to deal 00006 in the Software without restriction, including without limitation the rights 00007 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 copies of the Software, and to permit persons to whom the Software is 00009 furnished to do so, subject to the following conditions: 00010 00011 The above copyright notice and this permission notice shall be included in 00012 all copies or substantial portions of the Software. 00013 00014 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00018 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00019 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00020 */ 00021 00022 // QtCrypto has the declarations for all of QCA 00023 #include <QtCrypto> 00024 00025 #include <QCoreApplication> 00026 00027 #include <iostream> 00028 00032 class ClientPassphraseHandler: public QObject 00033 { 00034 Q_OBJECT 00035 public: 00036 ClientPassphraseHandler(QObject *parent = 0) : QObject( parent ) 00037 { 00038 // When the PasswordAsker or TokenAsker needs to interact 00039 // with the user, it raises a signal. We connect that to a 00040 // local slot to get the required information. 00041 connect( &m_handler, SIGNAL( eventReady(int, const QCA::Event &) ), 00042 SLOT( my_eventReady(int, const QCA::Event &) ) ); 00043 00044 // Now that we are set up, we can start the EventHandler. Nothing 00045 // will happen if you don't call this method. 00046 m_handler.start(); 00047 } 00048 00049 private slots: 00050 // This slot gets called when the provider needs a token inserted, 00051 // or to get a passphrase / password / PIN. 00052 void my_eventReady(int id, const QCA::Event &event) 00053 { 00054 // We can sanity check the event 00055 if ( event.isNull() ) { 00056 return; 00057 } 00058 00059 // Events can be associated with a a keystore or a file/bytearray 00060 // You can tell which by looking at the Source 00061 if ( event.source() == QCA::Event::KeyStore ) { 00062 std::cout << "Event is associated with a key store operation" << std::endl; 00063 } else if ( event.source() == QCA::Event::Data ) { 00064 std::cout << "Event is associated with a file or some other data" << std::endl; 00065 // if the event comes from a file type operation, you can get the 00066 // name / label using fileName() 00067 std::cout << " Filename: " << qPrintable( event.fileName() ) << std::endl; 00068 } else { 00069 std::cout << "Unexpected Source for Event" << std::endl; 00070 } 00071 00072 // There are different kinds of events. 00073 if ( event.type() == QCA::Event::Token ) { 00074 // You would typically ask the user to insert the token here 00075 std::cout << "Request for token" << std::endl; 00076 // we just fake it for this demo. 00077 m_handler.tokenOkay( id ); 00078 // you could use m_handler.reject( id ) to refuse the token request 00079 00080 } else if ( event.type() == QCA::Event::Password ) { 00081 std::cout << "Request for password, passphrase or PIN" << std::endl; 00082 // and within the Password type, we have a few different styles. 00083 if ( event.passwordStyle() == QCA::Event::StylePassword ) { 00084 std::cout << " [Password request]" << std::endl; 00085 } else if ( event.passwordStyle() == QCA::Event::StylePassphrase ) { 00086 std::cout << " [Passphrase request]" << std::endl; 00087 } else if ( event.passwordStyle() == QCA::Event::StylePIN ){ 00088 std::cout << " [PIN request]" << std::endl; 00089 } else { 00090 std::cout << " [unexpect request style]" << std::endl; 00091 } 00092 // You would typically request the password/PIN/passphrase. 00093 // again, we just fake it. 00094 m_handler.submitPassword( id, QCA::SecureArray( "hello" ) ); 00095 00096 } else { 00097 std::cout << "Unexpected event type" << std::endl; 00098 } 00099 } 00100 private: 00101 QCA::EventHandler m_handler; 00102 00103 }; 00104 00105 void asker_procedure(); 00106 00107 class AskerThread : public QThread 00108 { 00109 Q_OBJECT 00110 protected: 00111 virtual void run() 00112 { 00113 asker_procedure(); 00114 } 00115 }; 00116 00117 int main(int argc, char **argv) 00118 { 00119 QCoreApplication exampleApp(argc, argv); 00120 00121 // the Initializer object sets things up, and 00122 // also does cleanup when it goes out of scope 00123 QCA::Initializer init; 00124 00125 ClientPassphraseHandler cph; 00126 00127 // handler and asker cannot occur in the same thread 00128 AskerThread askerThread; 00129 QObject::connect(&askerThread, SIGNAL(finished()), &exampleApp, SLOT(quit())); 00130 askerThread.start(); 00131 00132 exampleApp.exec(); 00133 return 0; 00134 } 00135 00136 void asker_procedure() 00137 { 00138 QCA::PasswordAsker pwAsker; 00139 00140 pwAsker.ask( QCA::Event::StylePassword, "foo.tmp", 0 ); 00141 00142 pwAsker.waitForResponse(); 00143 00144 std::cout << "Password was: " << pwAsker.password().toByteArray().data() << std::endl; 00145 00146 std::cout << std::endl << "Now do token:" << std::endl; 00147 00148 QCA::TokenAsker tokenAsker; 00149 00150 tokenAsker.ask( QCA::KeyStoreInfo( QCA::KeyStore::SmartCard, "Token Id", "Token Name" ), QCA::KeyStoreEntry(), 0 ); 00151 00152 tokenAsker.waitForResponse(); 00153 00154 if ( tokenAsker.accepted() ) { 00155 std::cout << "Token was accepted" << std::endl; 00156 } else { 00157 std::cout << "Token was not accepted" << std::endl; 00158 } 00159 } 00160 00161 #include "eventhandlerdemo.moc"