예제 #1
0
    def getCertificate(self, certificateName, allowAny = False):    
        """
        Get a certificate from the identity storage.
        
        :param Name certificateName: The name of the requested certificate.
        :param bool allowAny: (optional) If False, only a valid certificate will 
          be returned, otherwise validity is disregarded.  If omitted, 
          allowAny is False.
        :return: The requested certificate. If not found, return None.
        :rtype: Data
        """
        chosenCert = None
        certificateUri = certificateName.toUri()
        cursor = self._database.cursor()

        #if not allowAny:
        #    validityClause = " AND valid_flag=1"
        #else:
        validityClause = ""

        # use LIKE because key locators chop off timestamps
        # need to escape any percent signs in the certificate uri for sql's
        # sake, but still append % for LIKE
        escapedUri = certificateUri.replace('%', '\\%')
        full_statement = "SELECT certificate_data FROM Certificate WHERE cert_name LIKE ?"+validityClause+" ESCAPE '\\' ORDER BY cert_name DESC"
        #full_statement = "SELECT certificate_data FROM Certificate WHERE cert_name=?"+validityClause
        cursor.execute(full_statement, (escapedUri+'%', ))
        try:
            (certData, ) = cursor.fetchone()
        except TypeError:
            pass
        else:
            chosenCert = IdentityCertificate()
            chosenCert.wireDecode(bytearray(certData))
        return chosenCert 
예제 #2
0
    def _generateCertificateForKey(self, keyName):
        # Let any raised SecurityExceptions bubble up.
        publicKeyBits = self._identityStorage.getKey(keyName)

        publicKey = PublicKey(publicKeyBits)

        timestamp = Common.getNowMilliseconds()

        # TODO: Specify where the 'KEY' component is inserted
        # to delegate responsibility for cert delivery.
        # cf: http://redmine.named-data.net/issues/1659
        certificateName = keyName.getPrefix(-1).append('KEY').append(
            keyName.get(-1))
        certificateName.append("ID-CERT").appendVersion(int(timestamp))

        certificate = IdentityCertificate()
        certificate.setName(certificateName)

        certificate.setNotBefore(timestamp)
        certificate.setNotAfter(
            (timestamp + 2 * 365 * 24 * 3600 * 1000))  # about 2 years.

        certificate.setPublicKeyInfo(publicKey)

        # ndnsec likes to put the key name in a subject description.
        sd = CertificateSubjectDescription("2.5.4.41", keyName.toUri())
        certificate.addSubjectDescription(sd)

        certificate.encode()

        return certificate
예제 #3
0
    def test_prepare_unsigned_certificate(self):
        identityStorage = MemoryIdentityStorage()
        privateKeyStorage = MemoryPrivateKeyStorage()
        identityManager = IdentityManager(identityStorage, privateKeyStorage)
        keyName = Name("/test/ksk-1457560485494")
        identityStorage.addKey(keyName, KeyType.RSA, Blob(PUBLIC_KEY))

        subjectDescriptions = []
        subjectDescriptions.append(
            CertificateSubjectDescription(TEST_OID, "TEST NAME"))
        newCertificate = identityManager.prepareUnsignedIdentityCertificate(
            keyName, keyName.getPrefix(1), self.toyCertNotBefore,
            self.toyCertNotAfter, subjectDescriptions)

        # Update the generated certificate version to equal the one in toyCert.
        newCertificate.setName(
            Name(newCertificate.getName().getPrefix(-1).append(
                self.toyCert.getName().get(-1))))

        # Make a copy to test encoding.
        certificateCopy = IdentityCertificate(newCertificate)
        self.assertEqual(
            str(self.toyCert), str(certificateCopy),
            "Prepared unsigned certificate dump does not have the expected format"
        )
예제 #4
0
    def generateCertificateForKey(self, keyName):
        # let any raised SecurityExceptions bubble up
        publicKeyBits = self._identityStorage.getKey(keyName)
        publicKeyType = self._identityStorage.getKeyType(keyName)

        publicKey = PublicKey(publicKeyType, publicKeyBits)

        timestamp = Common.getNowMilliseconds()

        # TODO: specify where the 'KEY' component is inserted
        # to delegate responsibility for cert delivery
        certificateName = keyName.getPrefix(-1).append('KEY').append(
            keyName.get(-1))
        certificateName.append("ID-CERT").append(
            Name.Component(struct.pack(">Q", timestamp)))

        certificate = IdentityCertificate(certificateName)

        certificate.setNotBefore(timestamp)
        certificate.setNotAfter(
            (timestamp + 30 * 86400 * 1000))  # about a month

        certificate.setPublicKeyInfo(publicKey)

        # ndnsec likes to put the key name in a subject description
        sd = CertificateSubjectDescription("2.5.4.41", keyName.toUri())
        certificate.addSubjectDescription(sd)

        certificate.encode()

        return certificate
예제 #5
0
    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)

        # 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

        with open(self.testCertFile, 'w') as certFile:
            cert = IdentityCertificate()
            certData = b64decode(CERT_DUMP)
            cert.wireDecode(Blob(certData, False))
            self.keyChain.signByIdentity(cert, self.identityName)
            encodedCert = b64encode(cert.wireEncode().toBytes())
            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")
예제 #6
0
    def test_create_d_key_data(self):
        # Create the group manager.
        manager = GroupManager(
            Name("Alice"), Name("data_type"),
            Sqlite3GroupManagerDb(self.dKeyDatabaseFilePath), 2048, 1,
            self.keyChain)

        newCertificateBlob = self.certificate.wireEncode()
        newCertificate = IdentityCertificate()
        newCertificate.wireDecode(newCertificateBlob)

        # Encrypt the D-KEY.
        data = manager._createDKeyData(
            "20150825T000000", "20150827T000000", Name("/ndn/memberA/KEY"),
            self.decryptKeyBlob,
            newCertificate.getPublicKeyInfo().getKeyDer())

        # Verify the encrypted D-KEY.
        dataContent = data.getContent()

        # Get the nonce key.
        # dataContent is a sequence of the two EncryptedContent.
        encryptedNonce = EncryptedContent()
        encryptedNonce.wireDecode(dataContent)
        self.assertEqual(0, encryptedNonce.getInitialVector().size())
        self.assertEqual(EncryptAlgorithmType.RsaOaep,
                         encryptedNonce.getAlgorithmType())

        blobNonce = encryptedNonce.getPayload()
        decryptParams = EncryptParams(EncryptAlgorithmType.RsaOaep)
        nonce = RsaAlgorithm.decrypt(self.decryptKeyBlob, blobNonce,
                                     decryptParams)

        # Get the D-KEY.
        # Use the size of encryptedNonce to find the start of encryptedPayload.
        payloadContent = dataContent.buf()[encryptedNonce.wireEncode().size():]
        encryptedPayload = EncryptedContent()
        encryptedPayload.wireDecode(payloadContent)
        self.assertEqual(16, encryptedPayload.getInitialVector().size())
        self.assertEqual(EncryptAlgorithmType.AesCbc,
                         encryptedPayload.getAlgorithmType())

        decryptParams.setAlgorithmType(EncryptAlgorithmType.AesCbc)
        decryptParams.setInitialVector(encryptedPayload.getInitialVector())
        blobPayload = encryptedPayload.getPayload()
        largePayload = AesAlgorithm.decrypt(nonce, blobPayload, decryptParams)

        self.assertTrue(largePayload.equals(self.decryptKeyBlob))
예제 #7
0
    def getCertificate(self, certificateName, allowAny=False):
        """
        Get a certificate from the identity storage.

        :param Name certificateName: The name of the requested certificate.
        :param bool allowAny: (optional) If False, only a valid certificate will
          be returned, otherwise validity is disregarded.  If omitted,
          allowAny is False.
        :return: The requested certificate. If not found, return None.
        :rtype: IdentityCertificate
        """
        certificateNameUri = certificateName.toUri()
        if not (certificateNameUri in self._certificateStore):
            # Not found.  Silently return None.
            return None

        certificate = IdentityCertificate()
        certificate.wireDecode(self._certificateStore[certificateNameUri])
        return certificate
예제 #8
0
            def onRootCertificateDownload(interest, data):
                try:
                    # zhehao: the root cert is downloaded and installed without verifying; should the root cert be preconfigured?
                    # Insert root certificate so that we can verify newCert
                    self._policyManager._certificateCache.insertCertificate(
                        data)

                    # Set the root cert as default for root identity
                    try:
                        self._identityManager.addCertificateAsIdentityDefault(
                            IdentityCertificate(data))
                    except SecurityException as e:
                        print(
                            "Error when addCertificateAsIdentityDefault for root: "
                            + data.getName().toUri())
                        print(str(e))

                    self._rootCertificate = data
                    try:
                        # use the default configuration where possible
                        # TODO: use environment variable for this, fall back to default
                        fileName = os.path.expanduser('~/.ndn/.iot.root.cert')
                        rootCertFile = open(fileName, "w")
                        rootCertFile.write(
                            Blob(
                                b64encode(self._rootCertificate.wireEncode().
                                          toBytes()), False).toRawStr())
                        rootCertFile.close()
                    except IOError as e:
                        self.log.error(
                            "Cannot write to root certificate file: " +
                            rootCertFile)
                        print "Cannot write to root certificate file: " + rootCertFile

                except SecurityException as e:
                    print(str(e))
                    # already exists, or got certificate in wrong format
                    pass
                self._keyChain.verifyData(newCert,
                                          self._finalizeCertificateDownload,
                                          self._certificateValidationFailed)
예제 #9
0
    def _processValidCertificate(self, data):
        # unpack the cert from the HMAC signed packet and verify
        try:
            newCert = IdentityCertificate()
            newCert.wireDecode(data.getContent())
            self.log.info("Received certificate from controller")
            self.log.debug(str(newCert))

            # NOTE: we download and install the root certificate without verifying it (!)
            # otherwise our policy manager will reject it.
            # we may need a static method on KeyChain to allow verifying before adding

            rootCertName = newCert.getSignature().getKeyLocator().getKeyName()
            # update trust rules so we trust the controller
            self._policyManager.setDeviceIdentity(self._configureIdentity)
            self._policyManager.updateTrustRules()

            def onRootCertificateDownload(interest, data):
                try:
                    self._identityStorage.addCertificate(data)
                except SecurityException:
                    # already exists
                    pass
                self._keyChain.verifyData(newCert,
                                          self._finalizeCertificateDownload,
                                          self._certificateValidationFailed)

            def onRootCertificateTimeout(interest):
                # TODO: limit number of tries, then revert trust root + network prefix
                # reset salt, create new Hmac key
                self.face.expressInterest(rootCertName,
                                          onRootCertificateDownload,
                                          onRootCertificateTimeout)

            self.face.expressInterest(rootCertName, onRootCertificateDownload,
                                      onRootCertificateTimeout)

        except Exception as e:
            self.log.exception("Could not import new certificate",
                               exc_info=True)
예제 #10
0
    def addCertificate(self, certificate):    
        """
        Add a certificate to the identity storage.
        
        :param IdentityCertificate certificate: The certificate to be added. 
          This makes a copy of the certificate.
        """
        #TODO: actually check validity of certificate timestamp
        certificateName = certificate.getName()
        
        if self.doesCertificateExist(certificateName):
            raise SecurityException("Certificate has already been installed!")

        certCopy = IdentityCertificate(certificate)
        makeDefault = 0
        keyName = certCopy.getPublicKeyName()
        keyInfo = certCopy.getPublicKeyInfo()
        if not self.doesKeyExist(keyName):
            self.addKey(keyName, keyInfo.getKeyType(), keyInfo.getKeyDer())
            makeDefault = 1
        else:
            # see if the key we already have matches this certificate
            keyBlob = self.getKey(keyName)
            if (keyBlob.isNull() or keyBlob.toBuffer() != 
                    keyInfo.getKeyDer().toBuffer()):
                raise SecurityException("Certificate does not match public key")

        keyId = keyName.get(-1).toEscapedString()
        identityUri = keyName.getPrefix(-1).toUri()
        certIssuer = certCopy.getSignature().getKeyLocator().getKeyName().toUri()
        encodedCert = buffer(bytearray(certCopy.wireEncode().buf()))
        notBefore = certCopy.getNotBefore()
        notAfter = certCopy.getNotAfter()
        cursor = self._database.cursor()
        cursor.execute("INSERT INTO Certificate VALUES(?,?,?,?,?,?,?,?,?)",
            (certificateName.toUri(), certIssuer, identityUri, keyId,
                notBefore, notAfter, encodedCert, 1, makeDefault))
        self._database.commit()
        cursor.close()
예제 #11
0
    def getCertificate(self, certificateName):
        """
        Get a certificate from the identity storage.

        :param Name certificateName: The name of the requested certificate.
        :return: The requested certificate.
        :rtype: IdentityCertificate
        :raises SecurityException: if the certificate doesn't exist.
        """
        certificateNameUri = certificateName.toUri()
        if not (certificateNameUri in self._certificateStore):
            raise SecurityException(
                "MemoryIdentityStorage.getCertificate: The certificate does not exist"
            )

        certificate = IdentityCertificate()
        try:
            certificate.wireDecode(self._certificateStore[certificateNameUri])
        except ValueError:
            raise SecurityException(
                "MemoryIdentityStorage.getCertificate: The certificate cannot be decoded"
            )

        return certificate
예제 #12
0
    def setUp(self):
        # Reuse the policy_config subdirectory for the temporary SQLite files.
        self.dKeyDatabaseFilePath = "policy_config/manager-d-key-test.db"
        try:
            os.remove(self.dKeyDatabaseFilePath)
        except OSError:
            # no such file
            pass

        self.eKeyDatabaseFilePath = "policy_config/manager-e-key-test.db"
        try:
            os.remove(self.eKeyDatabaseFilePath)
        except OSError:
            # no such file
            pass

        self.intervalDatabaseFilePath = "policy_config/manager-interval-test.db"
        try:
            os.remove(self.intervalDatabaseFilePath)
        except OSError:
            # no such file
            pass

        self.groupKeyDatabaseFilePath = "policy_config/manager-group-key-test.db"
        try:
            os.remove(self.groupKeyDatabaseFilePath)
        except OSError:
            # no such file
            pass

        params = RsaKeyParams()
        memberDecryptKey = RsaAlgorithm.generateKey(params)
        self.decryptKeyBlob = memberDecryptKey.getKeyBits()
        memberEncryptKey = RsaAlgorithm.deriveEncryptKey(self.decryptKeyBlob)
        self.encryptKeyBlob = memberEncryptKey.getKeyBits()

        # Generate the certificate.
        self.certificate = IdentityCertificate()
        self.certificate.setName(Name("/ndn/memberA/KEY/ksk-123/ID-CERT/123"))
        contentPublicKey = PublicKey(self.encryptKeyBlob)
        self.certificate.setPublicKeyInfo(contentPublicKey)
        self.certificate.setNotBefore(0)
        self.certificate.setNotAfter(0)
        self.certificate.encode()

        signatureInfoBlob = Blob(SIG_INFO, False)
        signatureValueBlob = Blob(SIG_VALUE, False)

        signature = TlvWireFormat.get().decodeSignatureInfoAndValue(
            signatureInfoBlob.buf(), signatureValueBlob.buf())
        self.certificate.setSignature(signature)

        self.certificate.wireEncode()

        # Set up the keyChain.
        identityStorage = MemoryIdentityStorage()
        privateKeyStorage = MemoryPrivateKeyStorage()
        self.keyChain = KeyChain(
            IdentityManager(identityStorage, privateKeyStorage),
            NoVerifyPolicyManager())
        identityName = Name("TestGroupManager")
        self.keyChain.createIdentityAndCertificate(identityName)
        self.keyChain.getIdentityManager().setDefaultIdentity(identityName)
예제 #13
0
    def prepareUnsignedIdentityCertificate(self,
                                           keyName,
                                           publicKey,
                                           signingIdentity,
                                           notBefore,
                                           notAfter,
                                           subjectDescription=None,
                                           certPrefix=None):
        """
        Prepare an unsigned identity certificate.

        :param Name keyName: The key name, e.g., `/{identity_name}/ksk-123456`.
        :param PublicKey publicKey: (optional) The public key to sign. If
          ommited, use the keyName to get the public key from the identity
          storage.
        :param Name signingIdentity: The signing identity.
        :param float notBefore: See IdentityCertificate.
        :param float notAfter: See IdentityCertificate.
        :param Array<CertificateSubjectDescription> subjectDescription: A list
          of CertificateSubjectDescription. See IdentityCertificate. If None or
          empty, this adds a an ATTRIBUTE_NAME based on the keyName.
        :param Name certPrefix: (optional) The prefix before the `KEY`
          component. If None, this infers the certificate name according to the
          relation between the signingIdentity and the subject identity. If the
          signingIdentity is a prefix of the subject identity, `KEY` will be
          inserted after the signingIdentity, otherwise `KEY` is inserted after
          subject identity (i.e., before `ksk-...`).
        :return: The unsigned IdentityCertificate, or None if the inputs are
          invalid.
        :rtype: IdentityCertificate
        """
        if not isinstance(publicKey, PublicKey):
            # The publicKey was omitted. Shift arguments.
            certPrefix = subjectDescription
            subjectDescription = notAfter
            notAfter = notBefore
            notBefore = signingIdentity
            signingIdentity = publicKey

            publicKey = PublicKey(self._identityStorage.getKey(keyName))

        if keyName.size() < 1:
            return None

        tempKeyIdPrefix = keyName.get(-1).toEscapedString()
        if len(tempKeyIdPrefix) < 4:
            return None
        keyIdPrefix = tempKeyIdPrefix[0:4]
        if keyIdPrefix != "ksk-" and keyIdPrefix != "dsk-":
            return None

        certificate = IdentityCertificate()
        certName = Name()

        if certPrefix == None:
            # No certificate prefix hint, so infer the prefix.
            if signingIdentity.match(keyName):
                certName.append(signingIdentity) \
                    .append("KEY") \
                    .append(keyName.getSubName(signingIdentity.size())) \
                    .append("ID-CERT") \
                    .appendVersion(int(Common.getNowMilliseconds()))
            else:
                certName.append(keyName.getPrefix(-1)) \
                    .append("KEY") \
                    .append(keyName.get(-1)) \
                    .append("ID-CERT") \
                    .appendVersion(int(Common.getNowMilliseconds()))
        else:
            # A cert prefix hint is supplied, so determine the cert name.
            if certPrefix.match(keyName) and not certPrefix.equals(keyName):
                certName.append(certPrefix) \
                    .append("KEY") \
                    .append(keyName.getSubName(certPrefix.size())) \
                    .append("ID-CERT") \
                    .appendVersion(int(Common.getNowMilliseconds()))
            else:
                return None

        certificate.setName(certName)
        certificate.setNotBefore(notBefore)
        certificate.setNotAfter(notAfter)
        certificate.setPublicKeyInfo(publicKey)

        if subjectDescription == None or len(subjectDescription) == 0:
            certificate.addSubjectDescription(
                CertificateSubjectDescription("2.5.4.41",
                                              keyName.getPrefix(-1).toUri()))
        else:
            for i in range(len(subjectDescription)):
                certificate.addSubjectDescription(subjectDescription[i])

        try:
            certificate.encode()
        except Exception as ex:
            raise SecurityException("DerEncodingException: " + str(ex))

        return certificate
예제 #14
0
    def _processValidCertificate(self, data):
        # unpack the cert from the HMAC signed packet and verify
        try:
            newCert = IdentityCertificate()
            newCert.wireDecode(data.getContent())
            self.log.info("Received certificate from controller")

            # NOTE: we download and install the root certificate without verifying it (!)
            # otherwise our policy manager will reject it.
            # we may need a static method on KeyChain to allow verifying before adding

            rootCertName = newCert.getSignature().getKeyLocator().getKeyName()
            # update trust rules so we trust the controller
            self._policyManager.setDeviceIdentity(self._configureIdentity)
            self._policyManager.updateTrustRules()

            def onRootCertificateDownload(interest, data):
                try:
                    # zhehao: the root cert is downloaded and installed without verifying; should the root cert be preconfigured?
                    # Insert root certificate so that we can verify newCert
                    self._policyManager._certificateCache.insertCertificate(
                        data)

                    # Set the root cert as default for root identity
                    try:
                        self._identityManager.addCertificateAsIdentityDefault(
                            IdentityCertificate(data))
                    except SecurityException as e:
                        print(
                            "Error when addCertificateAsIdentityDefault for root: "
                            + data.getName().toUri())
                        print(str(e))

                    self._rootCertificate = data
                    try:
                        # use the default configuration where possible
                        # TODO: use environment variable for this, fall back to default
                        fileName = os.path.expanduser('~/.ndn/.iot.root.cert')
                        rootCertFile = open(fileName, "w")
                        rootCertFile.write(
                            Blob(
                                b64encode(self._rootCertificate.wireEncode().
                                          toBytes()), False).toRawStr())
                        rootCertFile.close()
                    except IOError as e:
                        self.log.error(
                            "Cannot write to root certificate file: " +
                            rootCertFile)
                        print "Cannot write to root certificate file: " + rootCertFile

                except SecurityException as e:
                    print(str(e))
                    # already exists, or got certificate in wrong format
                    pass
                self._keyChain.verifyData(newCert,
                                          self._finalizeCertificateDownload,
                                          self._certificateValidationFailed)

            def onRootCertificateTimeout(interest):
                # TODO: limit number of tries, then revert trust root + network prefix
                # reset salt, create new Hmac key
                self.face.expressInterest(rootCertName,
                                          onRootCertificateDownload,
                                          onRootCertificateTimeout)

            self.face.expressInterest(rootCertName, onRootCertificateDownload,
                                      onRootCertificateTimeout)

        except Exception as e:
            self.log.exception("Could not import new certificate",
                               exc_info=True)