Mixe for Privacy and Anonymity in the Internet
CADynamicCascadeConfigurator.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000, The JAP-Team 
00003 All rights reserved.
00004 Redistribution and use in source and binary forms, with or without modification, 
00005 are permitted provided that the following conditions are met:
00006  
00007   - Redistributions of source code must retain the above copyright notice, 
00008     this list of conditions and the following disclaimer.
00009  
00010   - Redistributions in binary form must reproduce the above copyright notice, 
00011     this list of conditions and the following disclaimer in the documentation and/or 
00012     other materials provided with the distribution.
00013  
00014   - Neither the name of the University of Technology Dresden, Germany nor the names of its contributors 
00015     may be used to endorse or promote products derived from this software without specific 
00016     prior written permission. 
00017  
00018   
00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 
00020 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
00021 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
00022 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00023 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
00024 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
00025 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00026 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00027 */
00028 #include "StdAfx.h"
00029 
00030 #ifdef DYNAMIC_MIX
00031 #include "CADynamicCascadeConfigurator.hpp"
00032 #include "CACmdLnOptions.hpp"
00033 #include "CAListenerInterface.hpp"
00034 #include "CASocketAddrINet.hpp"
00035 #include "CASocket.hpp"
00036 #include "CAHttpClient.hpp"
00037 #include "CACertificate.hpp"
00038 #include "CAMsg.hpp"
00039 
00046 CADynamicCascadeConfigurator::CADynamicCascadeConfigurator(CASignature *a_pSignature, CAMix *a_pMix)
00047 {
00048   this->m_pSignature = a_pSignature;
00049   this->m_pMix = a_pMix;
00050   m_proposals = NULL;
00051 }
00052 
00058 CADynamicCascadeConfigurator::~CADynamicCascadeConfigurator()
00059 {
00060   if(m_proposals != NULL)
00061   {
00062     PROPOSALENTRY *tmpProposal = NULL;
00063     PROPOSERENTRY *tmpProposer = NULL;
00064     while( (tmpProposal = m_proposals) != NULL )
00065     {
00066       while( (tmpProposer = tmpProposal->proposers) != NULL)
00067       {
00068         tmpProposal->proposers = tmpProposer->next;
00069         delete tmpProposer->ski;
00070         tmpProposer->ski = NULL;
00071         delete tmpProposer;
00072         tmpProposer = NULL;
00073       }
00074       delete tmpProposal->proposal;
00075       tmpProposal->proposal = NULL;
00076 //      delete tmpProposal->elem;
00077       m_proposals = tmpProposal->next;
00078       delete tmpProposal;
00079       tmpProposal = NULL;
00080     }
00081   }
00082 
00083 }
00084 
00100 SINT32 CADynamicCascadeConfigurator::configure()
00101 {
00102   UINT32 nrAddresses;
00103   CAListenerInterface** ppSocketAddresses = pglobalOptions->getInfoServices(nrAddresses);
00104 
00105 #ifdef DEBUG
00106   CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Querying %i infoservices...\n", nrAddresses);
00107 #endif
00108   UINT8 bufMixId[255];
00109   UINT32 mixIdLen = 255;
00110   UINT8 request[255];
00111   pglobalOptions->getMixId( bufMixId, mixIdLen );
00112   sprintf((char*)request, "/reconfigure/%s",bufMixId );
00113 
00114   for (UINT32 i = 0; i < nrAddresses; i++)
00115   {
00116     CASocketAddrINet* pAddr=(CASocketAddrINet*)ppSocketAddresses[i]->getAddr();
00117     DOM_Element elem;
00118     if( sendInfoserviceGetRequest(pAddr, request, &elem) != E_SUCCESS)
00119     {
00120 #ifdef DEBUG
00121     CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Query %i WAS NOT SUCCESSFULL!\n", i);
00122 #endif
00123       delete pAddr;
00124       pAddr = NULL;
00125       continue;
00126     }
00127 #ifdef DEBUG
00128     CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Query %i successful, adding proposal now...\n", i);
00129 #endif
00130     delete pAddr;
00131     pAddr = NULL;
00132 /*    UINT8* sendBuff=NULL; 
00133     UINT32 sendBuffLen = 0;
00134     sendBuff=DOM_Output::dumpToMem(elem,&sendBuffLen);
00135     if(sendBuff!=NULL)
00136       CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Proposal %s\n", sendBuff);*/
00137     addProposal( elem );
00138 }
00139 
00140 #ifdef DEBUG
00141   CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Queried all infoservices, will now vote...\n");
00142 #endif
00143 
00144   DOM_Node *newCascade  = NULL;
00145   UINT8 proposal[1024];
00146   if( getMajorityVote( nrAddresses, newCascade, proposal ) == E_SUCCESS )
00147   {
00149     UINT8 buff[1024];
00150     UINT32 len = 1024;
00151     if(pglobalOptions->getLastCascadeProposal(buff, len) == E_SUCCESS)
00152     {
00153       if(strcmp((char*)proposal, (char*)buff) == 0)
00154       {
00155         CAMsg::printMsg(LOG_DEBUG, "New proposal == old proposal:  SKIPPING\n");
00156         return E_SUCCESS;
00157       }
00158     }
00159     CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Vote successful!\n");
00160     if(newCascade != NULL)
00161     {
00162       return reconfigureMix(*newCascade, proposal);
00163     }
00164   }
00165   else
00166   {
00167     CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Vote not successful, no majority found, remaining as I am\n");
00168   }
00169   return E_SUCCESS;
00170 }
00171 
00180 SINT32 CADynamicCascadeConfigurator::getMajorityVote(UINT32 a_nrInfoServices, DOM_Node *&r_elemMajority, UINT8* r_strProposal)
00181 {
00182   SINT32 ret = E_UNKNOWN;
00183   r_elemMajority = NULL;
00184   PROPOSALENTRY *tmp = m_proposals;
00185   while( tmp != NULL )
00186   {
00187     if(tmp->count >= MIN_MAJORITY_QUOTE(a_nrInfoServices))
00188     {
00189 #ifdef DEBUG
00190       CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::getMajorityVote - Proposal (%s) has %i votes, thats the majority (%i were needed)!\n", tmp->proposal, tmp->count,
00191                MIN_MAJORITY_QUOTE(a_nrInfoServices));
00192 #endif
00193       r_elemMajority = &tmp->elem;
00194       if( r_elemMajority != NULL)
00195       {
00196         strcpy((char*)r_strProposal, (char*)tmp->proposal);
00197         ret = E_SUCCESS;
00198       }
00199     }
00200 #ifdef DEBUG
00201     else
00202     {
00203       CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::getMajorityVote - Proposal (%s) has %i votes, discarting, majority would be (%i)\n", tmp->proposal, tmp->count,
00204                MIN_MAJORITY_QUOTE(a_nrInfoServices));
00205     }
00206 #endif
00207     tmp = tmp->next;
00208   }
00209   return ret;
00210 }
00211 
00219 SINT32 CADynamicCascadeConfigurator::reconfigureMix(DOM_Node a_elemNewCascade, UINT8* a_strProposal)
00220 {
00221   DOM_Element mixesElement;
00222   getDOMChildByName(a_elemNewCascade,(UINT8*)"Mixes", mixesElement, false);
00223   DOM_Node child = mixesElement.getFirstChild();
00224   char* mixId;
00225   UINT8 myMixId[255];
00226   UINT32 len=255;
00227   pglobalOptions->getMixId(myMixId, len);
00228   char* prevMixId = NULL;
00229   char* myNextMixId = NULL;
00230   char* myPrevMixId = NULL;
00231   bool bFoundMix = false;
00232   while(child!=NULL)
00233   {
00234     if(child.getNodeName().equals("Mix") && child.getNodeType() == DOM_Node::ELEMENT_NODE)
00235     {
00236       mixId = static_cast<const DOM_Element&>(child).getAttribute("id").transcode();
00237       if(strcmp(mixId,(char*)myMixId) == 0)
00238       {
00239         bFoundMix = true;
00240         myPrevMixId = prevMixId;
00241       }
00242       else if(bFoundMix == true)
00243       {
00244         myNextMixId = mixId;
00245         break;
00246       }
00247       prevMixId = mixId;
00248     }
00249     child = child.getNextSibling();
00250   }
00251 
00252   if(!bFoundMix)
00253   {
00254     CAMsg::printMsg(LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - Unable to find my mix ID in the majority cascade info\n");
00255     return E_UNKNOWN;
00256   }
00257 
00258   // Empty cascade info -> I wasn't assigned a new cascade, stop the old one
00260   if(myPrevMixId == NULL && myNextMixId == NULL) 
00261   {
00262     // Only stops the cascade, now reconfiguration is done yet
00263     pglobalOptions->resetPrevMix();
00264     pglobalOptions->resetNextMix();
00265     pglobalOptions->setCascadeProposal(a_strProposal, strlen((char*)a_strProposal));
00266     m_pMix->dynaReconfigure( false );
00267     return E_SUCCESS;
00268   }
00269   m_pMix->setReconfiguring(true);
00270   SINT32 ret = 0;
00271 
00272   bool typeChanged = false;
00273 
00275   if(myPrevMixId == NULL)
00276   {
00277 
00278     if(pglobalOptions->isLastMix())
00279     {
00280       CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - I am a LastMix and should be reconfigured as a FirstMix! Won't do that!!\n");
00281       return E_UNKNOWN;
00282     }
00283     else if(pglobalOptions->isMiddleMix())
00284     {
00285 #ifdef DEBUG
00286       CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am a MiddleMix and should be reconfigured as a FirstMix!\n");
00287 #endif
00288       pglobalOptions->changeMixType(CAMix::FIRST_MIX);
00289       typeChanged = true;
00290     }
00291     else if(pglobalOptions->isFirstMix())
00292     {
00293 #ifdef DEBUG
00294       CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - CADynamicCascadeConfigurator::reconfigureMix - I am (and will remain) a first mix!\n");
00295 #endif
00296     }
00297     else
00298     {
00299 #ifdef DEBUG
00300       CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - Ugh! I do not have a current mix type! Trying to become a FirstMix nevertheless, but that might fail\n");
00301 #endif
00302       pglobalOptions->changeMixType(CAMix::FIRST_MIX);
00303       typeChanged = true;
00304     }
00305   }
00306 
00308   if( myNextMixId == NULL )
00309   {
00310     if(!pglobalOptions->isLastMix())
00311     {
00312       CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - I am NOT a LastMix and should be reconfigured as a LastMix! Won't do that!!\n");
00313       return E_UNKNOWN;
00314     }
00315 #ifdef DEBUG
00316     else
00317     {
00318       CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am (and will remain) a last mix!\n");
00319     }
00320 #endif
00321   }
00322 
00324   if(myPrevMixId != NULL && myNextMixId != NULL)
00325   {
00326     if(pglobalOptions->isLastMix())
00327     {
00328       CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - I am a LastMix and should be reconfigured as a MiddleMix! Won't do that!!\n");
00329       return E_UNKNOWN;
00330     }
00331     else if(pglobalOptions->isFirstMix())
00332     {
00333 #ifdef DEBUG
00334       CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am a FirstMix and should be reconfigured as a MiddleMix!\n");
00335 #endif
00336       pglobalOptions->changeMixType(CAMix::MIDDLE_MIX);
00337       typeChanged = true;
00338     }
00339     else if(pglobalOptions->isMiddleMix())
00340     {
00341       CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am (and will remain) a middle mix!\n");
00342     }
00343     else
00344     {
00345 #ifdef DEBUG
00346       CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - Ugh! I do not have a current mix type! Trying to become a MiddleMix nevertheless, but that might fail\n");
00347 #endif
00348       pglobalOptions->changeMixType(CAMix::MIDDLE_MIX);
00349       typeChanged = true;
00350     }
00351   }
00352 
00353   // MiddleMix or LastMox
00354   if(myPrevMixId != NULL)
00355   {
00356     CAMsg::printMsg(LOG_INFO,"CADynamicCascadeConfigurator::reconfigureMix - Asking InfoService about previous mix ...\n");
00357     char buf[255];
00358     sprintf(buf, "/mixinfo/%s", (char*)myPrevMixId);
00359     DOM_Element result;
00361     ret = sendRandomInfoserviceGetRequest( (UINT8*)buf, &result);
00362     if(ret != E_SUCCESS)
00363     {
00364       CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error retrieving mix info from InfoService!\n");
00365       return ret;
00366     }
00367     DOM_Document doc = result.getOwnerDocument();
00368     ret = pglobalOptions->setPrevMix( doc );
00369     if(ret != E_SUCCESS)
00370     {
00371       CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error setting next mix info!\n");
00372       pglobalOptions->resetPrevMix();
00373       return E_UNKNOWN;
00374     }
00375   }
00376   else
00377   {
00378     if(pglobalOptions->resetPrevMix() != E_SUCCESS)
00379     {
00380       CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - Unable to reset prev mix information\n");
00381       return E_UNKNOWN;
00382     }
00383   }
00384 
00385   // MiddleMix or FirstMix
00386   if(myNextMixId != NULL)
00387   {
00388     CAMsg::printMsg(LOG_INFO,"CADynamicCascadeConfigurator::reconfigureMix - Asking InfoService about next mix ...\n");
00389     char buf[255];
00390     sprintf(buf, "/mixinfo/%s", (char*)myNextMixId);
00391     DOM_Element result;
00392     if( sendRandomInfoserviceGetRequest( (UINT8*)buf, &result) != E_SUCCESS )
00393     {
00394       CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error retrieving mix info from InfoService!\n");
00395       return E_UNKNOWN;
00396     }
00397     DOM_Document doc = result.getOwnerDocument();
00398     if(pglobalOptions->setNextMix( doc ) != E_SUCCESS)
00399     {
00400       CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error setting next mix info!\n");
00401       return E_UNKNOWN;
00402     }
00403   }
00404   else
00405   {
00406     if(pglobalOptions->resetNextMix() != E_SUCCESS)
00407     {
00408       CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - Unable to reset next mix information\n");
00409       return E_UNKNOWN;
00410     }
00411   }
00412 
00413   pglobalOptions->setCascadeProposal(a_strProposal, strlen((char*)a_strProposal));
00414 /*  if(pglobalOptions->isFirstMix()) 
00415   {
00416     pglobalOptions->setCascadeXML((DOM_Element&)a_elemNewCascade);
00417   }*/
00418 #ifdef DEBUG
00419   CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - Calling dynaReconfigure on the mix, grab a hold of something!\n");
00420 #endif
00421   m_pMix->dynaReconfigure( typeChanged );
00422   return E_SUCCESS;
00423 }
00424 
00436 SINT32 CADynamicCascadeConfigurator::addProposal(DOM_Element a_elem)
00437 {
00439   // FIXME Signature cannot be verified. Why is that?
00440   /*    if( m_pSignature->verifyXML( a_elem, NULL ) != E_SUCCESS)
00441       {
00442         CAMsg::printMsg( LOG_DEBUG, "Signature was not ok, throwing it away...\n");
00443         return E_UNKNOWN;
00444       }*/
00446   DOM_Element mixesElement;
00447   getDOMChildByName(a_elem,(UINT8*)"Mixes", mixesElement, false);
00448   DOM_Node child = mixesElement.getFirstChild();
00449   char* mixId;
00450   char* tmpProposal = NULL;
00451   while(child!=NULL)
00452   {
00453     if(child.getNodeName().equals("Mix") && child.getNodeType() == DOM_Node::ELEMENT_NODE)
00454     {
00455       mixId = static_cast<const DOM_Element&>(child).getAttribute("id").transcode();
00456       if(tmpProposal == NULL)
00457       {
00458         tmpProposal = new char[strlen(mixId)+1];
00459         strncpy(tmpProposal, mixId, strlen(mixId)+1);
00460       }
00461       else
00462       {
00463         char *tmp = new char[strlen(tmpProposal)+1];
00464         strncpy(tmp, tmpProposal, strlen(tmpProposal)+1);
00465         delete tmpProposal;
00466         tmpProposal = new char[ strlen(mixId) + strlen(tmp) + 1];
00467         strncpy(tmpProposal, tmp, strlen(tmp) + 1);
00468         delete tmp;
00469         tmp = NULL;
00470         strcat(tmpProposal, mixId);
00471       }
00472     }
00473     child = child.getNextSibling();
00474   }
00475   UINT8* proposal = NULL;
00476   UINT32 lenProposal = 0;
00477   proposal = new UINT8[strlen(tmpProposal) + 1];
00478   memcpy(proposal, tmpProposal, strlen(tmpProposal) + 1);
00479   lenProposal = strlen(tmpProposal);
00480   delete tmpProposal;
00481   tmpProposal = NULL;
00482 
00483 #ifdef DEBUG
00484 //  CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::addProposal - next proposal is %s\n", proposal);
00485 #endif
00486 
00488   DOM_Element elemSig, elemCert;
00489   getDOMChildByName(a_elem,(UINT8*)"Signature",elemSig,false);
00490   getDOMChildByName(elemSig,(UINT8*)"X509Data",elemCert,true);
00491   CACertificate *cert = NULL;
00492   if(elemSig!=NULL)
00493     cert = CACertificate::decode(elemCert.getFirstChild(),CERT_X509CERTIFICATE);
00494 
00495   UINT8 proposerSki[60];
00496   UINT32 lenProposerSki = 60;
00497   if(cert != NULL)
00498     cert->getSubjectKeyIdentifier( proposerSki, &lenProposerSki );
00499 
00500 #ifdef DEBUG
00501 //  CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::addProposal - the proposer is %s\n", proposerSki);
00502 #endif
00503 
00504   bool added = false;
00505   
00507   PROPOSALENTRY *tmpEntry;
00508   if( m_proposals == NULL )
00509   {
00510     m_proposals = createProposal( proposal, lenProposal, proposerSki, lenProposerSki, &a_elem );
00511 #ifdef DEBUG
00512 /*    CAMsg::printMsg(LOG_DEBUG,  "CADynamicCascadeConfigurator::addProposal - Adding proposal %s from InfoService %s. Got %i proposing IS for this value\n", m_proposals->proposal,
00513             m_proposals->proposers->ski, m_proposals->count );*/
00514 #endif
00515   }
00516   else
00517   {
00518     tmpEntry=m_proposals;
00519     while(true)
00520     {
00521       if(memcmp(tmpEntry->proposal, proposal, lenProposal) == 0)
00522       {
00523         PROPOSERENTRY *proposer = tmpEntry->proposers;
00524         bool ok = true;
00525         while(true)
00526         {
00527           if(memcmp(proposer->ski, proposerSki, lenProposerSki) == 0)
00528           {
00529             // Duplicate!
00530             ok = false;
00531             added = true;
00532             break;
00533           }
00534           if(proposer->next == NULL)
00535             break;
00536           proposer = proposer->next;
00537         }
00538         if(ok)
00539         {
00540           PROPOSERENTRY *tmpProposer = new PROPOSERENTRY;
00541           tmpProposer->next = NULL;
00542           tmpProposer->ski = new UINT8[lenProposerSki+1];
00543           memcpy(tmpProposer->ski, proposerSki, lenProposerSki+1);
00544           proposer->next = tmpProposer;
00545           tmpEntry->count++;
00546 #ifdef DEBUG
00547 /*          CAMsg::printMsg(LOG_DEBUG,  "CADynamicCascadeConfigurator::addProposal - Adding proposal %s from InfoService %s. Got %i proposing IS for this value\n", tmpEntry->proposal,tmpProposer->ski, tmpEntry->count );*/
00548 #endif
00549           added = true;
00550           break;
00551         }
00552       }
00553       if(tmpEntry->next == NULL) 
00554         break;
00555       tmpEntry = tmpEntry->next;
00556     }
00557     if(!added)
00558     {
00559       tmpEntry->next = createProposal( proposal, lenProposal, proposerSki, lenProposerSki, &a_elem );
00560 #ifdef DEBUG
00561 /*      CAMsg::printMsg(LOG_DEBUG,  "CADynamicCascadeConfigurator::addProposal - Adding proposal %s from InfoService %s. Got %i proposing IS for this value\n", tmpEntry->next->proposal,tmpEntry->next->proposers->ski, tmpEntry->next->count );*/
00562 #endif
00563     }
00564   }
00565   return E_SUCCESS;
00566 }
00567 
00578 PROPOSALENTRY *CADynamicCascadeConfigurator::createProposal(UINT8* a_strProposal, UINT32 a_lenProposal, UINT8 *a_strProposer, UINT32 a_lenProposer, DOM_Element *a_elem)
00579 {
00580   PROPOSALENTRY *entry = new PROPOSALENTRY;
00581   entry->proposal = new UINT8[a_lenProposal+1];
00582   memcpy(entry->proposal, a_strProposal, a_lenProposal+1);
00583   entry->count = 1;
00584   entry->next = NULL;
00585   PROPOSERENTRY *proposer = new PROPOSERENTRY;
00586   proposer->next = NULL;
00587   proposer->ski = new UINT8[a_lenProposer+1];
00588   memcpy(proposer->ski, a_strProposer, a_lenProposer+1);
00589   entry->proposers = proposer;
00590   entry->elem = a_elem->cloneNode( true );
00591   return entry;
00592 }
00593 #endif // DYNAMIC_MIX