def get(self, certificateName): """ Get the certificate with certificateName from the container. :param Name certificateName: The name of the certificate. :return: A copy of the certificate. :rtype: CertificateV2 :raises ValueError: If certificateName does not match the key name :raises Pib.Error: If the certificate does not exist. """ try: cachedCertificate = self._certificates[certificateName] except KeyError: cachedCertificate = None if cachedCertificate != None: # Make a copy. # TODO: Copy is expensive. Can we just tell the caller not to modify it? return CertificateV2(cachedCertificate) # Get from the PIB and cache. if (not CertificateV2.isValidName(certificateName) or not CertificateV2.extractKeyNameFromCertName(certificateName).equals (self._keyName)): raise ValueError("Certificate name `" + certificateName.toUri() + "` is invalid or does not match key name") certificate = self._pibImpl.getCertificate(certificateName) # Copy the certificate Name. self._certificates[Name(certificateName)] = certificate # Make a copy. # TODO: Copy is expensive. Can we just tell the caller not to modify it? return CertificateV2(certificate)
def remove(self, certificateName): """ Remove the certificate with name certificateName from the container. If the certificate does not exist, do nothing. :param Name certificateName: The name of the certificate. :raises ValueError: If certificateName does not match the key name. """ if (not CertificateV2.isValidName(certificateName) or not CertificateV2.extractKeyNameFromCertName(certificateName).equals (self._keyName)): raise ValueError("Certificate name `" + certificateName.toUri() + "` is invalid or does not match key name") try: self._certificateNames.remove(certificateName) except KeyError: # Do nothing if it doesn't exist. pass try: del self._certificates[certificateName] except KeyError: # Do nothing if it doesn't exist. pass self._pibImpl.removeCertificate(certificateName)
def getCertificate(self, certificateName): """ Get the certificate with name certificateName. :param Name certificateName: The name of the certificate. :return: A copy of the certificate. :rtype: CertificateV2 :raises Pib.Error: If the certificate does not exist. """ encoding = None try: cursor = self._database.cursor() cursor.execute( "SELECT certificate_data FROM certificates WHERE certificate_name=?", (sqlite3.Binary(bytearray( certificateName.wireEncode().buf())), )) row = cursor.fetchone() if row != None: (encoding, ) = row cursor.close() except Exception as ex: raise PibImpl.Error("PibSqlite3: SQLite error: " + str(ex)) if encoding != None: certificate = CertificateV2() certificate.wireDecode(bytearray(encoding)) return certificate else: raise Pib.Error("Certificate `" + certificateName.toUri() + "` does not exit")
def getDefaultCertificateOfKey(self, keyName): """ Get the default certificate for the key with eyName. :param Name keyName: The name of the key. :return: A copy of the default certificate. :rtype: CertificateV2 :raises Pib.Error: If the default certificate does not exist. """ encoding = None try: cursor = self._database.cursor() cursor.execute( "SELECT certificate_data " + "FROM certificates JOIN keys ON certificates.key_id=keys.id " + "WHERE certificates.is_default=1 AND keys.key_name=?", (sqlite3.Binary(bytearray(keyName.wireEncode().buf())), )) row = cursor.fetchone() if row != None: (encoding, ) = row cursor.close() except Exception as ex: raise PibImpl.Error("PibSqlite3: SQLite error: " + str(ex)) if encoding != None: certificate = CertificateV2() certificate.wireDecode(bytearray(encoding)) return certificate else: raise Pib.Error("No default certificate for key `" + keyName.toUri() + "`")
def addDirectory(self, directoryName, refreshPeriod): allFiles = [f for f in os.listdir(directoryName) if os.path.isfile(os.path.join(directoryName, f))] certificateNames = [] for f in allFiles: if self._isSecurityV1: try: fullPath = os.path.join(directoryName, f) cert = self.loadIdentityCertificateFromFile(fullPath) except Exception: pass # allow files that are not certificates else: # Cut off the timestamp so it matches KeyLocator Name format. certUri = cert.getName()[:-1].toUri() self._certificateCache.insertCertificate(cert) certificateNames.append(certUri) else: try: fullPath = os.path.join(directoryName, f) cert = self.loadCertificateV2FromFile(fullPath) except Exception: pass # allow files that are not certificates else: # Get the key name since this is in the KeyLocator. certUri = CertificateV2.extractKeyNameFromCertName( cert.getName()).toUri() self._certificateCacheV2.insert(cert) certificateNames.append(certUri) self._refreshDirectories[directoryName] = { 'certificates': certificateNames, 'nextRefresh': Common.getNowMilliseconds() + refreshPeriod, 'refreshPeriod':refreshPeriod }
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))
def _lookupCertificateV2(self, certID, isPath): """ This looks up certificates specified as base64-encoded data or file names. These are cached by filename or encoding to avoid repeated reading of files or decoding. :return: The CertificateV2, or None if not found. :rtype: CertificateV2 """ if self._isSecurityV1: raise SecurityException( "lookupCertificateV2: For security v1, use lookupCertificate()" ) try: certUri = self._fixedCertificateCache[certID] except KeyError: if isPath: # load the certificate data (base64 encoded IdentityCertificate) cert = TrustAnchorRefreshManager.loadCertificateV2FromFile( certID) else: certData = b64decode(certID) cert = CertificateV2() cert.wireDecode(Blob(certData, False)) certUri = cert.getName()[:-1].toUri() self._fixedCertificateCache[certID] = certUri self._certificateCacheV2.insert(cert) else: cert = self._certificateCacheV2.find(Name(certUri)) return cert
def onCertificateDownloadComplete(data): if self._isSecurityV1: try: certificate = IdentityCertificate(data) except: try: onValidationFailed( dataOrInterest, "Cannot decode certificate " + data.getName().toUri()) except: logging.exception("Error in onValidationFailed") return None self._certificateCache.insertCertificate(certificate) else: try: certificate = CertificateV2(data) except: try: onValidationFailed( dataOrInterest, "Cannot decode certificate " + data.getName().toUri()) except: logging.exception("Error in onValidationFailed") return None self._certificateCacheV2.insert(certificate) self.checkVerificationPolicy(dataOrInterest, stepCount + 1, onVerified, onValidationFailed)
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 = 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
def _processConfigTrustAnchor(self, configSection, inputName): """ Process the trust-anchor configuration section and call validator_.loadAnchor as needed. :param BoostInfoTree configSection: The section containing the definition of the trust anchor, e.g. one of "validator.trust-anchor". :param str inputName: Used for log messages, etc. """ anchorType = configSection.getFirstValue("type") if anchorType == None: raise ValidatorConfigError("Expected <trust-anchor.type>") if anchorType.lower() == "file": # Get trust-anchor.file . fileName = configSection.getFirstValue("file-name") if fileName == None: raise ValidatorConfigError("Expected <trust-anchor.file-name>") refreshPeriod = ValidationPolicyConfig._getRefreshPeriod( configSection) self._validator.loadAnchor(fileName, fileName, refreshPeriod, False) return elif anchorType.lower() == "base64": # Get trust-anchor.base64-string . base64String = configSection.getFirstValue("base64-string") if base64String == None: raise ValidatorConfigError( "Expected <trust-anchor.base64-string>") encoding = b64decode(base64String) certificate = CertificateV2() try: certificate.wireDecode(Blob(encoding, False)) except Exception as ex: raise ValidatorConfigError( "Cannot decode certificate from base64-string: " + repr(ex)) self._validator.loadAnchor("", certificate) return elif anchorType.lower() == "dir": # Get trust-anchor.dir . dirString = configSection.getFirstValue("dir") if dirString == None: raise ValidatorConfigError("Expected <trust-anchor.dir>") refreshPeriod = ValidationPolicyConfig._getRefreshPeriod( configSection) self._validator.loadAnchor(dirString, dirString, refreshPeriod, True) return elif anchorType.lower() == "any": self._shouldBypass = True else: raise ValidatorConfigError("Unsupported trust-anchor.type")
def test_refresh_10s(self): with open('policy_config/testData', 'r') as dataFile: encodedData = dataFile.read() data = Data() dataBlob = Blob(b64decode(encodedData)) data.wireDecode(dataBlob) # This test is needed, since the KeyChain will express interests in # unknown certificates. vr = doVerify(self.policyManager, data) self.assertTrue(vr.hasFurtherSteps, "ConfigPolicyManager did not create ValidationRequest for unknown certificate") self.assertEqual(vr.successCount, 0, "ConfigPolicyManager called success callback with pending ValidationRequest") self.assertEqual(vr.failureCount, 0, "ConfigPolicyManager called failure callback with pending ValidationRequest") # Now save the cert data to our anchor directory, and wait. # We have to sign it with the current identity or the policy manager # will create an interest for the signing certificate. cert = CertificateV2() certData = b64decode(CERT_DUMP) cert.wireDecode(Blob(certData, False)) signingInfo = SigningInfo() signingInfo.setSigningIdentity(self.identityName) # Make sure the validity period is current for two years. now = Common.getNowMilliseconds() signingInfo.setValidityPeriod(ValidityPeriod (now, now + 2 * 365 * 24 * 3600 * 1000.0)) self.keyChain.sign(cert, signingInfo) encodedCert = b64encode(cert.wireEncode().toBytes()) with open(self.testCertFile, 'w') as certFile: certFile.write(Blob(encodedCert, False).toRawStr()) # Still too early for refresh to pick it up. vr = doVerify(self.policyManager, data) self.assertTrue(vr.hasFurtherSteps, "ConfigPolicyManager refresh occured sooner than specified") self.assertEqual(vr.successCount, 0, "ConfigPolicyManager called success callback with pending ValidationRequest") self.assertEqual(vr.failureCount, 0, "ConfigPolicyManager called failure callback with pending ValidationRequest") time.sleep(6) # Now we should find it. vr = doVerify(self.policyManager, data) self.assertFalse(vr.hasFurtherSteps, "ConfigPolicyManager did not refresh certificate store") self.assertEqual(vr.successCount, 1, "Verification success called {} times instead of 1".format( vr.successCount)) self.assertEqual(vr.failureCount, 0, "ConfigPolicyManager did not verify valid signed data")
def loadCertificateV2FromFile(filename): """ :param str filename: :rtype: CertificateV2 """ with open(filename, 'r') as certFile: encodedData = certFile.read() decodedData = b64decode(encodedData) cert = CertificateV2() cert.wireDecode(Blob(decodedData, False)) return cert
def addCertificate(self, certificate): """ Add the certificate to the top of the certificate chain. If the certificate chain is empty, then the certificate should be the signer of the original packet. If the certificate chain is not empty, then the certificate should be the signer of the front of the certificate chain. Note: This function does not verify the signature bits. :param CertificateV2 certificate: The certificate to add, which is copied. """ self._certificateChain.insert(0, CertificateV2(certificate))
def getCertificate(self, certificateName): """ Get the certificate with name certificateName. :param Name certificateName: The name of the certificate. :return: A copy of the certificate. :rtype: CertificateV2 :raises Pib.Error: If the certificate does not exist. """ if not self.hasCertificate(certificateName): raise Pib.Error( "Certificate `" + certificateName.toUri() + "` does not exist") return CertificateV2(self._certificates[certificateName])
def _makeSelfSignedCertificate(keyName, privateKeyBag, publicKeyEncoding, password, digestAlgorithm, wireFormat): certificate = CertificateV2() # Set the name. now = Common.getNowMilliseconds() certificateName = Name(keyName) certificateName.append("self").appendVersion(int(now)) certificate.setName(certificateName) # Set the MetaInfo. certificate.getMetaInfo().setType(ContentType.KEY) # Set a one-hour freshness period. certificate.getMetaInfo().setFreshnessPeriod(3600 * 1000.0) # Set the content. publicKey = PublicKey(publicKeyEncoding) certificate.setContent(publicKey.getKeyDer()) # Create a temporary in-memory Tpm and import the private key. tpm = Tpm("", "", TpmBackEndMemory()) tpm._importPrivateKey(keyName, privateKeyBag.toBytes(), password) # Set the signature info. if publicKey.getKeyType() == KeyType.RSA: certificate.setSignature(Sha256WithRsaSignature()) elif publicKey.getKeyType() == KeyType.EC: certificate.setSignature(Sha256WithEcdsaSignature()) else: raise ValueError("Unsupported key type") signatureInfo = certificate.getSignature() KeyLocator.getFromSignature(signatureInfo).setType( KeyLocatorType.KEYNAME) KeyLocator.getFromSignature(signatureInfo).setKeyName(keyName) # Set a 20-year validity period. ValidityPeriod.getFromSignature(signatureInfo).setPeriod( now, now + 20 * 365 * 24 * 3600 * 1000.0) # Encode once to get the signed portion. encoding = certificate.wireEncode(wireFormat) signatureBytes = tpm.sign(encoding.toSignedBytes(), keyName, digestAlgorithm) signatureInfo.setSignature(signatureBytes) # Encode again to include the signature. certificate.wireEncode(wireFormat) return certificate
def test_overwrite(self): fixture = self.fixture pibImpl = PibMemory() try: PibKeyImpl(fixture.id1Key1Name, pibImpl) self.fail("Did not throw the expected exception") except Pib.Error: pass else: self.fail("Did not throw the expected exception") PibKeyImpl(fixture.id1Key1Name, fixture.id1Key1.buf(), pibImpl) key1 = PibKeyImpl(fixture.id1Key1Name, pibImpl) # Overwriting the key should work. PibKeyImpl(fixture.id1Key1Name, fixture.id1Key2.buf(), pibImpl) key2 = PibKeyImpl(fixture.id1Key1Name, pibImpl) # key1 should have cached the original public key. self.assertTrue(not key1.getPublicKey().equals(key2.getPublicKey())) self.assertTrue(key2.getPublicKey().equals(fixture.id1Key2)) key1.addCertificate(fixture.id1Key1Cert1) # Use the wire encoding to check equivalence. self.assertTrue( key1.getCertificate( fixture.id1Key1Cert1.getName()).wireEncode().equals( fixture.id1Key1Cert1.wireEncode())) otherCert = CertificateV2(fixture.id1Key1Cert1) otherCert.getSignature().getValidityPeriod().setPeriod( Common.getNowMilliseconds(), Common.getNowMilliseconds() + 1000) # Don't bother resigning so we don't have to load a private key. self.assertTrue(fixture.id1Key1Cert1.getName().equals( otherCert.getName())) self.assertTrue(otherCert.getContent().equals( fixture.id1Key1Cert1.getContent())) self.assertFalse(otherCert.wireEncode().equals( fixture.id1Key1Cert1.wireEncode())) key1.addCertificate(otherCert) self.assertTrue( key1.getCertificate( fixture.id1Key1Cert1.getName()).wireEncode().equals( otherCert.wireEncode()))
def getDefaultCertificateOfKey(self, keyName): """ Get the default certificate for the key with eyName. :param Name keyName: The name of the key. :return: A copy of the default certificate. :rtype: CertificateV2 :raises Pib.Error: If the default certificate does not exist. """ try: certificateName = self._defaultCertificateNames[keyName] except KeyError: raise Pib.Error( "No default certificate for key `" + keyName.toUri() + "`") certificate = self._certificates[certificateName] return CertificateV2(certificate)
def readCertificate(filePath): """ Read a base-64-encoded certificate from a file. :param str filePath: The certificate file path. :return: The decoded certificate, or None if there is an error. :rtype: CertificateV2 """ try: with open(filePath, 'r') as certificateFile: encodedData = certificateFile.read() decodedData = b64decode(encodedData) result = CertificateV2() result.wireDecode(Blob(decodedData, False)) return result except: return None
def insert(self, certificate): """ Insert the certificate into the cache. The inserted certificate will be removed no later than its NotAfter time, or maxLifetimeMilliseconds given to the constructor. :param CertificateV2 certificate: The certificate object, which is copied. """ notAfterTime = certificate.getValidityPeriod().getNotAfter() # _nowOffsetMilliseconds is only used for testing. now = Common.getNowMilliseconds() + self._nowOffsetMilliseconds if notAfterTime < now: logging.getLogger(__name__).info( "Not adding " + certificate.getName().toUri() + ": already expired at " + Schedule.toIsoString(notAfterTime)) return removalTime = min(notAfterTime, now + self._maxLifetimeMilliseconds) if removalTime < self._nextRefreshTime: # We need to run refresh() sooner. self._nextRefreshTime = removalTime logging.getLogger(__name__).info("Adding " + certificate.getName().toUri() + ", will remove in " + str((removalTime - now) / (3600 * 1000.0)) + " hours") certificateCopy = CertificateV2(certificate) certificateName = certificateCopy.getName() if certificateName in self._certificatesByName: # A duplicate name. Simply replace. self._certificatesByName[ certificateName]._certificate = certificateCopy self._certificatesByName[ certificateName]._removalTime = removalTime else: # Insert into _certificatesByNameKeys sorted. # Keep it sync with _certificatesByName. self._certificatesByName[ certificateName] = CertificateCacheV2._Entry( certificateCopy, removalTime) bisect.insort(self._certificatesByNameKeys, certificateName)
def add(self, certificate): """ Add the certificate to the container. :param CertificateV2 certificate: The certificate to add, which is copied. """ certificateCopy = CertificateV2(certificate) name = certificateCopy.getName() if name in self._anchorsByNameKeys: # Just replace the existing entry value. self._anchorsByName[name] = certificateCopy return # Insert into _anchorsByNameKeys sorted. # Keep it sync with _anchorsByName. self._anchorsByName[name] = certificateCopy bisect.insort(self._anchorsByNameKeys, name)
def add(self, certificate): """ Add certificate into the container. If the certificate already exists, this replaces it. :param CertificateV2 certificate: The certificate to add. This copies the object. :raises ValueError: If the name of the certificate does not match the key name. """ if not self._keyName.equals(certificate.getKeyName()): raise ValueError("The certificate name `" + certificate.getKeyName().toUri() + "` does not match the key name") certificateName = Name(certificate.getName()) self._certificateNames.add(certificateName) # Copy the certificate. self._certificates[certificateName] = CertificateV2(certificate) self._pibImpl.addCertificate(certificate)
def getCertificatesOfKey(self, keyName): """ Get a list of certificate names of the key with id keyName. The returned certificate names can be used to create a PibCertificateContainer. With a certificate name and a backend implementation, one can obtain the certificate. :param Name keyName: The name of the key. :return: The set of certificate names. The Name objects are fresh copies. If the key does not exist, return an empty set. :rtype: set of Name """ certificateNames = set() for certificateName in self._certificates: if (CertificateV2.extractKeyNameFromCertName (self._certificates[certificateName].getName()).equals(keyName)): # Copy the Name. certificateNames.add(Name(certificateName)) return certificateNames
def onData(interest, data): logging.getLogger(__name__).info( "Fetched certificate from network " + data.getName().toUri()) try: certificate = CertificateV2(data) except Exception as ex: state.fail( ValidationError( ValidationError.MALFORMED_CERTIFICATE, "Fetched a malformed certificate `" + data.getName().toUri() + "` (" + repr(ex) + ")")) return try: continueValidation(certificate, state) except Exception as ex: state.fail( ValidationError( ValidationError.CANNOT_RETRIEVE_CERTIFICATE, "Error in continueValidation: " + repr(ex)))
def removeCertificate(self, certificateName): """ Remove the certificate with name certificateName. If the certificate does not exist, do nothing. :param Name certificateName: The name of the certificate. """ try: del self._certificates[certificateName] except KeyError: # Do nothing if it doesn't exist. pass keyName = CertificateV2.extractKeyNameFromCertName(certificateName) try: defaultCertificateName = self._defaultCertificateNames[keyName] except KeyError: defaultCertificateName = None if (defaultCertificateName != None and defaultCertificateName.equals(certificateName)): del self._defaultCertificateNames[keyName]
def addCertificate(self, certificate): """ Add the certificate. If a certificate with the same name (without implicit digest) already exists, then overwrite the certificate. If the key or identity does not exist, they will be created. If no default certificate for the key has been set, then set the added certificate as the default for the key. If no default key was set for the identity, it will be set as the default key for the identity. If no default identity was selected, the certificate's identity becomes the default. :param CertificateV2 certificate: The certificate to add. This copies the object. """ certificateNameCopy = Name(certificate.getName()) # getKeyName already makes a new Name. keyNameCopy = certificate.getKeyName() identity = certificate.getIdentity() self.addKey(identity, keyNameCopy, certificate.getContent().toBytes()) self._certificates[certificateNameCopy] = CertificateV2(certificate) if not (keyNameCopy in self._defaultCertificateNames): self._defaultCertificateNames[keyNameCopy] = certificateNameCopy
def test_find_by_interest(self): self.anchorContainer.insert("group1", self.certificatePath1, 400.0) interest = Interest(self.identity1.getName()) self.assertTrue(self.anchorContainer.find(interest) != None) interest1 = Interest(self.identity1.getName().getPrefix(-1)) self.assertTrue(self.anchorContainer.find(interest1) != None) interest2 = Interest(Name(self.identity1.getName()).appendVersion(1)) self.assertTrue(self.anchorContainer.find(interest2) == None) certificate3 = self.fixture.addCertificate( self.identity1.getDefaultKey(), "3") certificate4 = self.fixture.addCertificate( self.identity1.getDefaultKey(), "4") certificate5 = self.fixture.addCertificate( self.identity1.getDefaultKey(), "5") certificate3Copy = CertificateV2(certificate3) self.anchorContainer.insert("group2", certificate3Copy) self.anchorContainer.insert("group3", certificate4) self.anchorContainer.insert("group4", certificate5) interest3 = Interest(certificate3.getKeyName()) foundCertificate = self.anchorContainer.find(interest3) self.assertTrue(foundCertificate != None) self.assertTrue(interest3.getName().isPrefixOf( foundCertificate.getName())) self.assertTrue(certificate3.getName().equals( foundCertificate.getName())) interest3.getExclude().appendComponent(certificate3.getName().get( CertificateV2.ISSUER_ID_OFFSET)) foundCertificate = self.anchorContainer.find(interest3) self.assertTrue(foundCertificate != None) self.assertTrue(interest3.getName().isPrefixOf( foundCertificate.getName())) self.assertTrue( not foundCertificate.getName().equals(certificate3.getName()))
def insert(self, certificate): """ Insert the certificate into the cache. The inserted certificate will be removed no later than its NotAfter time, or maxLifetimeMilliseconds given to the constructor. :param CertificateV2 certificate: The certificate object, which is copied. """ # TODO: Implement certificatesByTime_ to support refresh(). There can be # multiple certificate for the same removalTime, and adding the same # certificate again should update the removalTime. certificateCopy = CertificateV2(certificate) certificateName = certificateCopy.getName() if certificateName in self._certificatesByName: # A duplicate name. Simply replace. self._certificatesByName[certificateName] = certificateCopy else: # Insert into _certificatesByNameKeys sorted. # Keep it sync with _certificatesByName. self._certificatesByName[certificateName] = certificateCopy bisect.insort(self._certificatesByNameKeys, certificateName)
def encodeCertificate(buffer): result = CertificateV2() result.wireDecode(buffer) return result