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

Generated on Wed Jun 2 16:32:54 2004 for COrnell Data EXchange (CODEX) by doxygen1.2.18