2007-05-03 22:14:13 +00:00
# include <QtCore>
# include <QtGui>
# include <QtCrypto>
# include "ui_mainwin.h"
# include "mylistview.h"
# include "ui_loadstore.h"
# include "ui_modconfig.h"
QString escape ( const QString & in )
{
QString out ;
for ( int n = 0 ; n < in . length ( ) ; + + n )
{
if ( in [ n ] = = ' \\ ' )
out + = " \\ \\ " ;
else if ( in [ n ] = = ' : ' )
out + = " \\ c " ;
else
out + = in [ n ] ;
}
return out ;
}
QString unescape ( const QString & in )
{
QString out ;
for ( int n = 0 ; n < in . length ( ) ; + + n )
{
if ( in [ n ] = = ' \\ ' )
{
if ( n + 1 < in . length ( ) )
{
+ + n ;
if ( in [ n ] = = ' \\ ' )
out + = ' \\ ' ;
else if ( in [ n ] = = ' c ' )
out + = ' : ' ;
}
}
else
out + = in [ n ] ;
}
return out ;
}
class IdentityItem
{
public :
enum Type { File , Entry } ;
Type type ;
QString name ;
QString fileName ;
QCA : : KeyStoreEntry entry ;
QCA : : SecureArray password ; // for runtime of File type only
bool usable ;
QString toString ( ) const
{
QStringList parts ;
if ( type = = File )
{
parts + = " file " ;
parts + = name ;
parts + = fileName ;
}
else // Entry
{
parts + = " entry " ;
parts + = name ;
parts + = entry . toString ( ) ;
}
for ( int n = 0 ; n < parts . count ( ) ; + + n )
parts [ n ] = escape ( parts [ n ] ) ;
return parts . join ( " : " ) ;
}
bool fromString ( const QString & in )
{
QStringList parts = in . split ( ' : ' ) ;
for ( int n = 0 ; n < parts . count ( ) ; + + n )
parts [ n ] = unescape ( parts [ n ] ) ;
if ( parts . count ( ) < 3 )
return false ;
usable = false ;
if ( parts [ 0 ] = = " file " )
{
type = File ;
name = parts [ 1 ] ;
fileName = parts [ 2 ] ;
if ( QFile : : exists ( fileName ) )
usable = true ;
}
else if ( parts [ 0 ] = = " entry " )
{
type = Entry ;
name = parts [ 1 ] ;
entry = QCA : : KeyStoreEntry ( parts [ 2 ] ) ;
if ( ! entry . isNull ( ) )
usable = true ;
}
else
return false ;
return true ;
}
} ;
class IdentityListModel : public QAbstractListModel
{
Q_OBJECT
//private:
public :
QList < IdentityItem > list ;
public :
IdentityListModel ( QObject * parent = 0 ) :
QAbstractListModel ( parent )
{
}
int rowCount ( const QModelIndex & parent = QModelIndex ( ) ) const
{
Q_UNUSED ( parent ) ;
return list . count ( ) ;
}
QVariant data ( const QModelIndex & index , int role ) const
{
if ( ! index . isValid ( ) )
return QVariant ( ) ;
if ( index . row ( ) > = list . count ( ) )
return QVariant ( ) ;
if ( role = = Qt : : DisplayRole )
{
return list [ index . row ( ) ] . name ;
}
else if ( role = = Qt : : DecorationRole )
{
const IdentityItem & i = list [ index . row ( ) ] ;
if ( i . type = = IdentityItem : : File )
return QPixmap ( " :/gfx/key.png " ) ;
else // Entry
return QPixmap ( " :/gfx/key.png " ) ;
}
else
return QVariant ( ) ;
}
void addItem ( const IdentityItem & i )
{
beginInsertRows ( QModelIndex ( ) , list . size ( ) , list . size ( ) ) ;
list + = i ;
endInsertRows ( ) ;
}
void removeItem ( int at )
{
beginRemoveRows ( QModelIndex ( ) , at , at ) ;
list . removeAt ( at ) ;
endRemoveRows ( ) ;
}
QString getUniqueName ( const QString & name )
{
int num = 1 ;
while ( 1 )
{
QString tryname ;
if ( num = = 1 )
tryname = name ;
else
tryname = name + QString ( " (%1) " ) . arg ( num ) ;
bool found = false ;
foreach ( const IdentityItem & i , list )
{
if ( i . name = = tryname )
{
found = true ;
break ;
}
}
if ( ! found )
return tryname ;
+ + num ;
}
}
} ;
class KnownItem
{
public :
QString name ;
QCA : : Certificate cert ;
QString toString ( ) const
{
QStringList parts ;
parts + = name ;
parts + = QCA : : Base64 ( ) . arrayToString ( cert . toDER ( ) ) ;
for ( int n = 0 ; n < parts . count ( ) ; + + n )
parts [ n ] = escape ( parts [ n ] ) ;
return parts . join ( " : " ) ;
}
bool fromString ( const QString & in )
{
QStringList parts = in . split ( ' : ' ) ;
for ( int n = 0 ; n < parts . count ( ) ; + + n )
parts [ n ] = unescape ( parts [ n ] ) ;
if ( parts . count ( ) < 2 )
return false ;
name = parts [ 0 ] ;
cert = QCA : : Certificate : : fromDER ( QCA : : Base64 ( ) . stringToArray ( parts [ 1 ] ) ) ;
if ( cert . isNull ( ) )
return false ;
return true ;
}
} ;
class KnownListModel : public QAbstractListModel
{
Q_OBJECT
//private:
public :
QList < KnownItem > list ;
public :
KnownListModel ( QObject * parent = 0 ) :
QAbstractListModel ( parent )
{
}
int rowCount ( const QModelIndex & parent = QModelIndex ( ) ) const
{
Q_UNUSED ( parent ) ;
return list . count ( ) ;
}
QVariant data ( const QModelIndex & index , int role ) const
{
if ( ! index . isValid ( ) )
return QVariant ( ) ;
if ( index . row ( ) > = list . count ( ) )
return QVariant ( ) ;
if ( role = = Qt : : DisplayRole )
{
return list [ index . row ( ) ] . name ;
}
else if ( role = = Qt : : DecorationRole )
{
return QPixmap ( " :/gfx/key.png " ) ;
}
else
return QVariant ( ) ;
}
void addItem ( const KnownItem & i )
{
beginInsertRows ( QModelIndex ( ) , list . size ( ) , list . size ( ) ) ;
list + = i ;
endInsertRows ( ) ;
}
void removeItem ( int at )
{
beginRemoveRows ( QModelIndex ( ) , at , at ) ;
list . removeAt ( at ) ;
endRemoveRows ( ) ;
}
} ;
class Operation : public QObject
{
Q_OBJECT
public :
Operation ( QObject * parent = 0 ) :
QObject ( parent )
{
}
signals :
void error ( const QString & str ) ;
} ;
class SignOperation : public Operation
{
Q_OBJECT
private :
QByteArray in ;
IdentityItem * item ;
QCA : : CMS * cms ;
QCA : : KeyLoader * loader ;
QCA : : KeyBundle key ;
QCA : : SecureMessage * msg ;
public :
SignOperation ( const QByteArray & _in , IdentityItem * _item , QCA : : CMS * _cms , QObject * parent = 0 ) :
Operation ( parent ) ,
in ( _in ) ,
item ( _item ) ,
cms ( _cms ) ,
loader ( 0 ) ,
msg ( 0 )
{
if ( item - > type = = IdentityItem : : File )
{
loader = new QCA : : KeyLoader ( this ) ;
connect ( loader , SIGNAL ( finished ( ) ) , SLOT ( loaded ( ) ) ) ;
loader - > loadKeyBundleFromFile ( item - > fileName ) ;
}
else // Entry
{
key = item - > entry . keyBundle ( ) ;
QMetaObject : : invokeMethod ( this , " do_sign " , Qt : : QueuedConnection ) ;
}
}
~ SignOperation ( )
{
}
signals :
void finished ( const QString & sig ) ;
private slots :
void loaded ( )
{
if ( loader - > convertResult ( ) ! = QCA : : ConvertGood )
{
emit error ( tr ( " Error opening key file. " ) ) ;
return ;
}
key = loader - > keyBundle ( ) ;
delete loader ;
loader = 0 ;
do_sign ( ) ;
}
void do_sign ( )
{
printf ( " do_sign \n " ) ;
QCA : : SecureMessageKey signer ;
signer . setX509CertificateChain ( key . certificateChain ( ) ) ;
signer . setX509PrivateKey ( key . privateKey ( ) ) ;
msg = new QCA : : SecureMessage ( cms ) ;
connect ( msg , SIGNAL ( finished ( ) ) , SLOT ( msg_finished ( ) ) ) ;
msg - > setFormat ( QCA : : SecureMessage : : Ascii ) ;
msg - > setSigner ( signer ) ;
msg - > startSign ( QCA : : SecureMessage : : Detached ) ;
update ( ) ;
}
void update ( )
{
printf ( " update \n " ) ;
QByteArray buf = in . mid ( 0 , 16384 ) ; // 16k chunks
in = in . mid ( buf . size ( ) ) ;
msg - > update ( buf ) ;
if ( in . isEmpty ( ) )
msg - > end ( ) ;
else
QMetaObject : : invokeMethod ( this , " update " , Qt : : QueuedConnection ) ;
}
void msg_finished ( )
{
printf ( " msg_finished \n " ) ;
if ( ! msg - > success ( ) )
{
delete msg ;
msg = 0 ;
emit error ( tr ( " Error during sign operation. " ) ) ;
return ;
}
QByteArray result = msg - > signature ( ) ;
delete msg ;
msg = 0 ;
emit finished ( QString : : fromLatin1 ( result ) ) ;
}
} ;
class VerifyOperation : public Operation
{
Q_OBJECT
private :
QByteArray in , sig ;
QCA : : CMS * cms ;
QCA : : SecureMessage * msg ;
public :
VerifyOperation ( const QByteArray & _in , const QByteArray & _sig , QCA : : CMS * _cms , QObject * parent = 0 ) :
Operation ( parent ) ,
in ( _in ) ,
sig ( _sig ) ,
cms ( _cms ) ,
msg ( 0 )
{
printf ( " do_verify \n " ) ;
msg = new QCA : : SecureMessage ( cms ) ;
connect ( msg , SIGNAL ( finished ( ) ) , SLOT ( msg_finished ( ) ) ) ;
msg - > setFormat ( QCA : : SecureMessage : : Ascii ) ;
msg - > startVerify ( sig ) ;
QMetaObject : : invokeMethod ( this , " update " , Qt : : QueuedConnection ) ;
}
signals :
void finished ( ) ;
private slots :
void update ( )
{
printf ( " update \n " ) ;
QByteArray buf = in . mid ( 0 , 16384 ) ; // 16k chunks
in = in . mid ( buf . size ( ) ) ;
msg - > update ( buf ) ;
if ( in . isEmpty ( ) )
msg - > end ( ) ;
else
QMetaObject : : invokeMethod ( this , " update " , Qt : : QueuedConnection ) ;
}
void msg_finished ( )
{
printf ( " msg_finished \n " ) ;
if ( ! msg - > success ( ) )
{
delete msg ;
msg = 0 ;
emit error ( tr ( " Error during verify operation. " ) ) ;
return ;
}
QCA : : SecureMessageSignature signer = msg - > signer ( ) ;
QCA : : SecureMessageSignature : : IdentityResult r = signer . identityResult ( ) ;
delete msg ;
msg = 0 ;
if ( r ! = QCA : : SecureMessageSignature : : Valid )
{
emit error ( tr ( " Verification failed! [%1] " ) . arg ( ( int ) r ) ) ;
return ;
}
emit finished ( ) ;
}
} ;
QAction * actionView , * actionRename , * actionRemove ;
MyListView : : MyListView ( QWidget * parent ) :
QListView ( parent )
{
}
void MyListView : : contextMenuEvent ( QContextMenuEvent * event )
{
QItemSelection selection = selectionModel ( ) - > selection ( ) ;
if ( selection . indexes ( ) . isEmpty ( ) )
return ;
QMenu menu ( this ) ;
menu . addAction ( actionView ) ;
menu . addAction ( actionRename ) ;
menu . addAction ( actionRemove ) ;
menu . exec ( event - > globalPos ( ) ) ;
}
static QString entryTypeToString ( QCA : : KeyStoreEntry : : Type type )
{
QString out ;
switch ( type )
{
case QCA : : KeyStoreEntry : : TypeKeyBundle : out = " X " ; break ;
case QCA : : KeyStoreEntry : : TypeCertificate : out = " C " ; break ;
case QCA : : KeyStoreEntry : : TypeCRL : out = " R " ; break ;
case QCA : : KeyStoreEntry : : TypePGPSecretKey : out = " S " ; break ;
case QCA : : KeyStoreEntry : : TypePGPPublicKey : out = " P " ; break ;
default : out = " U " ; break ;
}
return out ;
}
class KeyStoreModel : public QStandardItemModel
{
Q_OBJECT
public :
QCA : : KeyStoreManager ksm ;
QList < QCA : : KeyStore * > stores ;
QList < QStandardItem * > storeItems ;
QList < QList < QCA : : KeyStoreEntry > > storeEntries ;
QList < QList < QStandardItem * > > storeEntryItems ;
KeyStoreModel ( QObject * parent = 0 ) :
QStandardItemModel ( parent ) , ksm ( this )
{
// make sure keystores are started
QCA : : KeyStoreManager : : start ( ) ;
connect ( & ksm , SIGNAL ( keyStoreAvailable ( const QString & ) ) , SLOT ( ks_available ( const QString & ) ) ) ;
QStringList list = ksm . keyStores ( ) ;
foreach ( const QString & s , list )
ks_available ( s ) ;
}
private slots :
void ks_available ( const QString & keyStoreId )
{
QCA : : KeyStore * ks = new QCA : : KeyStore ( keyStoreId , & ksm ) ;
connect ( ks , SIGNAL ( updated ( ) ) , SLOT ( ks_updated ( ) ) ) ;
connect ( ks , SIGNAL ( unavailable ( ) ) , SLOT ( ks_unavailable ( ) ) ) ;
stores + = ks ;
ks - > startAsynchronousMode ( ) ;
QStandardItem * item = new QStandardItem ( ks - > name ( ) ) ;
storeItems + = item ;
storeEntries + = QList < QCA : : KeyStoreEntry > ( ) ;
storeEntryItems + = QList < QStandardItem * > ( ) ;
appendRow ( item ) ;
}
void ks_updated ( )
{
QCA : : KeyStore * ks = ( QCA : : KeyStore * ) sender ( ) ;
int at = stores . indexOf ( ks ) ;
QList < QCA : : KeyStoreEntry > entries = ks - > entryList ( ) ;
// only list keybundles
/*for(int n = 0; n < entries.count(); ++n)
{
if ( entries [ n ] . type ( ) ! = QCA : : KeyStoreEntry : : TypeKeyBundle )
{
entries . removeAt ( n ) ;
- - n ; // adjust position
}
} */
storeEntries [ at ] = entries ;
storeEntryItems [ at ] . clear ( ) ;
foreach ( const QCA : : KeyStoreEntry & entry , entries )
{
QStandardItem * item = new QStandardItem ( entryTypeToString ( entry . type ( ) ) + " - " + entry . name ( ) ) ;
storeEntryItems [ at ] + = item ;
storeItems [ at ] - > appendRow ( item ) ;
}
}
void ks_unavailable ( )
{
QCA : : KeyStore * ks = ( QCA : : KeyStore * ) sender ( ) ;
Q_UNUSED ( ks ) ;
// TODO
}
} ;
class LoadStore : public QDialog
{
Q_OBJECT
private :
Ui_LoadStore ui ;
KeyStoreModel * model ;
QCA : : KeyStoreEntry cur_entry ;
public :
LoadStore ( QWidget * parent = 0 ) :
QDialog ( parent )
{
ui . setupUi ( this ) ;
ui . lv_stores - > header ( ) - > hide ( ) ;
ui . buttonBox - > button ( QDialogButtonBox : : Ok ) - > setEnabled ( false ) ;
model = new KeyStoreModel ( this ) ;
ui . lv_stores - > setModel ( model ) ;
connect ( ui . lv_stores - > selectionModel ( ) , SIGNAL ( selectionChanged ( const QItemSelection & , const QItemSelection & ) ) , SLOT ( stores_selectionChanged ( const QItemSelection & , const QItemSelection & ) ) ) ;
}
signals :
void entrySelected ( const QCA : : KeyStoreEntry & entry ) ;
protected slots :
virtual void accept ( )
{
QCA : : KeyStoreEntry entry = cur_entry ;
QDialog : : accept ( ) ;
emit entrySelected ( entry ) ;
}
private slots :
void stores_selectionChanged ( const QItemSelection & selected , const QItemSelection & deselected )
{
Q_UNUSED ( deselected ) ;
bool valid = false ;
QCA : : KeyStoreEntry entry ;
{
QModelIndex index ;
if ( ! selected . indexes ( ) . isEmpty ( ) )
index = selected . indexes ( ) . first ( ) ;
if ( index . isValid ( ) )
{
QModelIndex pindex = index . parent ( ) ;
// are we clicking on an entry?
if ( pindex . isValid ( ) )
{
int store_at = pindex . row ( ) ;
int entry_at = index . row ( ) ;
entry = model - > storeEntries [ store_at ] [ entry_at ] ;
if ( entry . type ( ) = = QCA : : KeyStoreEntry : : TypeKeyBundle )
valid = true ;
}
}
}
if ( valid )
cur_entry = entry ;
else
cur_entry = QCA : : KeyStoreEntry ( ) ;
QPushButton * ok = ui . buttonBox - > button ( QDialogButtonBox : : Ok ) ;
if ( valid & & ! ok - > isEnabled ( ) )
ok - > setEnabled ( true ) ;
else if ( ! valid & & ok - > isEnabled ( ) )
ok - > setEnabled ( false ) ;
}
} ;
// support for the 'http://affinix.com/qca/forms/qca-pkcs11#1.0' provider form
class ModItem
{
public :
QString name ; // must be unique among all modules
QString library ; // dll
bool enabled ;
bool allow_protected_auth ;
bool cert_private ;
int private_mask ;
QString slotevent_method ;
int slotevent_timeout ;
ModItem ( ) :
enabled ( false ) ,
allow_protected_auth ( true ) ,
cert_private ( false ) ,
private_mask ( 0 ) ,
slotevent_method ( " auto " ) ,
slotevent_timeout ( 0 )
{
}
} ;
class ModListModel : public QAbstractListModel
{
Q_OBJECT
//private:
public :
QList < ModItem > list ;
public :
ModListModel ( QObject * parent = 0 ) :
QAbstractListModel ( parent )
{
}
int rowCount ( const QModelIndex & parent = QModelIndex ( ) ) const
{
Q_UNUSED ( parent ) ;
return list . count ( ) ;
}
QVariant data ( const QModelIndex & index , int role ) const
{
if ( ! index . isValid ( ) )
return QVariant ( ) ;
if ( index . row ( ) > = list . count ( ) )
return QVariant ( ) ;
if ( role = = Qt : : DisplayRole )
{
return list [ index . row ( ) ] . name ;
}
/*else if(role == Qt::DecorationRole)
{
return QPixmap ( " :/gfx/key.png " ) ;
} */
else
return QVariant ( ) ;
}
void addItem ( const ModItem & i )
{
beginInsertRows ( QModelIndex ( ) , list . size ( ) , list . size ( ) ) ;
list + = i ;
endInsertRows ( ) ;
}
void removeItem ( int at )
{
beginRemoveRows ( QModelIndex ( ) , at , at ) ;
list . removeAt ( at ) ;
endRemoveRows ( ) ;
}
void updateItem ( int at )
{
QModelIndex i = index ( at ) ;
emit dataChanged ( i , i ) ;
}
} ;
class ModConfig : public QDialog
{
Q_OBJECT
private :
Ui_ModConfig ui ;
ModListModel * model ;
QString providerName ;
QVariantMap config ;
public :
ModConfig ( const QString & _providerName , const QVariantMap & _config , QWidget * parent = 0 ) :
QDialog ( parent ) ,
providerName ( _providerName ) ,
config ( _config )
{
ui . setupUi ( this ) ;
model = new ModListModel ( this ) ;
ui . lv_modules - > setModel ( model ) ;
connect ( ui . lv_modules - > selectionModel ( ) , SIGNAL ( selectionChanged ( const QItemSelection & , const QItemSelection & ) ) , SLOT ( modules_selectionChanged ( const QItemSelection & , const QItemSelection & ) ) ) ;
# if defined(Q_OS_WIN)
ui . lb_file - > setText ( " Module File (.dll): " ) ;
# elif defined(Q_OS_MAC)
ui . lb_file - > setText ( " Module File (.dylib): " ) ;
# else
ui . lb_file - > setText ( " Module File (.so): " ) ;
# endif
connect ( ui . pb_add , SIGNAL ( clicked ( ) ) , SLOT ( mod_add ( ) ) ) ;
connect ( ui . pb_remove , SIGNAL ( clicked ( ) ) , SLOT ( mod_remove ( ) ) ) ;
connect ( ui . pb_browse , SIGNAL ( clicked ( ) ) , SLOT ( mod_browse ( ) ) ) ;
connect ( ui . le_name , SIGNAL ( textEdited ( const QString & ) ) , SLOT ( name_edited ( const QString & ) ) ) ;
connect ( ui . le_library , SIGNAL ( textEdited ( const QString & ) ) , SLOT ( library_edited ( const QString & ) ) ) ;
ui . pb_remove - > setEnabled ( false ) ;
ui . gb_details - > setEnabled ( false ) ;
// TODO: config integrity check
// FIXME: this reorders the provider config. we may not want that
for ( int n = 0 ; n < 10 ; + + n )
{
ModItem i ;
QString prefix = QString ( ) . sprintf ( " provider_%02d_ " , n ) ;
i . name = config [ prefix + " name " ] . toString ( ) ;
if ( i . name . isEmpty ( ) )
continue ;
i . library = config [ prefix + " library " ] . toString ( ) ;
i . enabled = config [ prefix + " enabled " ] . toBool ( ) ;
i . allow_protected_auth = config [ prefix + " allow_protected_authentication " ] . toBool ( ) ;
i . cert_private = config [ prefix + " cert_private " ] . toBool ( ) ;
i . private_mask = config [ prefix + " private_mask " ] . toInt ( ) ;
i . slotevent_method = config [ prefix + " slotevent_method " ] . toString ( ) ;
i . slotevent_timeout = config [ prefix + " slotevent_method " ] . toInt ( ) ;
model - > addItem ( i ) ;
}
if ( ! model - > list . isEmpty ( ) )
ui . lv_modules - > selectionModel ( ) - > select ( model - > index ( 0 ) , QItemSelectionModel : : Clear | QItemSelectionModel : : Select | QItemSelectionModel : : Current ) ;
}
protected slots :
virtual void accept ( )
{
for ( int n = 0 ; n < 10 | | n < model - > list . count ( ) ; + + n )
{
ModItem i ;
if ( n < model - > list . count ( ) )
i = model - > list [ n ] ;
else
i = ModItem ( ) ; // default for padded items
QString prefix = QString ( ) . sprintf ( " provider_%02d_ " , n ) ;
config [ prefix + " name " ] = i . name ;
config [ prefix + " library " ] = i . library ;
config [ prefix + " enabled " ] = i . enabled ;
config [ prefix + " allow_protected_authentication " ] = i . allow_protected_auth ;
config [ prefix + " cert_private " ] = i . cert_private ;
config [ prefix + " private_mask " ] = i . private_mask ;
config [ prefix + " slotevent_method " ] = i . slotevent_method ;
config [ prefix + " slotevent_method " ] = i . slotevent_timeout ;
}
QCA : : setProviderConfig ( providerName , config ) ;
QCA : : saveProviderConfig ( providerName ) ;
QDialog : : accept ( ) ;
}
private slots :
void modules_selectionChanged ( const QItemSelection & selected , const QItemSelection & deselected )
{
Q_UNUSED ( deselected ) ;
if ( ! selected . indexes ( ) . isEmpty ( ) )
{
if ( ! ui . pb_remove - > isEnabled ( ) )
{
ui . pb_remove - > setEnabled ( true ) ;
ui . gb_details - > setEnabled ( true ) ;
}
QModelIndex index = selected . indexes ( ) . first ( ) ;
// TODO: ensure plaintext only
ui . le_name - > setText ( model - > list [ index . row ( ) ] . name ) ;
ui . le_library - > setText ( model - > list [ index . row ( ) ] . library ) ;
}
else if ( selected . indexes ( ) . isEmpty ( ) & & ui . pb_remove - > isEnabled ( ) )
{
ui . le_name - > setText ( " " ) ;
ui . le_library - > setText ( " " ) ;
ui . pb_remove - > setEnabled ( false ) ;
ui . gb_details - > setEnabled ( false ) ;
}
}
void name_edited ( const QString & text )
{
QItemSelection selection = ui . lv_modules - > selectionModel ( ) - > selection ( ) ;
if ( selection . indexes ( ) . isEmpty ( ) )
return ;
QModelIndex index = selection . indexes ( ) . first ( ) ;
int at = index . row ( ) ;
model - > list [ at ] . name = text ;
model - > updateItem ( at ) ;
}
void library_edited ( const QString & text )
{
QItemSelection selection = ui . lv_modules - > selectionModel ( ) - > selection ( ) ;
if ( selection . indexes ( ) . isEmpty ( ) )
return ;
QModelIndex index = selection . indexes ( ) . first ( ) ;
int at = index . row ( ) ;
model - > list [ at ] . library = text ;
}
void mod_add ( )
{
ModItem i ;
i . name = " New Module " ;
i . enabled = true ;
model - > addItem ( i ) ;
ui . lv_modules - > selectionModel ( ) - > select ( model - > index ( model - > list . count ( ) - 1 ) , QItemSelectionModel : : Clear | QItemSelectionModel : : Select | QItemSelectionModel : : Current ) ;
ui . le_name - > setFocus ( ) ;
ui . le_name - > selectAll ( ) ;
}
void mod_remove ( )
{
QItemSelection selection = ui . lv_modules - > selectionModel ( ) - > selection ( ) ;
if ( selection . indexes ( ) . isEmpty ( ) )
return ;
QModelIndex index = selection . indexes ( ) . first ( ) ;
model - > removeItem ( index . row ( ) ) ;
}
void mod_browse ( )
{
QString spec ;
// FIXME: is this too restrictive?
# if defined(Q_OS_WIN)
spec = " (*.dll) " ;
# elif defined(Q_OS_MAC)
spec = " (*.dylib) " ;
# else
spec = " (*.so) " ;
# endif
QString fileName = QFileDialog : : getOpenFileName ( this , tr ( " Select PKCS#11 Module " ) , QString ( ) , tr ( " PKCS#11 Modules " ) + ' ' + spec ) ;
if ( fileName . isEmpty ( ) )
return ;
ui . le_library - > setText ( fileName ) ;
library_edited ( fileName ) ;
}
} ;
class MainWin : public QMainWindow
{
Q_OBJECT
private :
Ui_MainWin ui ;
QCA : : EventHandler * eventHandler ;
QCA : : SecureArray lastPassword ;
QCA : : KeyLoader * keyLoader ;
QString keyLoader_fileName ;
IdentityListModel * model ;
KnownListModel * known ;
QCA : : CMS * cms ;
Operation * op ;
public :
MainWin ( QWidget * parent = 0 ) :
QMainWindow ( parent ) ,
keyLoader ( 0 ) ,
op ( 0 )
{
ui . setupUi ( this ) ;
actionView = new QAction ( tr ( " &View " ) , this ) ;
actionRename = new QAction ( tr ( " Re&name " ) , this ) ;
actionRemove = new QAction ( tr ( " Rem&ove " ) , this ) ;
// TODO
actionView - > setEnabled ( false ) ;
connect ( ui . actionLoad_Identity_From_File , SIGNAL ( triggered ( ) ) , SLOT ( load_file ( ) ) ) ;
connect ( ui . actionLoad_Identity_From_Storage_Device , SIGNAL ( triggered ( ) ) , SLOT ( load_device ( ) ) ) ;
connect ( ui . actionConfigure_PKCS_11_Modules , SIGNAL ( triggered ( ) ) , SLOT ( mod_config ( ) ) ) ;
connect ( ui . actionQuit , SIGNAL ( triggered ( ) ) , SLOT ( close ( ) ) ) ;
connect ( ui . actionAbout_CMS_Signer , SIGNAL ( triggered ( ) ) , SLOT ( about ( ) ) ) ;
connect ( ui . pb_sign , SIGNAL ( clicked ( ) ) , SLOT ( do_sign ( ) ) ) ;
connect ( ui . pb_verify , SIGNAL ( clicked ( ) ) , SLOT ( do_verify ( ) ) ) ;
connect ( actionView , SIGNAL ( triggered ( ) ) , SLOT ( item_view ( ) ) ) ;
connect ( actionRename , SIGNAL ( triggered ( ) ) , SLOT ( item_rename ( ) ) ) ;
connect ( actionRemove , SIGNAL ( triggered ( ) ) , SLOT ( item_remove ( ) ) ) ;
ui . pb_sign - > setEnabled ( false ) ;
eventHandler = new QCA : : EventHandler ( this ) ;
connect ( eventHandler , SIGNAL ( eventReady ( int , const QCA : : Event & ) ) , SLOT ( eh_eventReady ( int , const QCA : : Event & ) ) ) ;
eventHandler - > start ( ) ;
model = new IdentityListModel ( this ) ;
ui . lv_identities - > setModel ( model ) ;
connect ( ui . lv_identities - > selectionModel ( ) , SIGNAL ( selectionChanged ( const QItemSelection & , const QItemSelection & ) ) , SLOT ( identities_selectionChanged ( const QItemSelection & , const QItemSelection & ) ) ) ;
known = new KnownListModel ( this ) ;
ui . lv_known - > setModel ( known ) ;
ui . lv_identities - > model = model ;
ui . lv_known - > model = known ;
cms = new QCA : : CMS ( this ) ;
}
private slots :
void eh_eventReady ( int id , const QCA : : Event & event )
{
QString promptType ;
if ( event . passwordStyle ( ) = = QCA : : Event : : StylePassphrase )
promptType = tr ( " Passphrase " ) ;
else if ( event . passwordStyle ( ) = = QCA : : Event : : StylePIN )
promptType = tr ( " PIN " ) ;
else // Password
promptType = tr ( " Password " ) ;
QString promptStr = promptType + " : " ;
bool ok ;
QString pass = QInputDialog : : getText ( this , tr ( " CMS Signer " ) , promptStr , QLineEdit : : Password , QString ( ) , & ok ) ;
if ( ! ok )
{
eventHandler - > reject ( id ) ;
return ;
}
QCA : : SecureArray password = pass . toUtf8 ( ) ;
// cache file passwords
if ( event . source ( ) = = QCA : : Event : : Data )
lastPassword = password ;
eventHandler - > submitPassword ( id , password ) ;
}
void load_file ( )
{
2007-05-04 21:26:08 +00:00
QString fileName = QFileDialog : : getOpenFileName ( this , tr ( " Open File " ) , QString ( ) , tr ( " X.509 Identities (*.p12 *.pfx) " ) ) ;
2007-05-03 22:14:13 +00:00
if ( fileName . isEmpty ( ) )
return ;
setEnabled ( false ) ;
keyLoader = new QCA : : KeyLoader ( this ) ;
connect ( keyLoader , SIGNAL ( finished ( ) ) , SLOT ( load_file_finished ( ) ) ) ;
keyLoader_fileName = fileName ;
keyLoader - > loadKeyBundleFromFile ( fileName ) ;
}
void load_device ( )
{
LoadStore * w = new LoadStore ( this ) ;
w - > setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
w - > setWindowModality ( Qt : : WindowModal ) ;
connect ( w , SIGNAL ( entrySelected ( const QCA : : KeyStoreEntry & ) ) , SLOT ( load_device_finished ( const QCA : : KeyStoreEntry & ) ) ) ;
w - > show ( ) ;
}
void load_file_finished ( )
{
if ( keyLoader - > convertResult ( ) ! = QCA : : ConvertGood )
{
setEnabled ( true ) ;
QMessageBox : : information ( this , tr ( " Error " ) , tr ( " Error opening key file. " ) ) ;
return ;
}
QCA : : KeyBundle kb = keyLoader - > keyBundle ( ) ;
delete keyLoader ;
keyLoader = 0 ;
QCA : : Certificate cert = kb . certificateChain ( ) . primary ( ) ;
QString name = model - > getUniqueName ( cert . commonName ( ) ) ;
// TODO: check for duplicate identities?
IdentityItem i ;
i . type = IdentityItem : : File ;
i . name = name ;
i . fileName = keyLoader_fileName ;
i . password = lastPassword ;
i . usable = true ;
lastPassword . clear ( ) ;
model - > addItem ( i ) ;
ui . lv_identities - > selectionModel ( ) - > select ( model - > index ( model - > list . count ( ) - 1 ) , QItemSelectionModel : : Clear | QItemSelectionModel : : Select | QItemSelectionModel : : Current ) ;
// TODO: give unique names to knowns? check for dups also?
KnownItem ki ;
ki . name = i . name ;
ki . cert = cert ;
known - > addItem ( ki ) ;
setEnabled ( true ) ;
}
void load_device_finished ( const QCA : : KeyStoreEntry & entry )
{
QCA : : KeyBundle kb = entry . keyBundle ( ) ;
QCA : : Certificate cert = kb . certificateChain ( ) . primary ( ) ;
QString name = model - > getUniqueName ( entry . name ( ) ) ;
IdentityItem i ;
i . type = IdentityItem : : Entry ;
i . name = name ;
i . entry = entry ;
i . usable = true ;
model - > addItem ( i ) ;
ui . lv_identities - > selectionModel ( ) - > select ( model - > index ( model - > list . count ( ) - 1 ) , QItemSelectionModel : : Clear | QItemSelectionModel : : Select | QItemSelectionModel : : Current ) ;
KnownItem ki ;
ki . name = i . name ;
ki . cert = cert ;
known - > addItem ( ki ) ;
setEnabled ( true ) ;
}
void mod_config ( )
{
QCA : : ProviderList providers = QCA : : providers ( ) ;
providers + = QCA : : defaultProvider ( ) ;
QCA : : Provider * provider = 0 ;
QVariantMap config ;
foreach ( QCA : : Provider * p , providers )
{
config = QCA : : getProviderConfig ( p - > name ( ) ) ;
if ( ! config . isEmpty ( ) & & config [ " formtype " ] = = " http://affinix.com/qca/forms/qca-pkcs11#1.0 " )
{
provider = p ;
break ;
}
}
if ( ! provider )
{
QMessageBox : : information ( this , tr ( " Error " ) , tr ( " No provider available supporting standard PKCS#11 configuration. " ) ) ;
return ;
}
ModConfig * w = new ModConfig ( provider - > name ( ) , config , this ) ;
w - > setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
w - > setWindowModality ( Qt : : WindowModal ) ;
w - > show ( ) ;
}
void identities_selectionChanged ( const QItemSelection & selected , const QItemSelection & deselected )
{
Q_UNUSED ( deselected ) ;
if ( ! selected . indexes ( ) . isEmpty ( ) & & ! ui . pb_sign - > isEnabled ( ) )
ui . pb_sign - > setEnabled ( true ) ;
else if ( selected . indexes ( ) . isEmpty ( ) & & ui . pb_sign - > isEnabled ( ) )
ui . pb_sign - > setEnabled ( false ) ;
}
void item_view ( )
{
if ( ui . lv_identities - > hasFocus ( ) )
{
QItemSelection selection = ui . lv_identities - > selectionModel ( ) - > selection ( ) ;
if ( selection . indexes ( ) . isEmpty ( ) )
return ;
QModelIndex index = selection . indexes ( ) . first ( ) ;
identity_view ( index . row ( ) ) ;
}
else // lv_known
{
QItemSelection selection = ui . lv_known - > selectionModel ( ) - > selection ( ) ;
if ( selection . indexes ( ) . isEmpty ( ) )
return ;
QModelIndex index = selection . indexes ( ) . first ( ) ;
known_view ( index . row ( ) ) ;
}
}
void item_rename ( )
{
if ( ui . lv_identities - > hasFocus ( ) )
{
QItemSelection selection = ui . lv_identities - > selectionModel ( ) - > selection ( ) ;
if ( selection . indexes ( ) . isEmpty ( ) )
return ;
QModelIndex index = selection . indexes ( ) . first ( ) ;
identity_rename ( index . row ( ) ) ;
}
else // lv_known
{
QItemSelection selection = ui . lv_known - > selectionModel ( ) - > selection ( ) ;
if ( selection . indexes ( ) . isEmpty ( ) )
return ;
QModelIndex index = selection . indexes ( ) . first ( ) ;
known_rename ( index . row ( ) ) ;
}
}
void item_remove ( )
{
if ( ui . lv_identities - > hasFocus ( ) )
{
QItemSelection selection = ui . lv_identities - > selectionModel ( ) - > selection ( ) ;
if ( selection . indexes ( ) . isEmpty ( ) )
return ;
QModelIndex index = selection . indexes ( ) . first ( ) ;
identity_remove ( index . row ( ) ) ;
}
else // lv_known
{
QItemSelection selection = ui . lv_known - > selectionModel ( ) - > selection ( ) ;
if ( selection . indexes ( ) . isEmpty ( ) )
return ;
QModelIndex index = selection . indexes ( ) . first ( ) ;
known_remove ( index . row ( ) ) ;
}
}
void identity_view ( int at )
{
printf ( " identity_view: %d \n " , at ) ;
}
void identity_rename ( int at )
{
printf ( " identity_rename: %d \n " , at ) ;
}
void identity_remove ( int at )
{
model - > removeItem ( at ) ;
}
void known_view ( int at )
{
printf ( " known_view: %d \n " , at ) ;
}
void known_rename ( int at )
{
printf ( " known_rename: %d \n " , at ) ;
}
void known_remove ( int at )
{
known - > removeItem ( at ) ;
}
void do_sign ( )
{
op = new SignOperation ( ui . te_data - > toPlainText ( ) . toUtf8 ( ) , & model - > list [ 0 ] , cms , this ) ;
connect ( op , SIGNAL ( finished ( const QString & ) ) , SLOT ( sign_finished ( const QString & ) ) ) ;
connect ( op , SIGNAL ( error ( const QString & ) ) , SLOT ( op_error ( const QString & ) ) ) ;
}
void do_verify ( )
{
// get known
QCA : : CertificateCollection col ;
foreach ( const KnownItem & i , known - > list )
col . addCertificate ( i . cert ) ;
col + = QCA : : systemStore ( ) ;
cms - > setTrustedCertificates ( col ) ;
op = new VerifyOperation ( ui . te_data - > toPlainText ( ) . toUtf8 ( ) , ui . te_sig - > toPlainText ( ) . toUtf8 ( ) , cms , this ) ;
connect ( op , SIGNAL ( finished ( ) ) , SLOT ( verify_finished ( ) ) ) ;
connect ( op , SIGNAL ( error ( const QString & ) ) , SLOT ( op_error ( const QString & ) ) ) ;
}
void about ( )
{
QMessageBox : : about ( this , tr ( " About CMS Signer " ) , tr ( " CMS Signer v0.1 \n A simple tool for creating and verifying digital signatures. " ) ) ;
}
void sign_finished ( const QString & sig )
{
ui . te_sig - > setPlainText ( sig ) ;
}
void verify_finished ( )
{
QMessageBox : : information ( this , tr ( " Verify " ) , tr ( " Signature verified successfully. " ) ) ;
}
void op_error ( const QString & msg )
{
QMessageBox : : information ( this , tr ( " Error " ) , msg ) ;
delete op ;
op = 0 ;
}
} ;
int main ( int argc , char * * argv )
{
QCA : : Initializer qcaInit ;
QApplication qapp ( argc , argv ) ;
if ( ! QCA : : isSupported ( " cms " ) )
{
QMessageBox : : critical ( 0 , MainWin : : tr ( " CMS Signer: Error " ) , MainWin : : tr ( " No support for CMS is available. Please install an appropriate QCA plugin, such as qca-openssl. " ) ) ;
return 1 ;
}
MainWin mainWin ;
mainWin . show ( ) ;
return qapp . exec ( ) ;
}
# include "main.moc"