Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ClientReadCallback.cc

00001 /*
00002  * Copyright 2003 Michael A. Marsh, Cornell University. All rights reserved.
00003  * This software is released under the modified BSD license.
00004  * See the file LICENSE in the top-level directory for details.
00005  */
00006 //
00007 // $Id: ClientReadCallback.cc,v 1.5 2005/01/15 03:41:37 mmarsh Exp $
00008 //
00009 // $Log: ClientReadCallback.cc,v $
00010 // Revision 1.5  2005/01/15 03:41:37  mmarsh
00011 // Updated to work with more recent versions of g++.
00012 //
00013 // Revision 1.4  2004/05/19 15:56:51  mmarsh
00014 // *** empty log message ***
00015 //
00016 // Revision 1.3  2003/11/04 22:31:49  mmarsh
00017 // *** empty log message ***
00018 //
00019 //
00020 
00021 #include "ClientReadCallback.h"
00022 #include "CODEX_Events/Event.h"
00023 #include "CODEX_Server/ServerExceptions.h"
00024 #include "CODEX_Client/Message.h"
00025 #include "SupportedClientResponse.h"
00026 #include "CODEX_Server/SignRequestEvent.h"
00027 #include "ClientDelegation.h"
00028 #include "SignReadCallback.h"
00029 #include "CODEX_Server/ShareLabelChallenge.h"
00030 #include "CODEX_Server/BroadcastRequestEvent.h"
00031 #include "VerifiableBlindKeyMsg.h"
00032 
00033 #include "timing.h"
00034 
00035 using namespace CODEX_KeyService;
00036 
00037 ClientReadCallback::ClientReadCallback(
00038    CODEX_Events::DeadPileType& deadPile,
00039    CODEX_Events::QType& eventQueue,
00040    CODEX_Server::SignRequestHandler* destination,
00041    ClientResponseHandler* clientAct,
00042    const LabeledReadKeyMsg& req,
00043    const unsigned char* seqNum,
00044    CODEX_Server::BroadcastRequestHandler* reqHandler ) :
00045    ResponseCallback( seqNum ),
00046    CODEX_Events::Activity( deadPile, eventQueue ),
00047    m_destination( destination ),
00048    m_clientAct( clientAct ),
00049    m_request( req ),
00050    m_complete( false ),
00051    m_reqHandler( reqHandler )
00052 {
00053 }
00054 
00055 ClientReadCallback::~ClientReadCallback()
00056 {
00057    DigestMap::iterator dItr = m_digests.begin();
00058    DigestMap::iterator dEnd = m_digests.end();
00059    for ( ; dItr != dEnd ; ++dItr )
00060    {
00061       if ( 0 != dItr->second ) BN_free( dItr->second );
00062    }
00063 #ifndef ELGAMAL
00064    PartialMap::iterator pItr = m_partials.begin();
00065    PartialMap::iterator pEnd = m_partials.end();
00066    for ( ; pItr != pEnd ; ++pItr )
00067    {
00068       while ( pItr->second.size() )
00069       {
00070          delete pItr->second.back();
00071          pItr->second.pop_back();
00072       }
00073    }
00074 #endif
00075    ChallengeVector::iterator vItr = m_challenges.begin();
00076    ChallengeVector::iterator vEnd = m_challenges.end();
00077    for ( ; vItr != vEnd ; ++vItr )
00078    {
00079       delete *vItr;
00080    }
00081 }
00082 
00084 bool
00085 ClientReadCallback::operator()( unsigned int server,
00086                                 CODEX_Quorum::Message* msg )
00087 {
00088    if ( 0 == msg )
00089    {
00090       return false;
00091    }
00092 
00093    if ( m_complete )
00094    {
00095       delete msg;
00096       return true;
00097    }
00098 
00099 #ifdef TIMING
00100    ActiveTimer.start();
00101 #endif
00102 
00103    CODEX_Server::ServerState* serverState =
00104       CODEX_Server::ServerState::instance();
00105    if ( 0 == serverState )
00106    {
00107       delete msg;
00108 #ifdef TIMING
00109       ActiveTimer.stop();
00110 #endif
00111       return false;
00112    }
00113 
00114    StateInfo* stateInfo = StateInfo::instance();
00115    if ( 0 == stateInfo )
00116    {
00117       delete msg;
00118 #ifdef TIMING
00119       ActiveTimer.stop();
00120 #endif
00121       return false;
00122    }
00123 
00124    // Sanity check -- is the client still connected?
00125    if ( 0 == stateInfo->getActFromSeqNum( seqNum() ) )
00126    {
00127       delete msg;
00128 #ifdef TIMING
00129       ActiveTimer.stop();
00130 #endif
00131       return false;
00132    }
00133 
00134    CODEX_Quorum::QuorumSystem* qs = serverState->quorumSystem();
00135    if ( 0 == qs )
00136    {
00137       delete msg;
00138 #ifdef TIMING
00139       ActiveTimer.stop();
00140 #endif
00141       throw CODEX_Server::NoQuorumSystemException( __FILE__ , __LINE__ );
00142    }
00143 
00144    unsigned char* data = (unsigned char*)msg->buffer();
00145    int length = msg->length();
00146 
00147    if ( length < 2 )
00148    {
00149       delete msg;
00150 #ifdef TIMING
00151       ActiveTimer.stop();
00152 #endif
00153       return false;
00154    }
00155 
00156    // Check the message type.
00157    if ( stateInfo->delegationDomain() != data[0] )
00158    {
00159       delete msg;
00160 #ifdef TIMING
00161       ActiveTimer.stop();
00162 #endif
00163       return false;
00164    }
00165    ++data;
00166    --length;
00167 
00168    // Test a special condition
00169    if ( ClientDelegation::kBadShareLabel == data[0] )
00170    {
00171       cerr << __FILE__ << ", line " << __LINE__ << ":\n"
00172            << "   kBadShareLabel returned" << endl;
00173       ++data;
00174       --length;
00175       // We need to re-send the request with the new label, but only if
00176       // the label returned is actually valid.
00177       CODEX_Server::ServerState::LSType::LabelType label;
00178       if ( 0 == label.unmarshal( 0, &data, length ) )
00179       {
00180          // The response is no good.
00181          delete msg;
00182 #ifdef TIMING
00183          ActiveTimer.stop();
00184 #endif
00185          return false;
00186       }
00187       LabeledReadKeyMsg newReq( m_request, label );
00188       const unsigned char* newSeqNum = serverState->newSequenceNumber();
00189       stateInfo->registerSequenceNumber( newSeqNum, m_clientAct );
00190       ClientReadCallback* cb = new ClientReadCallback( m_deadPile,
00191                                                        m_queue,
00192                                                        m_destination,
00193                                                        m_clientAct,
00194                                                        newReq,
00195                                                        newSeqNum,
00196                                                        m_reqHandler );
00197 
00198       CODEX_Quorum::Message message;
00199 
00200       unsigned char self = serverState->hostNum();
00201       message.fill( self | CODEX_Server::ServerState::OutgoingMask );
00202       message.fill( newSeqNum, CODEX_Server::ServerState::nMID );
00203       message.fill( stateInfo->messageDomain() );
00204       message.fill( CODEX_Client::kReadKeyMsg | CODEX_Client::SignatureMask );
00205       int length = newReq.marshal(0);
00206       unsigned char* buffer = new unsigned char[length];
00207       unsigned char* pBuffer = buffer;
00208       newReq.marshal(&pBuffer);
00209       message.fill( buffer, length );
00210       delete [] buffer;
00211 
00212       // Create the outgoing event.
00213       CODEX_Server::BroadcastRequestEvent* outEvent =
00214          new CODEX_Server::BroadcastRequestEvent( 0,
00215                                                   m_reqHandler,
00216                                                   message,
00217                                                   cb );
00218       CODEX_Server::ShareLabelChallenge* slc =
00219          new CODEX_Server::ShareLabelChallenge( label, server, cb, outEvent );
00220       m_challenges.push_back( slc );
00221       if ( m_challenges.size() > qs->faultsTolerated() )
00222       {
00223          // register challenges
00224          ChallengeVector::iterator vItr = m_challenges.begin();
00225          ChallengeVector::iterator vEnd = m_challenges.end();
00226          for ( ; vItr != vEnd ; ++vItr )
00227          {
00228             serverState->addChallenge( seqNum() , *vItr );
00229          }
00230          m_challenges.clear();
00231          // No progress will be made on this request.
00232          m_complete = true;
00233       }
00234       delete msg;
00235 #ifdef TIMING
00236    ActiveTimer.stop();
00237 #endif
00238       return true;
00239    }
00240 
00241    if ( ClientDelegation::kApproveClientRequest != data[0] )
00242    {
00243       delete msg;
00244 #ifdef TIMING
00245       ActiveTimer.stop();
00246 #endif
00247       return false;
00248    }
00249    ++data;
00250    --length;
00251 
00252    // Check that it unmarshalls.
00253    typedef CODEX_Ciphers::RSASignature  SigType;
00254    typedef ShareType                    TDType;
00255    typedef BlindPlainTextType           BKType;
00256    unsigned char* oData = data;
00257 
00258    SigType signature;
00259    if ( 0 == signature.unmarshal( 0, &data, length ) )
00260    {
00261       delete msg;
00262 #ifdef TIMING
00263       ActiveTimer.stop();
00264 #endif
00265       return false;
00266    }
00267    length -= (data-oData);
00268    oData = data;
00269 
00270    BlindCipherTextType bct;
00271    if ( 0 == bct.unmarshal( 0, &data, length ) )
00272    {
00273       delete msg;
00274 #ifdef TIMING
00275       ActiveTimer.stop();
00276 #endif
00277       return false;
00278    }
00279    length -= (data-oData);
00280    oData = data;
00281 
00282    TDType* partialResults = new TDType;
00283    if ( 0 == partialResults->unmarshal( 0, &data, length ) )
00284    {
00285       delete msg;
00286       delete partialResults;
00287 #ifdef TIMING
00288       ActiveTimer.stop();
00289 #endif
00290       return false;
00291    }
00292    length -= (data-oData);
00293    oData = data;
00294 
00295 #ifdef ELGAMAL
00296    const CODEX_Ciphers::ElGamalPublicKey& serviceEGKey =
00297       serverState->publicEGKey();
00298    if ( ! serviceEGKey.initialized() )
00299    {
00300       delete msg;
00301       delete partialResults;
00302 #ifdef TIMING
00303       ActiveTimer.stop();
00304 #endif
00305       throw CODEX_Server::PublicKeyNotFoundException( __FILE__ ,
00306                                                       __LINE__ );
00307    }
00308    CODEX_ThresholdCrypto::DLProof proofs[TDType::NumShares];
00309    for ( unsigned int i = 0 ; i < TDType::NumShares ; ++i )
00310    {
00311       CODEX_ASN1::Integer ai;
00312       if ( 0 == ai.unmarshal( 0, &data, length ) )
00313       {
00314          delete msg;
00315          delete partialResults;
00316 #ifdef TIMING
00317          ActiveTimer.stop();
00318 #endif
00319          return false;
00320       }
00321       length -= (data-oData);
00322       oData = data;
00323 
00324       if ( 0 != ai.value() )
00325       {
00326          if ( 0 == proofs[i].unmarshal( 0, &data, length ) )
00327          {
00328             delete msg;
00329             delete partialResults;
00330 #ifdef TIMING
00331             ActiveTimer.stop();
00332 #endif
00333             return false;
00334          }
00335          length -= (data-oData);
00336          oData = data;
00337       }
00338    }
00339 #endif
00340 
00341    delete msg;
00342 
00343    CODEX_Server::ServerSignature* servSig = 0;
00344    try
00345    {
00346       DigestMap::iterator dItr = m_digests.find( bct );
00347       if ( dItr == m_digests.end() )
00348       {
00349          m_digests.insert( DigestMap::value_type( bct, 0 ) );
00350          dItr = m_digests.find( bct );
00351       }
00352       if ( 0 == dItr->second )
00353       {
00354          unsigned char* buff = 0;
00355          CODEX_ASN1::ustring* str = 0;
00356          try
00357          {
00358             int length = m_request.SignedReadKeyMsg::marshal(0);
00359             length += bct.marshal(0);
00360             buff = new unsigned char[ length ];
00361             unsigned char* pBuff = buff;
00362             m_request.SignedReadKeyMsg::marshal(&pBuff);
00363             bct.marshal(&pBuff);
00364             str = serverState->hashFunc()( CODEX_ASN1::ustring(buff,length) );
00365             delete [] buff;
00366             buff = 0;
00367             dItr->second = BN_new();
00368             if ( 0 == dItr->second )
00369             {
00370                throw CODEX_Exceptions::BignumNullException( __FILE__ ,
00371                                                             __LINE__ );
00372             }
00373             if ( 0 == BN_bin2bn( str->data(),
00374                                     str->length(),
00375                                     dItr->second ) )
00376             {
00377                throw CODEX_Exceptions::BignumBin2BNException( __FILE__ ,
00378                                                               __LINE__ );
00379             }
00380 
00381             delete str;
00382          }
00383          catch ( ... )
00384          {
00385             if ( 0 != buff ) delete [] buff;
00386             if ( 0 != str ) delete str;
00387             if ( 0 != dItr->second ) BN_free( dItr->second );
00388             throw;
00389          }
00390       }
00391       // Verify the signature.
00392       if ( ! serverState->publicKey(server).verifySignature(
00393          signature, dItr->second ) )
00394       {
00395          throw CODEX_Server::SignatureVerificationFailedException( __FILE__ ,
00396                                                                    __LINE__ );
00397       }
00398 
00399       // Create a new ServerSignature.
00400       servSig = new CODEX_Server::ServerSignature( server, signature );
00401 
00402       // Add to the evidence set.
00403       m_evidence[ bct ].append( servSig );
00404       servSig = 0;
00405       // Add to the list of partial results.
00406 #ifndef ELGAMAL
00407       m_partials[ bct ].push_back( partialResults );
00408       partialResults = 0;
00409 #else
00410 
00411       // Test the validity of the partials based on the proofs provided.
00412       //
00413 
00414       // Putting the partials in a ShareSet unifies the interface for
00415       // any secret sharing scheme.
00416       ShareSetType tempSS;
00417       tempSS.addShare( *partialResults );
00418 
00419       const CODEX_Server::ServerState::LSType::LabelType& reqLabel =
00420          m_request.label();
00421 
00422       bool goodShares = true;
00423       for ( unsigned int i = 0 ;
00424             goodShares && ( i < ShareType::NumShares ) ;
00425             ++i )
00426       {
00427          if ( tempSS(i).initialized() )
00428          {
00429             if ( ! proofs[i].verify( bct.c1().value(),
00430                                      serviceEGKey.g().value(),
00431                                      tempSS(i).value(),
00432                                      reqLabel.vc(i).value(),
00433                                      serviceEGKey.p().value(),
00434                                      serverState->hashFunc() ) )
00435             {
00436                goodShares = false;
00437             }
00438          }
00439       }
00440       if ( goodShares )
00441       {
00442          m_partials[ bct ].addShare( *partialResults );
00443          delete partialResults;
00444          partialResults = 0;
00445          ++m_nResp[ bct ];
00446          for ( unsigned int i = 0 ; i < ShareType::NumShares ; ++i )
00447          {
00448             if ( proofs[i].initialized() )
00449             {
00450                if ( m_proofs[ bct ].size() != ShareType::NumShares )
00451                {
00452                   m_proofs[ bct ].resize( ShareType::NumShares );
00453                }
00454                if ( ! m_proofs[ bct ][i].initialized() )
00455                {
00456                   m_proofs[ bct ][i] = proofs[i];
00457                }
00458             }
00459          }
00460       }
00461       else
00462       {
00463          delete partialResults;
00464          partialResults = 0;
00465       }
00466 #endif
00467 
00468       // See if we have enough responses to create the threshold signature
00469       // request.
00470       typedef VerifiableBlindKeyMsg RespType;
00471       typedef CODEX_Client::SignedReadKeyMsg ReqType;
00472 
00473       BKType blindedKey;
00474       PartialMap::key_type pKey;
00475       PartialMap::mapped_type pVal;
00476 
00477       unsigned int numResp = 0;
00478       PartialMap::const_iterator itr = m_partials.begin();
00479       PartialMap::const_iterator end = m_partials.end();
00480       for ( ; ( itr != end ) && ( ! blindedKey.initialized() ) ; ++itr )
00481       {
00482 #ifndef ELGAMAL
00483          numResp += itr->second.size();
00484 #else
00485          numResp += m_nResp[ itr->first ];
00486 #endif
00487          constructBlindedKey( blindedKey, itr->first, itr->second );
00488          if ( blindedKey.initialized() )
00489          {
00490             pKey = itr->first;
00491             pVal = itr->second;
00492          }
00493       }
00494 
00495       if ( blindedKey.initialized() )
00496       {
00497          RespType bkMsg( m_request.message().name(),
00498                          blindedKey,
00499                          m_request.signature(),
00500 #ifdef ELGAMAL
00501                          reqLabel,
00502                          pVal,
00503                          m_proofs[pKey],
00504 #endif
00505                          pKey );
00506          const CODEX_Server::ServerState::LSType::LabelType& label =
00507             serverState->defaultSignatureLabel();
00508 
00509          SupportedClientResponse< RespType, ReqType > resp( bkMsg,
00510                                                             m_request,
00511                                                             m_evidence[bct],
00512                                                             label );
00513          unsigned char* seqNum = serverState->newSequenceNumber();
00514          stateInfo->registerSequenceNumber( seqNum, m_clientAct );
00515          SignReadCallback* cb = new SignReadCallback( m_deadPile,
00516                                                       m_queue,
00517                                                       m_clientAct,
00518                                                       resp,
00519                                                       seqNum,
00520                                                       m_destination );
00521 
00522          CODEX_Quorum::Message request;
00523          unsigned char self = serverState->hostNum();
00524          request.fill( self | CODEX_Server::ServerState::OutgoingMask );
00525          request.fill( seqNum, CODEX_Server::ServerState::nMID );
00526          request.fill( stateInfo->delegationDomain() );
00527          request.fill( ClientDelegation::kRequestSignature );
00528          request.fill( CODEX_Client::kBlindKeyMsg );
00529          int reqLen = resp.marshal(0);
00530          unsigned char* reqBuff = new unsigned char[reqLen];
00531          unsigned char* pReqBuff = reqBuff;
00532          resp.marshal(&pReqBuff);
00533          request.fill( reqBuff, reqLen );
00534          delete [] reqBuff;
00535 
00536          CODEX_Server::SignRequestEvent* event =
00537             new CODEX_Server::SignRequestEvent(this,
00538                                                m_destination,
00539                                                request,
00540                                                cb);
00541          sendEvent( event, 0 ); // no need to acknowledge
00542          serverState->removeChallenge( this->seqNum() );
00543          m_complete = true;
00544       }
00545       else if ( numResp >= qs->quorumSize() )
00546       {
00547          // We cannot form a threshold decryption because the key values
00548          // stored at different servers are inconsistent.
00549          sendEvent( new CODEX_Events::CloseEvent(0, m_clientAct), 0 );
00550 #ifdef TIMING
00551          ActiveTimer.stop();
00552 #endif
00553          return false;
00554       }
00555 #ifdef TIMING
00556       ActiveTimer.stop();
00557 #endif
00558       return true;
00559    }
00560    catch ( CODEX_Exceptions::ExceptionBase& e )
00561    {
00562       e.report();
00563       if ( 0 != servSig ) delete servSig;
00564       if ( 0 != partialResults ) delete partialResults;
00565 #ifdef TIMING
00566       ActiveTimer.stop();
00567 #endif
00568       return false;
00569    }
00570    catch ( ... )
00571    {
00572       if ( 0 != servSig ) delete servSig;
00573       if ( 0 != partialResults ) delete partialResults;
00574 #ifdef TIMING
00575       ActiveTimer.stop();
00576 #endif
00577       return false;
00578    }
00579    // Control should never reach here, but in case it does...
00580 #ifdef TIMING
00581    ActiveTimer.stop();
00582 #endif
00583    return false;
00584 }
00585 
00586 void
00587 ClientReadCallback::constructBlindedKey( BlindPlainTextType& blindedKey,
00588                                          const BlindCipherTextType& blinding,
00589                                          const PartialArray& partials )
00590 {
00591    typedef ShareType  TDType;
00592 
00593    CODEX_Server::ServerState* serverState =
00594       CODEX_Server::ServerState::instance();
00595    if ( 0 == serverState )
00596    {
00597       return;
00598    }
00599 
00600 #ifndef ELGAMAL
00601    if ( partials.size() > CODEX_Server::ServerState::nFaults )
00602    {
00603       // optimistic case
00604       ShareSetType allPartials;
00605       PartialArray::const_iterator itr = partials.begin();
00606       PartialArray::const_iterator end = partials.end();
00607       for ( ; itr != end ; ++itr )
00608       {
00609          allPartials.addShare( **itr );
00610       }
00611       // Get the threshold decryption, verify it, and if OK respond.
00612       const CODEX_Server::ServerState::ThresholdRSAType& thresholdRSA =
00613          serverState->thresholdRSA();
00614       BIGNUM* bk = thresholdRSA.threshold( allPartials );
00615       if ( 0 != bk )
00616       {
00617          try
00618          {
00619             const CODEX_Ciphers::RSAPublicKey& serviceKey =
00620                serverState->serviceKey();
00621             if ( ! serviceKey.initialized() )
00622             {
00623                throw CODEX_Server::PublicKeyNotFoundException( __FILE__ ,
00624                                                                __LINE__ );
00625             }
00626             // Check if the encryption of the threshold result matches
00627             // the blind encryption.
00628             CODEX_Ciphers::RSACipherText* ct = serviceKey.encrypt( bk );
00629             if ( 0 == BN_cmp( ct->value(), blinding.c1().value() ) )
00630             {
00631                blindedKey = BlindPlainTextType( bk, blinding.c2() );
00632                bk = 0;
00633             }
00634             delete ct;
00635          }
00636          catch ( ... )
00637          {
00638          }
00639          if ( 0 != bk ) BN_free( bk );
00640       }
00641 
00642       if ( ! blindedKey.initialized() )
00643       {
00644          bk = serverState->thresholdOperation( partials,
00645                                                blinding.c1().value() );
00646          if ( 0 != bk )
00647          {
00648             blindedKey = BlindPlainTextType( bk, blinding.c2() );
00649             bk = 0;
00650          }
00651          if ( 0 != bk ) BN_free( bk );
00652       }
00653    }
00654 #else /* ELGAMAL */
00655    // The ElGamal case is easy, since all partials have been verified
00656    // beforehand.  Consequently, if we have all of the partial results,
00657    // we can trivially compose the threshold decryption.
00658    BIGNUM * bk = serverState->thresholdEG().thresholdDecrypt( partials,
00659                                                               blinding );
00660    if ( 0 == bk )
00661    {
00662       return;
00663    }
00664    blindedKey = CODEX_ASN1::BigNumber( bk );
00665 #endif /* ELGAMAL */
00666 }

Generated on Fri May 6 17:38:50 2005 for COrnell Data EXchange (CODEX) by  doxygen 1.4.1