def create_identity(name): key_chain = KeyChain() try: cur_id = key_chain.getPib().getIdentity(Name(name)) key_chain.createKey(cur_id) except Pib.Error: key_chain.createIdentityV2(Name(name))
class IdentityManagementFixture(object): def __init__(self): self._keyChain = KeyChain("pib-memory:", "tpm-memory:") self._identityNames = set() self._certificateFiles = set() def saveCertificateToFile(self, data, filePath): """ :param Data data: The certificate to save. :param str filePath: The file path, which should be writable. :return: True if successful. :rtype: bool """ self._certificateFiles.add(filePath) try: encoding = data.wireEncode() encodedCertificate = Common.base64Encode(encoding.toBytes(), True) with open(filePath, 'w') as keyFile: keyFile.write(encodedCertificate) return True except Exception: return False def addIdentity(self, identityName, params = None): """ Add an identity for the identityName. :param Name identityName: The name of the identity. :param KeyParams params: (optional) The key parameters if a key needs to be generated for the identity. If omitted, use KeyChain.getDefaultKeyParams(). :return: The created PibIdentity instance. :rtype: PibIdentity """ if params == None: params = KeyChain.getDefaultKeyParams() identity = self._keyChain.createIdentityV2(identityName, params) self._identityNames.add(identityName) return identity def saveCertificate(identity, filePath): """ Save the identity's certificate to a file. :param PibIdentity identity: The PibIdentity. :param str filePath: The file path, which should be writable. :return: True if successful. :rtype: str """ try: certificate = identity.getDefaultKey().getDefaultCertificate() return self.saveCertificateToFile(certificate, filePath) except Pib.Error: return False def addSubCertificate(self, subIdentityName, issuer, params = None): """ Issue a certificate for subIdentityName signed by issuer. If the identity does not exist, it is created. A new key is generated as the default key for the identity. A default certificate for the key is signed by the issuer using its default certificate. """ if params == None: params = KeyChain.getDefaultKeyParams() subIdentity = self.addIdentity(subIdentityName, params) request = subIdentity.getDefaultKey().getDefaultCertificate() request.setName(request.getKeyName().append("parent").appendVersion(1)) certificateParams = SigningInfo(issuer) # Validity period of 20 years. now = Common.getNowMilliseconds() certificateParams.setValidityPeriod( ValidityPeriod(now, now + 20 * 365 * 24 * 3600 * 1000.0)) # Skip the AdditionalDescription. self._keyChain.sign(request, certificateParams) self._keyChain.setDefaultCertificate(subIdentity.getDefaultKey(), request) return subIdentity def addCertificate(self, key, issuerId): """ Add a self-signed certificate made from the key and issuer ID. :param PibKey key: The key for the certificate. :param str issuerId: The issuer ID name component for the certificate name. :return: The new certificate. :rtype: CertificateV2 """ certificateName = Name(key.getName()) certificateName.append(issuerId).appendVersion(3) certificate = CertificateV2() certificate.setName(certificateName) # Set the MetaInfo. certificate.getMetaInfo().setType(ContentType.KEY) # One hour. certificate.getMetaInfo().setFreshnessPeriod(3600 * 1000.0) # Set the content. certificate.setContent(key.getPublicKey()) params = SigningInfo(key) # Validity period of 10 days. now = Common.getNowMilliseconds() params.setValidityPeriod( ValidityPeriod(now, now + 10 * 24 * 3600 * 1000.0)) self._keyChain.sign(certificate, params) return certificate
class Experiment: _maxSegmentPayloadLength = 8192 def __init__(self, absPath, maxAttributes): self.keyChain = KeyChain("pib-memory:", "tpm-memory:") self.keyChain.createIdentityV2("/test/identity") self.validator = Validator( ValidationPolicyFromPib(self.keyChain.getPib())) # , filename, groupSize, nAttributes, absPath, keepData = False): # sys.stderr.write ("Using NDN-ABS authority, signer, and verifier database from %s\n" % absPath) self.db = ndnabs.PickleDb(absPath) self.signer = ndnabs.Signer(self.db) self.verifier = ndnabs.Verifier(self.db) try: info = self.signer.get_public_params_info() if info.getName().getPrefix( -2).toUri() != "/icn2019/test/authority": raise RuntimeError( 'NDN-ABS authority exists, but not setup for experiment. Use `ndnabs setup -f /icn2019/test/authority` to force-setup the authority' ) except: raise RuntimeError( "Public parameters are not properly installed for the signer/verifier" ) maxAttributes = [ b'attribute%d' % i for i in range(1, maxAttributes + 1) ] for attr in maxAttributes: if not attr in self.signer.get_attributes(): raise RuntimeError( "%s attribute missing. Generate attributes for the experiment using `ndnabs gen-secret %s | ndnabs install-secret`" % (str(attr, 'utf-8'), ' '.join( [str(i, 'utf-8') for i in maxAttributes]))) # self.attributes = [b'attribute%d' % i for i in range(1, nAttributes + 1)] # self._setupAbs(absPath) # self._readDataAndCreateManifests(filename, groupSize, keepData) def setupAbs(self, nAttributes): self.attributes = [ b'attribute%d' % i for i in range(1, nAttributes + 1) ] def _createManifest(self, name, manifestBuffer, nManifests): manifest = Data(name) manifest.setContent(manifestBuffer[0:nManifests * SHA256_DIGEST_SIZE]) return manifest def readDataAndCreateManifests(self, filename, groupSize, keepData): if groupSize < 1: raise RuntimeError("Group size cannot be less than 1") self.allChunks = [ ] # for holding the generated data packets, including unsigned manifests self.allManifests = [ ] # for storing first unsigned manifest packets, which are then signed in-place self.rawDataCount = 0 self.ndnChunkCount = 0 seqNo = 0 # sequence number of data packets chunkNo = 0 # number of the chunk in the group with open(filename, 'rb') as f: # prepare space to store all manifests of the group (last manifest will not use all the space) def allocateBufferForDigests(): return bytearray(groupSize * SHA256_DIGEST_SIZE) digests = allocateBufferForDigests() while f.readable(): chunkPayload = f.read(self._maxSegmentPayloadLength) if len(chunkPayload) == 0: break self.rawDataCount = self.rawDataCount + len(chunkPayload) chunk = Data( Name("/icn2019/test/data").appendSequenceNumber(seqNo)) seqNo = seqNo + 1 chunk.setContent(chunkPayload) digestSignature = DigestSha256Signature() digestSignature.setSignature( Blob(bytearray(SHA256_DIGEST_SIZE)) ) # not real a valid signature, but ok for the experiment chunk.setSignature(digestSignature) if keepData: self.allChunks.append(chunk) # only data chunks; manifest sizes counted separatedly, as they are signed self.ndnChunkCount = self.ndnChunkCount + chunk.wireEncode( ).size() # For storing data packet to a file # with open(writepath + "-1.txt", "wb") as dataf # dataf.write(dpacket_bytes) implicitDigest = chunk.getFullName()[-1].getValue() offset = chunkNo * SHA256_DIGEST_SIZE digests[offset:offset + SHA256_DIGEST_SIZE] = implicitDigest.toBytes()[:] chunkNo = chunkNo + 1 if chunkNo == groupSize: manifest = self._createManifest( Name("/icn2019/test/data").appendSequenceNumber(seqNo), digests, groupSize) # full group seqNo = seqNo + 1 self.allChunks.append(manifest) self.allManifests.append(manifest) chunkNo = 0 digests = allocateBufferForDigests() if chunkNo != 0: manifest = self._createManifest( Name("/icn2019/test/data").appendSequenceNumber(seqNo), digests, groupSize) # partial group self.allChunks.append(manifest) self.allManifests.append(manifest) self.nDataChunks = seqNo - len( self.allManifests ) # number of data packets, excluding the manifests def signManifestsABS(self): self.manifestCount = 0 self.signatureCounts = [] for manifest in self.allManifests: self.signer.sign(manifest, self.attributes) self.manifestCount = self.manifestCount + manifest.wireEncode( ).size() self.signatureCounts.append( manifest.getSignature().getSignature().size()) def verifyManifestsABS(self): for manifest in self.allManifests: if not self.signer.verify(manifest.wireEncode()): sys.stderr.write("Failed to verify %s\n" % manifest.getName()) def signManifestsRSA(self): self.manifestCount = 0 self.signatureCounts = [] for manifest in self.allManifests: self.keyChain.sign(manifest) self.manifestCount = self.manifestCount + manifest.wireEncode( ).size() self.signatureCounts.append( manifest.getSignature().getSignature().size()) def verifyManifestsRSA(self): def onSuccess(*k, **kw): pass def onFailure(data, *k, **kw): sys.stderr.write("Failed to verify %s\n" % manifest.getName()) for manifest in self.allManifests: self.validator.validate(manifest, onSuccess, onFailure)
class Server: def __init__(self, emit_func): self.emit = emit_func self.running = True self.event_list = [] # 1. If you use default constructor, when NFD is not started, # TcpTransport will be used instead of UnixTransport. # 2. Both TcpTransport and UnixTransport are not connected # before the first Interest is sent. # file_path = Face._getUnixSocketFilePathForLocalhost() # transport = UnixTransport() # connection_info = UnixTransport.ConnectionInfo(file_path) # self.face = Face(transport, connection_info) self.keychain = KeyChain() self.face = None def start_reconnection(self): """ Start reconnection process. NOT thread safe. """ self.face.shutdown() self.face = None def get_or_create_certificate(self): id_name = Name('/ndncc') cur_id = self.keychain.createIdentityV2(id_name) return cur_id.getDefaultKey().getDefaultCertificate().name def connection_test(self): interest = Interest("/localhost/nfd/faces/events") interest.mustBeFresh = True interest.canBePrefix = True interest.interestLifetimeMilliseconds = 1000 try: def empty(*_args, **_kwargs): pass self.face.expressInterest(interest, empty, empty, empty) return True except (ConnectionRefusedError, BrokenPipeError, OSError): return False async def run(self): while self.running: logging.info("Restarting face...") self.face = Face() self.face.setCommandSigningInfo(self.keychain, self.get_or_create_certificate()) if self.connection_test(): logging.info("Face creation succeeded") face_event = asyncio.get_event_loop().create_task(self.face_event()) while self.running and self.face is not None: try: self.face.processEvents() except AttributeError: logging.info("Attribute error.") self.start_reconnection() await asyncio.sleep(0.01) await face_event else: logging.info("Face creation failed") await asyncio.sleep(3) @staticmethod def face_event_to_dict(msg): ret = {} if msg.face_event_kind == 1: ret['face_event_kind'] = "CREATED" elif msg.face_event_kind == 2: ret['face_event_kind'] = "DESTROYED" elif msg.face_event_kind == 3: ret['face_event_kind'] = "UP" elif msg.face_event_kind == 4: ret['face_event_kind'] = "DOWN" else: ret['face_event_kind'] = "unknown" ret['face_id'] = str(msg.face_id) ret['local_uri'] = msg.local_uri.decode("utf-8") ret['remote_uri'] = msg.uri.decode("utf-8") if msg.face_scope == 1: ret['face_scope'] = "local" else: ret['face_scope'] = "non-local" if msg.face_persistency == 0: ret['face_persistency'] = "persistent" elif msg.face_event_kind == 1: ret['face_persistency'] = "on-demand" elif msg.face_persistency == 2: ret['face_persistency'] = "permanent" else: ret['face_persistency'] = "unknown" if msg.link_type == 0: ret['link_type'] = "point-to-point" elif msg.link_type == 1: ret['link_type'] = "multi-access" elif msg.link_type == 2: ret['link_type'] = "ad-hoc" else: ret['link_type'] = "unknown" ret['flags'] = str(msg.flags) return ret @staticmethod def response_to_dict(msg): ret = {'st_code': msg.st_code, 'st_text': msg.st_text.decode('utf-8')} return ret async def face_event(self): last_seq = -1 retry_time = 3000 retry_count_limit = 60000 // retry_time retry_count = 0 while self.running and self.face: name = Name("/localhost/nfd/faces/events") face_interest = Interest() if last_seq >= 0: name.appendSequenceNumber(last_seq + 1) face_interest.canBePrefix = False else: face_interest.mustBeFresh = True face_interest.canBePrefix = True logging.info("Face event notification stream %s", name.toUri()) face_interest.name = name # face_interest.interestLifetimeMilliseconds = 60000 face_interest.interestLifetimeMilliseconds = retry_time ret = await fetch_data_packet(self.face, face_interest) timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") if isinstance(ret, Data): retry_count = 0 last_seq = ret.name[-1].toSequenceNumber() face_event = FaceEventNotificationMessage() try: ProtobufTlv.decode(face_event, ret.content) dic = self.face_event_to_dict(face_event.face_event_notification) dic['seq'] = str(last_seq) dic['time'] = timestamp self.emit('face event', dic) self.event_list.append(dic) except RuntimeError as exc: logging.fatal('Decode failed %s', exc) last_seq = -1 elif ret is None: if retry_count >= retry_count_limit: logging.info("No response: face event") last_seq = -1 retry_count = 0 else: retry_count += 1 else: logging.info("NFD is not running: start reconnection") self.start_reconnection() return await asyncio.sleep(0.1) async def issue_command_interest(self, interest): ret = await fetch_data_packet(self.face, interest) if isinstance(ret, Data): response = ControlResponseMessage() try: ProtobufTlv.decode(response, ret.content) dic = self.response_to_dict(response.control_response) logging.info("Issue command Interest with %s", dic) return dic except RuntimeError as exc: logging.fatal('Decode failed %s', exc) return None async def add_face(self, uri): # It's not easy to distinguish udp4://127.0.0.1 and udp4://spurs.cs.ucla.edu # if reduce(lambda a, b: a or b, (x.isalpha() for x in uri)): # uri = socket.gethostbyname(uri) if uri[-1] == "/": uri = uri[:-1] if uri.find("://") < 0: uri = "udp4://" + uri if len(uri.split(":")) < 3: uri = uri + ":6363" interest = self.make_command('faces', 'create', uri=uri) return await self.issue_command_interest(interest) async def remove_face(self, face_id: int): interest = self.make_command('faces', 'destroy', face_id=face_id) return await self.issue_command_interest(interest) async def add_route(self, name: str, face_id: int): interest = self.make_command('rib', 'register', name=Name(name), face_id=face_id) return await self.issue_command_interest(interest) async def remove_route(self, name: str, face_id: int): interest = self.make_command('rib', 'unregister', name=Name(name), face_id=face_id) return await self.issue_command_interest(interest) async def set_strategy(self, name: str, strategy: str): interest = self.make_command('strategy-choice', 'set', name=Name(name), strategy=Name(strategy)) return await self.issue_command_interest(interest) async def unset_strategy(self, name: str): interest = self.make_command('strategy-choice', 'unset', name=Name(name)) return await self.issue_command_interest(interest) def run_server(self, work_loop): asyncio.set_event_loop(work_loop) try: work_loop.run_until_complete(self.run()) finally: work_loop.close() @staticmethod def start_server(emit_func): done = threading.Event() server = None def create_and_run(): nonlocal server, done server = Server(emit_func) work_loop = asyncio.new_event_loop() asyncio.set_event_loop(work_loop) done.set() try: work_loop.run_until_complete(server.run()) finally: work_loop.close() thread = threading.Thread(target=create_and_run) thread.setDaemon(True) thread.start() done.wait() return server def make_command(self, module, verb, **kwargs): name = Name('/localhost/nfd').append(module).append(verb) # Command Parameters cmd_param = ControlCommandMessage() if 'name' in kwargs: name_param = kwargs['name'] for compo in name_param: cmd_param.control_parameters.name.component.append(compo.getValue().toBytes()) if 'strategy' in kwargs: name_param = kwargs['strategy'] for compo in name_param: cmd_param.control_parameters.strategy.name.component.append(compo.getValue().toBytes()) for key in ['uri', 'local_uri']: if key in kwargs: setattr(cmd_param.control_parameters, key, kwargs[key].encode('utf-8')) for key in ['face_id', 'origin', 'cost', 'capacity', 'count', 'base_cong_mark', 'def_cong_thres', 'mtu', 'flags', 'mask', 'exp_period']: if key in kwargs: setattr(cmd_param.control_parameters, key, kwargs[key]) param_blob = ProtobufTlv.encode(cmd_param) name.append(Name.Component(param_blob)) # Command Interest Components ret = Interest(name) ret.canBePrefix = True self.face.makeCommandInterest(ret) return ret @staticmethod def list_key_tree(): """ Return the id-key-cert tree in a JSON like dict object. """ pib = KeyChain().getPib() identities = pib._identities._identityNames ret = {} try: default_id = pib.getDefaultIdentity().getName() except Pib.Error: default_id = Name('/') for id_name in identities: id_obj = pib.getIdentity(Name(id_name)) cur_id = {'default': '*' if id_name == default_id else ' '} try: default_key = id_obj.getDefaultKey().getName() except Pib.Error: default_key = Name('/') keys = id_obj._getKeys()._keyNames cur_id['keys'] = {} for key_name in keys: key_obj = id_obj.getKey(Name(key_name)) cur_key = {'default': '*' if key_name == default_key else ' '} try: default_cert = key_obj.getDefaultCertificate().getName() except Pib.Error: default_cert = Name('/') key_type = key_obj.getKeyType() if key_type <= 4: cur_key['key_type'] = ['NONE', 'RSA', 'EC', 'AES', 'HMAC'][key_type] else: cur_key['key_type'] = 'unknown' certs = key_obj._getCertificates()._certificateNames cur_key['certs'] = {} for cert_name in certs: cert_obj = key_obj.getCertificate(Name(cert_name)) signature = cert_obj.getSignature() cur_cert = { 'default': '*' if cert_name == default_cert else ' ', 'not_before': str(cert_obj.getValidityPeriod().getNotBefore()), 'not_after': str(cert_obj.getValidityPeriod().getNotAfter()), 'issuer_id': cert_obj.getIssuerId().toEscapedString(), 'key_locator': signature.getKeyLocator().getKeyName().toUri(), 'signature_type': cert_obj.getSignature().__class__.__name__, } cur_key['certs'][cert_name.toUri()] = cur_cert cur_id['keys'][key_name.toUri()] = cur_key ret[id_name.toUri()] = cur_id return ret @staticmethod def create_identity(name): key_chain = KeyChain() try: cur_id = key_chain.getPib().getIdentity(Name(name)) key_chain.createKey(cur_id) except Pib.Error: key_chain.createIdentityV2(Name(name)) @staticmethod def delete_security_object(name, kind): key_chain = KeyChain() logging.info("Delete security object %s %s", name, kind) if kind == "c": id_name = CertificateV2.extractIdentityFromCertName(Name(name)) key_name = CertificateV2.extractKeyNameFromCertName(Name(name)) cur_id = key_chain.getPib().getIdentity(id_name) cur_key = cur_id.getKey(key_name) key_chain.deleteCertificate(cur_key, Name(name)) elif kind == "k": id_name = PibKey.extractIdentityFromKeyName(Name(name)) cur_id = key_chain.getPib().getIdentity(id_name) cur_key = cur_id.getKey(Name(name)) key_chain.deleteKey(cur_id, cur_key) else: key_chain.deleteIdentity(Name(name)) async def query_face_id(self, uri): query_filter = FaceQueryFilterMessage() query_filter.face_query_filter.uri = uri.encode('utf-8') query_filter_msg = ProtobufTlv.encode(query_filter) name = Name("/localhost/nfd/faces/query").append(Name.Component(query_filter_msg)) interest = Interest(name) interest.mustBeFresh = True interest.canBePrefix = True ret = await fetch_data_packet(self.face, interest) if not isinstance(ret, Data): return None msg = FaceStatusMessage() try: ProtobufTlv.decode(msg, ret.content) except RuntimeError as exc: logging.fatal("Decoding Error %s", exc) return None if len(msg.face_status) <= 0: return None return msg.face_status[0].face_id async def autoconf(self): """ Automatically connect to ndn testbed. Add route /ndn and /localhop/nfd. """ uri = urllib.request.urlopen("http://ndn-fch.named-data.net/").read().decode('utf-8') uri = socket.gethostbyname(uri) uri = "udp4://" + uri + ":6363" interest = self.make_command('faces', 'create', uri=uri) ret = await fetch_data_packet(self.face, interest) if not isinstance(ret, Data): return False, "Create face failed" response = ControlResponseMessage() try: ProtobufTlv.decode(response, ret.content) except RuntimeError as exc: logging.info('Decode failed %s', exc) return False, "Create face failed" # # Ignore duplicated face # if response.control_response.st_code not in {200, 409}: # return False, "Create face failed" face_id = await self.query_face_id(uri) if face_id is None: return False, "Create face failed" route = Name("/ndn") interest = self.make_command('rib', 'register', name=route, face_id=face_id, origin=66, cost=100) await fetch_data_packet(self.face, interest) route = Name("/localhop/nfd") interest = self.make_command('rib', 'register', name=route, face_id=face_id, origin=66, cost=100) await fetch_data_packet(self.face, interest) return True, "Auto-configuration finished"
class ClientModule(): def __init__(self, caPrefix): self.ecdh = ECDHState() self.face = Face() self.keyChain = KeyChain() self.key = None self.caPrefix = caPrefix self.anchor = CertificateV2() self.anchor.wireDecode( Blob( b64decode( "Bv0DgQc7CANuZG4IA2VkdQgHbWVtcGhpcwgIYWdhd2FuZGUIA0tFWQgIo6cuGT4GVKEIAk5BCAn9AAABbQxT3hEUCRgBAhkEADbugBX9ASYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDII1sLOE7cCQVTKoGjeM5o/mxWqhMx0siLHJ81Ee/eUCNAMxA0w1oxAoTGQ8HbNP3vShZfvMJ/11Jiqus2wAWlNjRWvQShNv5MueU8kYtOGTbiqr/I1EpSRQ2aJX3s49CoskoWMzf6knK4ELleH3/EBUPGJK0cpHHdFOjwlzO3Y3Rtc/DhHVTVsBWvPS1wKgnzBFO36k73gAQJi4bOc0ggPPcK3UfVzpz8XTe+IcS2N9jew+kDqoZaL+HHz26PIAwQvXQFXPhE6y/nH/4yes24DlK3u+vHTQHXRKcLNSpYvmS6KrHvt2t01Fk0hXxeFkbh4XaE73eXB9AzNw+AccovAgMBAAEW/QEHGwEBHCQHIggDbmRuCANlZHUIB21lbXBoaXMIA0tFWQgI9bIQPIJIGTf9AP0m/QD+DzIwMTkwOTA2VDE1MjQ0Nf0A/w8yMDIwMDkwNlQxNTI0NDX9AQKw/QIAD/0CAQdhZHZpc29y/QICAP0CACH9AgEFZW1haWz9AgIUYWdhd2FuZGVAbWVtcGhpcy5lZHX9AgAf/QIBCGZ1bGxuYW1l/QICD0FzaGxlc2ggR2F3YW5kZf0CAA39AgEFZ3JvdXD9AgIA/QIAD/0CAQdob21ldXJs/QICAP0CAC39AgEMb3JnYW5pemF0aW9u/QICGVRoZSBVbml2ZXJzaXR5IG9mIE1lbXBoaXMX/QEAMZ4XLBqFjABr/k58Gq6GrNfaDMb+NLyJYF5X2mDwKnUgp1is83eg/90LqO8AVGYdyirKfr23HP4565iJXhOmFgRbP+faN++0oUTXdUSvDm43Rp+OCHr9uGPPYjUjUeNhrD7Fxfq5m3EHNMxQqnVJOODpVrF3D0EYJ4Q4IETmxrSmuDpH9I92fs7rU/51aNAZbU7DewPmcq/IrY4RO5G9pfYR+gu/gyO/L8gN39EhBbsOYWOh3EYOdAJlSktP1evL/5yRdQq7bVLyG6dZSsYQ1x4XDJ9epUesZ+TbCK/lXfRrmFG9uk8TI/rZNAYfUiQifnsNvRu34PcyELiFJ/h2xA==" ))) self.identityName = "" self.status = None self.requestId = None self.challenges = None def sendProbeInterest(self): probeInterest = Interest( Name(self.caPrefix).append("CA").append("_PROBE")) probeInterest.setMustBeFresh(True) probeInterest.setCanBePrefix(False) probeInterest.setApplicationParameters( json.dumps({"email": "*****@*****.**"}, indent=4)) probeInterest.appendParametersDigestToName() print("Expressing interest: {}".format(probeInterest.getName())) self.face.expressInterest(probeInterest, self.onProbeData, self.onTimeout) def onProbeData(self, interest, data): """ Content: { "email": "*****@*****.**", "UID": "", "name: "\/ndn\/edu\/memphis\/agawande\/6046888920342781294" } 1) Verify signature 2) Extract name component from the json to use as identity """ if not VerificationHelpers.verifyDataSignature(data, self.anchor): print("Cannot verify signature from: {}".format(self.caPrefix)) else: print("Successfully verified data with hard-coded certificate") try: self.identityName = Name( json.loads(data.getContent().__str__())['name']) if self.identityName == "": print("Name received from server is empty") sys.exit(0) except Exception as e: print(e) print("Got namespace {} from server".format(self.identityName)) self.generateKeyAndSendNewInterest(data) def generateKeyAndSendNewInterest(self, probeTokenData): """ """ pib = self.keyChain.getPib() try: identity = pib.getIdentity(self.identityName) self.key = self.keyChain.createKey(identity) except Exception as e: identity = self.keyChain.createIdentityV2(self.identityName) self.key = identity.getDefaultKey() cert = CertificateV2() cert.setName( Name(self.key.getName()).append("cert-request").appendVersion( int(time.time()))) cert.getMetaInfo().setType(ContentType.KEY) cert.getMetaInfo().setFreshnessPeriod(24 * 3600) cert.setContent(self.key.getPublicKey()) signingInfo = SigningInfo(self.key) now = Common.getNowMilliseconds() signingInfo.setValidityPeriod( ValidityPeriod(now, now + 24 * 3600 * 1000.0)) self.keyChain.sign(cert, signingInfo) #cert = self.keyChain.selfSign(self.key) # Does not work because validity period is greater than certserver default interestName = Name(self.caPrefix).append("CA").append("_NEW") newInterest = Interest(interestName) newInterest.setMustBeFresh(True) newInterest.setCanBePrefix(False) ecdhPub = "{}\n".format(self.ecdh.getBase64PubKey()) ecdhCertReq = "{}\n".format( b64encode(cert.wireEncode().toBytes()).decode('utf-8')) probeToken = "{}\n".format( b64encode(probeTokenData.wireEncode().toBytes()).decode('utf-8')) jsonDump = json.dumps( { "ecdh-pub": ecdhPub, "cert-request": ecdhCertReq, "probe-token": probeToken }, indent=4) print(jsonDump) newInterest.setApplicationParameters(jsonDump) newInterest.appendParametersDigestToName() self.keyChain.sign(newInterest, SigningInfo(self.key)) print(newInterest.getName()) self.face.expressInterest(newInterest, self.onNewData, self.onTimeout) def onNewData(self, interest, data): """ !! Again \n in public key?? Got data: { "ecdh-pub": "Aqxofe3QdsAfgbtS8TMxv31oudNKoSV307ci5gNXm88h\n", "salt": "12935684137560555161", "request-id": "14275252044236690531", "status": "0", "challenges": [ { "challenge-id": "Email" } ] } 1. Verify data 2. Derive shared secret """ content = data.getContent() print("Got data: ", content) if not VerificationHelpers.verifyDataSignature(data, self.anchor): print("Cannot verify signature from: {}".format(self.caPrefix)) else: print("Successfully verified data with hard-coded certificate") contentJson = json.loads(content.__str__()) peerKeyBase64 = contentJson['ecdh-pub'] self.status = contentJson['status'] self.requestId = contentJson['request-id'] self.challenges = contentJson['challenges'] print(peerKeyBase64) serverPubKey = ec.EllipticCurvePublicKey.from_encoded_point( ec.SECP256R1(), b64decode(peerKeyBase64)) shared_key = self.ecdh.private_key.exchange(ec.ECDH(), serverPubKey) derived_key = HKDF(algorithm=hashes.SHA256(), length=32, salt=contentJson['salt'].encode(), info=b'handshake data', backend=default_backend()).derive(shared_key) self.ecdh.derived_key = derived_key print(shared_key) for t in shared_key: print(t) challengeInterestName = Name( self.caPrefix).append("CA").append("_CHALLENGE").append( self.requestId) challengeInterest = Interest(challengeInterestName) challengeInterest.setMustBeFresh(True) challengeInterest.setCanBePrefix(False) # Encrypt the interest parameters challengeJson = json.dumps( { "selected-challenge": "Email", "email": "*****@*****.**" }, indent=4) raw = self.pad(challengeJson, 16) print("raw", raw) iv = Random.new().read(AES.block_size) #cipher = AES.new(self.ecdh.derived_key, AES.MODE_CBC, iv) cipher = AES.new(shared_key, AES.MODE_CBC, iv) print(iv) xx = cipher.encrypt(raw) print(cipher.decrypt(xx)) print("Printing iv:") for t in iv: print(t) encoder = TlvEncoder(256) saveLength = len(encoder) encoder.writeBlobTlv(632, iv) encoder.writeBlobTlv(630, cipher.encrypt(raw)) #encoder.writeTypeAndLength(36, len(encoder) - saveLength) challengeInterest.setApplicationParameters(Blob(encoder.getOutput())) challengeInterest.appendParametersDigestToName() self.keyChain.sign(challengeInterest, SigningInfo(self.key)) with open('foobar.tlv', 'wb') as f: f.write(challengeInterest.wireEncode().buf()) self.face.expressInterest(challengeInterest, self.onChallengeData, self.onTimeout) def onChallengeData(self, interest, data): print("Got data: ", data) def pad(self, s, blocksize): return s + (blocksize - len(s) % blocksize) * ' ' def onTimeout(self, interest): print("Got timeout for interest: {}".format(interest.getName())) def start(self): while True: self.face.processEvents() # We need to sleep for a few milliseconds so we don't use 100% of the CPU. time.sleep(0.01)