import os from twisted.trial import unittest from twisted.application import service from foolscap.api import Tub, fireEventually, flushEventualQueue from allmydata import key_generator from allmydata.util import pollmixin from allmydata.test.common import TEST_RSA_KEY_SIZE from pycryptopp.publickey import rsa def flush_but_dont_ignore(res): d = flushEventualQueue() def _done(ignored): return res d.addCallback(_done) return d class KeyGenService(unittest.TestCase, pollmixin.PollMixin): def setUp(self): self.parent = service.MultiService() self.parent.startService() self.tub = t = Tub() t.setOption("expose-remote-exception-types", False) t.setServiceParent(self.parent) t.listenOn("tcp:0") t.setLocationAutomatically() return fireEventually() def tearDown(self): d = self.parent.stopService() d.addCallback(fireEventually) d.addBoth(flush_but_dont_ignore) return d def test_key_gen_service(self): def p(junk, msg): #import time #print time.asctime(), msg return junk #print 'starting key generator service' keysize = TEST_RSA_KEY_SIZE kgs = key_generator.KeyGeneratorService(display_furl=False, default_key_size=keysize) kgs.key_generator.verbose = True kgs.setServiceParent(self.parent) kgs.key_generator.pool_size = 8 def keypool_full(): return len(kgs.key_generator.keypool) == kgs.key_generator.pool_size # first wait for key gen pool to fill up d = fireEventually() d.addCallback(p, 'waiting for pool to fill up') d.addCallback(lambda junk: self.poll(keypool_full)) d.addCallback(p, 'grabbing a few keys') # grab a few keys, check that pool size shrinks def get_key(junk=None): d = self.tub.getReference(kgs.keygen_furl) d.addCallback(lambda kg: kg.callRemote('get_rsa_key_pair', keysize)) return d def check_poolsize(junk, size): self.failUnlessEqual(len(kgs.key_generator.keypool), size) n_keys_to_waste = 4 for i in range(n_keys_to_waste): d.addCallback(get_key) d.addCallback(check_poolsize, kgs.key_generator.pool_size - n_keys_to_waste) d.addCallback(p, 'checking a key works') # check that a retrieved key is actually useful d.addCallback(get_key) def check_key_works(keys): verifying_key, signing_key = keys v = rsa.create_verifying_key_from_string(verifying_key) s = rsa.create_signing_key_from_string(signing_key) junk = os.urandom(42) sig = s.sign(junk) self.failUnless(v.verify(junk, sig)) d.addCallback(check_key_works) d.addCallback(p, 'checking pool exhaustion') # exhaust the pool for i in range(kgs.key_generator.pool_size): d.addCallback(get_key) d.addCallback(check_poolsize, 0) # and check it still works (will gen key synchronously on demand) d.addCallback(get_key) d.addCallback(check_key_works) d.addCallback(p, 'checking pool replenishment') # check that the pool will refill d.addCallback(lambda junk: self.poll(keypool_full)) return d