| # -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */ |
| # |
| # Copyright (C) 2014-2015 Regents of the University of California. |
| # Author: Jeff Thompson <jefft0@remap.ucla.edu> |
| # |
| # This program is free software: you can redistribute it and/or modify |
| # it under the terms of the GNU Lesser General Public License as published by |
| # the Free Software Foundation, either version 3 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU Lesser General Public License for more details. |
| # |
| # You should have received a copy of the GNU Lesser General Public License |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| # A copy of the GNU Lesser General Public License is in the file COPYING. |
| |
| import time |
| import json |
| from pyndn import Name, Face, Interest, Data, ThreadsafeFace |
| from pyndn import KeyLocator, KeyLocatorType |
| from base_node import BaseNode |
| from hmac_helper import HmacHelper |
| from pyndn.security.security_exception import SecurityException |
| from pyndn.util import Blob |
| try: |
| import asyncio |
| except ImportError: |
| import trollius as asyncio |
| |
| def dump(*list): |
| result = "" |
| for element in list: |
| result += (element if type(element) is str else repr(element)) + " " |
| print(result) |
| |
| class Device(BaseNode): |
| def __init__(self,configFileName): |
| super(Device, self).__init__(configFileName=configFileName) |
| |
| self._deviceSerial = self.getSerial() |
| self._callbackCount = 0 |
| self._symKey = "symmetricKeyForBootstrapping" |
| self._category = "sensors" |
| self._id = "T9273659" |
| self._hmacHelper = HmacHelper(self._symKey) |
| |
| |
| def expressBootstrapInterest(self): |
| |
| #generate bootstrap name /home/controller/bootstrap/<device-parameters> |
| bootstrapName = Name(self._bootstrapPrefix) |
| |
| deviceParameters = {} |
| deviceParameters["category"] = self._category |
| deviceParameters["id"] = self._id |
| bootstrapName.append(json.dumps(deviceParameters)) |
| |
| bootstrapInterest = Interest(bootstrapName) |
| bootstrapInterest.setInterestLifetimeMilliseconds(5000) |
| #bootstrapKeyLocator = KeyLocator() |
| #bootstrapKeyLocator.setType(KeyLocatorType.KEY_LOCATOR_DIGEST) |
| #bootstrapKeyLocator.setKeyData(self._symKey) |
| #bootstrapInterest.setKeyLocator(bootstrapKeyLocator) |
| self._hmacHelper.signInterest(bootstrapInterest) |
| |
| dump("Express bootstrap interest : ",bootstrapInterest.toUri()) |
| self.face.expressInterest(bootstrapInterest, self.onBootstrapData, self.onTimeout) |
| def onInterest(): |
| pass |
| def onRegisterFailed(): |
| pass |
| |
| def onBootstrapData(self, interest, data): |
| dump("Bootstrap data received.") |
| |
| if (self._hmacHelper.verifyData(data)): |
| self.log.info("Bootstrap data is verified") |
| content = json.loads(data.getContent().toRawStr(), encoding="latin-1") |
| deviceNewIdentity = Name(content["deviceNewIdentity"]) |
| controllerIdentity = Name(content["controllerIdentity"]) |
| controllerPublicKeyInfo = content["controllerPublicKey"] |
| |
| self.face.registerPrefix(content["deviceNewIdentity"],self.onInterest,self.onRegisterFailed) |
| #set new identity as default and generate default key-pair with KSK Certificate |
| self._identityStorage.addIdentity(deviceNewIdentity) |
| self._identityManager.setDefaultIdentity(deviceNewIdentity) |
| try: |
| self._identityManager.getDefaultKeyNameForIdentity(deviceNewIdentity) |
| except SecurityException: |
| #generate new key-pair and certificate for new identity |
| dump("Install new identity as default\nGenerate new key-pair and self signed certificate") |
| newKey = self._identityManager.generateRSAKeyPairAsDefault(Name(deviceNewIdentity), isKsk=True) |
| newCert = self._identityManager.selfSign(newKey) |
| self._identityManager.addCertificateAsIdentityDefault(newCert) |
| |
| #add controller's identity and public key |
| keyType = controllerPublicKeyInfo["keyType"] |
| keyName = Name(controllerPublicKeyInfo["keyName"]) |
| keyDer = Blob().fromRawStr(controllerPublicKeyInfo["publicKeyDer"]) |
| dump("Controller's KeyType: ",keyType) |
| dump("Controller's keyName: ",keyName) |
| dump("Controller public key der : ",keyDer) |
| |
| self._identityStorage.addIdentity(controllerIdentity) |
| try: |
| self._identityStorage.addKey(keyName, keyType, keyDer) |
| dump("Controller's identity, key and certificate installled.") |
| except SecurityException: |
| dump("Controller's identity, key, certificate already exists.") |
| |
| #express an certificate request interest |
| defaultKeyName = self._identityManager.getDefaultKeyNameForIdentity(self._keyChain.getDefaultIdentity() ) |
| self.requestCertificate(defaultKeyName) |
| else: |
| self.log.info("Bootstrap data is not verified") |
| |
| |
| |
| |
| def beforeLoopStart(self): |
| #self.face.registerPrefix('/', self.onInterest, self.onRegisterFailed) |
| self.expressBootstrapInterest() |
| |
| def onTimeout(self, interest): |
| self._callbackCount += 1 |
| dump("Time out for interest", interest.getName().toUri()) |
| |
| def requestCertificate(self, keyIdentity): |
| """ |
| We compose a command interest with our public key info so the controller |
| can sign us a certificate that can be used with other nodes in the network. |
| Name format : /home/<device-category>/KEY/<device-id>/<key-id>/<publickey>/ID-CERT/<version-number> |
| """ |
| certificateRequestName = self._keyChain.getDefaultIdentity() |
| deviceIdComponent = certificateRequestName.get(-1) |
| keyIdComponent = keyIdentity.get(-1) |
| |
| certificateRequestName = certificateRequestName |
| certificateRequestName.append("KEY") |
| #certificateRequestName.append(deviceIdComponent) |
| certificateRequestName.append(keyIdComponent) |
| |
| key = self._identityManager.getPublicKey(keyIdentity) |
| keyInfo = {} |
| keyInfo["keyType"] = key.getKeyType() |
| keyInfo["keyDer"] = key.getKeyDer().toRawStr() |
| |
| certificateRequestName.append(json.dumps(keyInfo, encoding="latin-1")) |
| |
| certificateRequestName.append("ID-CERT") |
| |
| certificateRequest = Interest(certificateRequestName) |
| certificateRequest.setInterestLifetimeMilliseconds(5000) |
| self._hmacHelper.signInterest(certificateRequest) |
| |
| dump("Sending certificate request : ",certificateRequestName) |
| |
| self.face.expressInterest(certificateRequest, self.onCertificateData, self.onTimeout) |
| #TODO use symmetric key to sign |
| |
| def onCertificateData(self, interest, data): |
| dump("OnCertificateData : ",data) |
| |
| |
| if __name__ == '__main__': |
| |
| device = Device("tmp.conf") |
| device.start() |
| |
| |
| |