def __init__(self, walletMessageType, entity, coins): self.walletMessageType = walletMessageType self.entity = entity #self.isMessageType = isMessageType if not self.walletMessageType.globals.status.can( MessageStatuses.PrivilegeClient): raise MessageError( 'given messageType does not have PrivilegeClient') class messages: pass self.walletMessages = messages() self.isMessages = messages() del messages # All the responses we can get from the IS self.isMessages.DKP = DSDBKeyPass(self.resumeConversation) # All the responses we can get from the other wallet self.walletMessages.BR = BlankReject(self.resumeConversation) self.walletMessages.BF = BlankFailure(self.resumeConversation) self.walletMessages.BA = BlankAccept(self.resumeConversation) self.walletMessages.CR = CoinsReject(self.resumeConversation) self.walletMessages.CA = CoinsAccept(self.resumeConversation) # Add handlers for all the messages using walletMessages if continues conversation self.walletMessageType.addMessageHandler(BlankPresent()) self.walletMessageType.addMessageHandler(self.walletMessages.BR) self.walletMessageType.addMessageHandler(self.walletMessages.BF) self.walletMessageType.addMessageHandler(self.walletMessages.BA) self.walletMessageType.addMessageHandler(CoinsRedeem()) self.walletMessageType.addMessageHandler(self.walletMessages.CR) self.walletMessageType.addMessageHandler(self.walletMessages.CA) self.coins = coins class state: pass self.persistant = state() del state self.lastMessageIdentifier = None
def checkValidObfuscatedBlanksAndKnownIssuers(self, blanks, cdds, mintingKeysKeyID): failure = False failures = [] if len(blanks) == 0: raise MessageError('Need atleast one blank!') for b in blanks: if not self.checkValidObfuscatedBlank(b, cdds, mintingKeysKeyID): failure = True failures.append((b, 'Malformed blank')) elif not self.checkKnownIssuer(b, self.manager.entity.cdds): failure = True failures.append((b, 'Unknown issuer')) if failure: return 'FAILED', failures else: return 'PASS', None
def __init__(self, messageType, entity): self.messageType = messageType self.entity = entity if not self.messageType.globals.status.can(MessageStatuses.PrivilegeServer): raise MessageError('given messageType does not have PrivilegeServer') class messages: pass self.messages = messages del messages #create conversation starting messages to trigger self.startConversation self.messages.DKR = DSDBKeyRequest(self.startConversation) self.messages.FMR = FetchMintedRequest(self.startConversation) self.messages.MR = MintRequest(self.startConversation) self.messages.MKFD = MintingKeyFetchDenomination(self.startConversation) self.messages.MKFK = MintingKeyFetchKeyID(self.startConversation) self.messages.RCR = RedeemCoinsRequest(self.startConversation) #add all of our special mesasges as MessageHandlers self.messageType.addMessageHandler(self.messages.DKR) self.messageType.addMessageHandler(self.messages.FMR) self.messageType.addMessageHandler(self.messages.MR) self.messageType.addMessageHandler(self.messages.MKFD) self.messageType.addMessageHandler(self.messages.MKFK) self.messageType.addMessageHandler(self.messages.RCR) #everything that can't start a conversation self.messageType.addMessageHandler(MintingKeyPass()) self.messageType.addMessageHandler(MintingKeyFailure()) self.messageType.addMessageHandler(MintReject()) self.messageType.addMessageHandler(MintAccept()) self.messageType.addMessageHandler(FetchMintedFailure()) self.messageType.addMessageHandler(FetchMintedWait()) self.messageType.addMessageHandler(FetchMintedAccept()) self.messageType.addMessageHandler(DSDBKeyPass()) self.messageType.addMessageHandler(RedeemCoinsReject()) self.messageType.addMessageHandler(RedeemCoinsAccept()) self.manager = None
def request(self, request_id, blinds, minting_keys_key_id, now): failure = False failures = [] if len(blinds) == 0: raise MessageError('request %s has no blinds' % request_id) for b in blinds: type, result = self.testBlind(b, minting_keys_key_id, now) if type == 'ACCEPT': pass elif type == 'REJECT': failure = True key_id, blind = b failures.append( (blind, result) ) if failure: return 'REJECT', failures self.acceptBlinds(request_id, blinds) return 'ACCEPT', request_id
def testBlank(self, blank, dsdb_key_id, dsdb_key, dsdb_database, dsdb_requests, minting_keys_key_id, now): mint_key_id, obfuscated = blank serial = self.unobfuscate(obfuscated, dsdb_key) if serial == 'Decryption of serial failed': return 'REJECT', 'Decryption of serial failed' if not minting_keys_key_id.has_key( mint_key_id ) or not minting_keys_key_id[mint_key_id].verify_time(now): return 'REJECT', 'Key ID of blank is unknown or expired' if dsdb_database.has_key(mint_key_id): if dsdb_database[mint_key_id].has_key(serial): result = dsdb_database[mint_key_id][serial] if result[0] == 'Spent': return 'REJECT', 'Serial already redeemed' elif result[0] == 'Locked': string, time_lock_expires, transaction_id = result if self.timeNow() <= time_lock_expires: return 'REJECT', 'Serial locked (not spent)' else: # the serial is no longer locked. unlock it time_transaction_lock_expires, keysAndSerials = dsdb_requests[ transaction_id] for key, ser in keysAndSerials: del dsdb_database[key][ser] del dsdb_requests[trasaction_id] return 'ACCEPT', serial else: raise MessageError('Got an impossible state: %s' % result[0]) else: # we have never seen this serial return 'ACCEPT', serial else: # we have never seen this valid mint_key_id return 'ACCEPT', serial
def handle(self, message): if not isinstance(message, CoinsRedeem) and not isinstance( message, CoinsAccept) and not isinstance(message, CoinsReject): if message.messageLayer.globals.lastState == MessageHello: # we are now on a different message. Oops. raise MessageError( 'Coins should have already been removed. It was not. Very odd. Message: %s LastMessage: %s' % (message.identifier, message.messageLayer.globals.lastState)) else: raise MessageError( 'We somehow called Coins.handle() but cannot be there. Message: %s' % message.identifier) if isinstance(message, CoinsRedeem): self.coins = self.manager.walletMessageType.persistant.coins self.manager.persistant.coins = self.coins type, result = self.verifyCoins( self.coins, self.manager.entity.minting_keys_key_id, self.manager.persistant.blanks, self.manager.persistant.dsdb_certificate, self.manager.entity.cdds) if type == 'ACCEPT': self.dsdb_lock = self.manager.persistant.dsdb_lock if not self.validDSDBLock(self.dsdb_lock, self.timeNow()): raise MessageError( 'Invalid DSDB lock. You are an idiot for letting this happen.' ) self._createAndOutputWallet(CoinsAccept) elif type == 'REJECT': self.manager.walletMessageType.persistant.reason = result self._createAndOutputWallet(CoinsReject) else: raise MessageError('Went to an impossible type: %s' % type) elif isinstance(message, CoinsReject): # We are done. We should be nice though and Unlock the coins if self.validDSDBLock( self.manager.dsdbMessageType.persistant.dsdb_lock, self.timeNow()): # FIXME: The else below removes two callbacks. Which one of them is wrong? self.manager.walletMessageType.removeCallback(self.handle) self._createAndOutputDSDB(UnlockCoinsRequest) else: # the DSDB lock has already expired. self.manager.walletMessageType.removeCallback(self.handle) self.manager.isMessageType.removeCallback(self.handle) self.manager.failure(self, message) elif isinstance(message, CoinsAccept): #figure out what request ID we will be using self.manager.persistant.mintRequestID = self.newRequestID() self.manager.persistant.target = self.manager.persistant.mintRequestID # the target and the mint request should be the same methinks #self.manager.persistant.target = self.newTarget() if self.isRequiresMRbeforeRCR: self.manager.isMessageType.persistant.request_id = self.manager.persistant.mintRequestID # setup blinds only for the MintRequest message blinds = [] for b in self.manager.persistant.mintBlanks: b.blind_blank( self.manager.entity.cdds, self.manager.entity.minting_keys_key_id ) # XXX should this be in makeBlanks() instead? blinds.append((b.key_identifier, b.blind_value)) self.manager.isMessageType.persistant.blinds = blinds self.manager.walletMessageType.removeCallback(self.handle) self._createAndOutputIS(MintRequest) else: self.manager.isMessageType.persistant.trasaction_id = self.manager.persistant.mintRequestID self.manager.isMessageType.persistant.target = self.manager.persistant.target self.manager.isMessageType.persistant.coins = self.manager.persistant.coins self.manager.isMessageType.removeCallback(self.handle) self._createAndOutput(RedeemCoinsRequest) self._setLastState(message.identifier)
def __init__(self, walletMessageType, entity): # isMessageType, dsdbMessageType, amount): self.walletMessageType = walletMessageType self.entity = entity #self.isMessageType = isMessageType #self.dsdbMessageType = dsdbMessageType if not self.walletMessageType.globals.status.can( MessageStatuses.PrivilegeServer): raise MessageError( 'given messageType does not have PrivilegeServer') class messages: pass self.walletMessages = messages() self.isMessages = messages() self.dsdbMessages = messages() del messages # All the responses we can get from the IS (we are client) #self.isMessages.MKP = MintingKeyPass(self.resumeConversation) # this are being handled elsewhere (BlankAndMintingKey) #self.isMessages.MKF = MintingKeyFailure(self.resumeConversation) # this is being handled elsewhere (BlankAndMintingKey) self.isMessages.MA = MintAccept(self.resumeConversation) self.isMessages.MR = MintReject(self.resumeConversation) self.isMessages.FMF = FetchMintedFailure(self.resumeConversation) self.isMessages.FMW = FetchMintedWait(self.resumeConversation) self.isMessages.FMA = FetchMintedAccept(self.resumeConversation) self.isMessages.RCR = RedeemCoinsReject(self.resumeConversation) self.isMessages.RCA = RedeemCoinsAccept(self.resumeConversation) # All messages can get from the other wallet (we are server) self.walletMessages.CR = CoinsRedeem(self.resumeConversation) self.walletMessages.BP = BlankPresent(self.resumeConversation) # All the responses we can get from the DSDB self.dsdbMessages.LCA = LockCoinsAccept(self.resumeConversation) self.dsdbMessages.LCF = LockCoinsFailure(self.resumeConversation) self.dsdbMessages.UCP = UnlockCoinsPass(self.resumeConversation) self.dsdbMessages.UCF = UnlockCoinsFailure(self.resumeConversation) # Add handlers for all the messages using walletMessages if starts conversation self.walletMessageType.addMessageHandler(self.walletMessages.BP) self.walletMessageType.addMessageHandler(BlankReject()) self.walletMessageType.addMessageHandler(BlankFailure()) self.walletMessageType.addMessageHandler(BlankAccept()) self.walletMessageType.addMessageHandler(self.walletMessages.CR) self.walletMessageType.addMessageHandler(CoinsReject()) self.walletMessageType.addMessageHandler(CoinsAccept()) class state: __slots__ = ( 'blanks', # the blanks given in BlankPresent 'dsdb_certificate', # the dsdb certificate given in BlankPresent 'mintBlanks', # blanks we created for use with a MintRequest (to make new coins) 'dsdb_lock', # the lock we receive when we perform a LockRequest 'coins', # the coins received from the other wallet with a CoinsRedeem 'mintingKeysKeyID', # the minting key certificates for all coins received 'mintingKeysDenomination', # the minting key certificates for all denominations of all coins received 'mintRequestID', # the request id generated for the MintRequest 'target', # the target for the MintRequest 'signatures', # the signatures returned from IS via FetchMintedRequest 'newCoins', # our newly minted coins after 'mintingFailures' # any coins where the signature was invalid. Nothing we can really do with this though. ) self.persistant = state() del state self.lastMessageIdentifier = None
def getMintingKeyAndContinue(self): if len(self.neededKeyIDs) > 0: # Get a key_id self.mkfType = self.mintingKeysKeyID self.mkfSearch = self.neededKeyIDs.pop() self.mkfReturn = self.getMintingKeyAndContinue self.manager.isMessageType.persistant.key_id = self.mkfSearch self._createAndOutputIS(MintingKeyFetchKeyID) elif len(self.neededDenominations) > 0: #get a denomination self.mkfType = self.mintingKeysDenomination self.mkfSearch = self.neededDenominations.pop() self.mkfReturn = self.getMintingKeyAndContinue self.manager.isMessageType.persistant.denomination = self.mkfSearch self._createAndOutputIS(MintingKeyFetchDenomination) else: # We have all the keys we need. Make new blanks. Verify blanks against DSDB (For now, we don't support trying to do a MintRequest right now # Add all the keys to the entity self.manager.entity.addMintingKeys( self.collapseMintingKeys(self.mintingKeysKeyID, self.mintingKeysDenomination)) # Make blanks self.manager.persistant.mintBlanks = self.makeBlanks( self.blanks, self.minting_denominations, self.mintingKeysDenomination) self.manager.persistant.mintingKeysDenomination = self.mintingKeysDenomination self.manager.persistant.mintingKeysKeyID = self.mintingKeysKeyID #Verify blanks type, result = self.checkValidObfuscatedBlanksAndKnownIssuers( self.blanks, self.manager.entity.cdds, self.manager.entity.minting_keys_key_id) if type == 'PASS': # setup the requirements for the LockCoinsRequest self.manager.dsdbMessageType.persistant.key_id = self.dsdb_certificate.key_identifier self.manager.dsdbMessageType.persistant.transaction_id = self.makeTransactionID( ) # the message to the dsdb, LOCK_COINS_REQUEST only gets sent the obfuscated serial and the minting_key. Get that information self.lockRequestBlanks = [] for b in self.blanks: self.lockRequestBlanks.append((b.key_identifier, b.serial)) self.manager.dsdbMessageType.persistant.blanks = self.lockRequestBlanks # setup future minting self.manager.isMessageType.persistant.transaction_id = self.manager.dsdbMessageType.persistant.transaction_id # it's the same id for a different thing self.manager.isMessageType.persistant.blanks = self.manager.persistant.mintBlanks # The result will be handled by a different Handler. Remove ourselves as a callback self.manager.walletMessageType.removeCallback(self.handle) self.manager.isMessageType.removeCallback(self.handle) # And finally output self._createAndOutputDSDB(LockCoinsRequest) elif type == 'FAILED': # Send a BlankReject self.manager.walletMessageType.persistant.reason = result self._createAndOutputWallet(BlankReject) else: raise MessageError('Received an impossible type: %s' % type)
def handle(self, message): if not isinstance(message, BlankPresent) and not isinstance(message, MintingKeyFetchDenomination) and not \ isinstance(message, MintingKeyFailure) and not isinstance(message, MintingKeyPass) and not isinstance(message, MintingKeyFetchKeyID): if message.messageLayer.globals.lastState == MessageHello: # we are now on a different message. Oops. raise MessageError( 'BlankAndMintingKey should have already been removed. It was not. Very odd. Message: %s LastWalletMessage: %s LastISMessage: %s' % (message.identifier, self.manager.walletMessageType.globals.lastState, self.manager.isMessageType.globals.lastState)) else: raise MessageError( 'We somehow called BlankAndMintingKey.handle() but cannot be there. Message: %s' % message.identifier) if isinstance(message, BlankPresent): self._verifyLastState([None]) self.dsdb_certificate = self.manager.walletMessageType.persistant.dsdb_certificate self.blanks = self.manager.walletMessageType.persistant.blanks self.manager.persistant.blanks = self.blanks self.manager.persistant.dsdb_certificate = self.dsdb_certificate # connect to IS # FIXME: Gah. What a hack. Only supports one IS result = self.getCDD(self.manager.entity.cdds, self.blanks) if result != 'Unknown issuer': self.manager.connectToIS(result) # add the required callback self.manager.isMessageType.addCallback(self.handle) # connect to dsdb self.manager.connectToDSDB( self.manager.persistant.dsdb_certificate) # get list of denominations we are minting #FIXME: This is a spot where we assume only one cdd self.minting_denominations = self.getMintingDenominations( self.blanks, self.manager.entity.cdds) # self.performMagic is a special function doing anything we want. self.performMagic(self.blanks, self.dsdb_certificate, self.minting_denominations) else: self.manager.walletMessageType.persistant.reason = result self._createAndOutputWallet(BlankReject) elif isinstance(message, MintingKeyPass): # we've received a key minting_certificate = self.manager.isMessageType.persistant.minting_certificate print 'received minting_certificate: %s' % str(minting_certificate) self.mkfType[self.mkfSearch] = minting_certificate self.mkfReturn() elif isinstance(message, MintingKeyFailure): self.reason = message.messageLayer.persistant.reason self.manager.failure(message, self) elif isinstance(message, MintingKeyFetchKeyID) or isinstance( message, MintingKeyFetchDenomination): self._verifyLastState(['BlankAndMintingKey' ]) # make sure we started in here # but we did send these messages, so do nothing else self._setLastState( 'BlankAndMintingKey' ) # There are many different ways to exit this. Just cover them all.