コード例 #1
0
def bootstrap():
    global trust_anchor, signer
    import_safebag("sec/server.safebag", "1234")
    import_cert("sec/server.ndncert")

    with open("sec/server.safebag", "r") as safebag:
        wire = safebag.read()
        wire = base64.b64decode(wire)
        wire = parse_and_check_tl(wire, SecurityV2TypeNumber.SAFE_BAG)
        bag = SafeBag.parse(wire)
        testbed_signed = CertificateV2Value.parse(bag.certificate_v2)
        server_key_name = Name.to_str(testbed_signed.name[:-2])
        privateKey = serialization.load_der_private_key(
            bytes(bag.encrypted_key_bag),
            password=b'1234',
            backend=default_backend())
        server_prv_key = privateKey.private_bytes(Encoding.DER,
                                                  PrivateFormat.PKCS8,
                                                  NoEncryption())
        signer = Sha256WithEcdsaSigner(server_key_name, server_prv_key)

    with open("sec/testbed.anchor", "r") as ndncert:
        wire = ndncert.read()
        wire = base64.b64decode(wire)
        trust_anchor = parse_certificate(wire)
コード例 #2
0
    def list_key_tree(self):
        """
        Return the id-key-cert tree in a JSON like dict object.
        """
        def get_key_type(key):
            key = bytes(key)
            try:
                RSA.import_key(key)
                return 'RSA'
            except ValueError:
                pass
            try:
                ECC.import_key(key)
                return 'ECC'
            except ValueError:
                pass
            return 'Unknown'

        sig_type_dic = {
            SignatureType.NOT_SIGNED: 'NotSigned',
            SignatureType.DIGEST_SHA256: 'DigestSha256',
            SignatureType.SHA256_WITH_RSA: 'SignatureSha256WithRsa',
            SignatureType.SHA256_WITH_ECDSA: 'SignatureSha256WithEcdsa',
            SignatureType.HMAC_WITH_SHA256: 'SignatureHmacWithSha256'
        }

        pib = self.app.keychain
        ret = {}
        for id_name, id_obj in pib.items():
            cur_id = {'default': '*' if id_obj.is_default else ' ', 'keys': {}}
            for key_name, key_obj in id_obj.items():
                cur_key = {
                    'default': '*' if key_obj.is_default else ' ',
                    'key_type': get_key_type(key_obj.key_bits),
                    'certs': {}
                }
                for cert_name, cert_obj in key_obj.items():
                    cert_v2 = parse_certificate(cert_obj.data)
                    cur_cert = {
                        'default':
                        '*' if cert_obj.is_default else ' ',
                        'not_before':
                        bytes(cert_v2.signature_info.validity_period.not_before
                              ).decode(),
                        'not_after':
                        bytes(cert_v2.signature_info.validity_period.not_after
                              ).decode(),
                        'issuer_id':
                        Component.to_str(cert_v2.name[-2]),
                        'key_locator':
                        Name.to_str(cert_v2.signature_info.key_locator.name),
                        'signature_type':
                        sig_type_dic.get(cert_v2.signature_info.signature_type,
                                         'Unknown')
                    }
                    cur_key['certs'][Name.to_str(cert_name)] = cur_cert
                cur_id['keys'][Name.to_str(key_name)] = cur_key
            ret[Name.to_str(id_name)] = cur_id
        return ret
コード例 #3
0
async def verify_ecdsa_signature(name: FormalName, sig: SignaturePtrs) -> bool:
    global trust_anchor

    logging.debug("Validating certificate %s", Name.to_str(name))
    sig_info = sig.signature_info
    covered_part = sig.signature_covered_part
    sig_value = sig.signature_value_buf
    if not sig_info or sig_info.signature_type != SignatureType.SHA256_WITH_ECDSA:
        return False
    if not covered_part or not sig_value:
        return False
    key_name = sig_info.key_locator.name[0:]
    logging.debug('Extracting key_name: ', Name.to_str(key_name))

    # check it's testbed root
    key_bits = None
    if Name.to_str(key_name) == Name.to_str(trust_anchor.name[:-2]):
        logging.debug('Reaching the trust anchor, begin to return')
        key_bits = bytes(trust_anchor.content)
    else:
        try:
            cert_name, meta_info, content, raw_packet = await app.express_interest(
                key_name,
                must_be_fresh=True,
                can_be_prefix=True,
                lifetime=6000,
                need_raw_packet=True,
                validator=verify_ecdsa_signature)
            # certificate itself is a Data packet
            cert = parse_certificate(raw_packet)
            # load public key from the data content
            key_bits = None
            try:
                key_bits = bytes(content)
            except (KeyError, AttributeError):
                logging.debug('Cannot load pub key from received certificate')
                return False
        except InterestNack as e:
            logging.debug(f'Nacked with reason={e.reason}')
        except InterestTimeout:
            logging.debug(f'Timeout')
        except InterestCanceled:
            logging.debug(f'Canceled')
        except ValidationFailure:
            logging.debug(f'Data failed to validate')
    pk = ECC.import_key(key_bits)
    verifier = DSS.new(pk, 'fips-186-3', 'der')
    sha256_hash = SHA256.new()
    for blk in covered_part:
        sha256_hash.update(blk)
    try:
        verifier.verify(sha256_hash, bytes(sig_value))
    except ValueError:
        logging.debug('Certificate validation failed! %s', Name.to_str(name))
        return False
    logging.debug('Certificate validated! %s', Name.to_str(name))
    return True
コード例 #4
0
    def process_cert_request(self, name, app_param):
        logging.info("[CERT REQ]: interest received")
        logging.info(name)
        if not app_param:
            logging.error("[CERT REQ]: interest has no parameter")
            return
        request = CertRequest.parse(app_param)
        if not request.identifier or not request.ecdh_n2 or not request.anchor_digest or not request.ecdh_n1:
            raise KeyError("[CERT REQ]: lacking parameters in application parameters")
        logging.info(bytes(request.identifier))
        logging.info(bytes(request.ecdh_n2))
        logging.info(bytes(request.anchor_digest))
        logging.info(bytes(request.ecdh_n1))
        if bytes(request.identifier) != self.boot_state['DeviceIdentifier'] or \
                bytes(request.ecdh_n2) != self.boot_state['N2PublicKey'] or \
                bytes(request.anchor_digest) != self.boot_state['TrustAnchorDigest'] or \
                bytes(request.ecdh_n1) != self.boot_state['N1PublicKey']:
            logging.error("[CERT REQ]: unauthenticated request")
            return
        # anchor signed certificate
        # create identity and key for the device
        device_name = self.system_prefix + '/' + bytes(request.identifier).decode()
        device_key = self.app.keychain.touch_identity(device_name).default_key()
        private_key = get_prv_key_from_safe_bag(device_name)
        default_cert = device_key.default_cert().data
        # resign certificate using anchor's key
        cert = parse_certificate(default_cert)
        new_cert_name = cert.name[:-2]
        new_cert_name.append('home')
        new_cert_name.append('001')
        cert = self.app.prepare_data(new_cert_name, cert.content, identity=self.system_prefix)
        # AES
        iv = urandom(16)
        cipher = AES.new(self.boot_state['SharedKey'], AES.MODE_CBC, iv)
        ct_bytes = cipher.encrypt(pad(private_key, AES.block_size))
        logging.info('Symmetic Key')
        logging.info(self.boot_state['SharedKey'])
        # AES IV
        logging.info("IV:")
        logging.info(iv)
        # encrpted device private key with temporary symmetric key
        ct = b64encode(ct_bytes)
        logging.info("Cipher:")
        logging.info(ct)

        response = CertResponse()
        response.cipher = ct
        response.iv = iv
        cert_bytes = parse_and_check_tl(cert, TypeNumber.DATA)
        response.id_cert = cert_bytes

        signer = HmacSha256Signer('pre-shared', self.boot_state['SharedSymmetricKey'])
        self.app.put_data(name, response.encode(), freshness_period=3000, signer=signer)
コード例 #5
0
async def main():
    global local_anchor

    import_safebag("sec/client.safebag", "1234")

    # parse again to read prv key into memory 
    request = CertRequest()
    with open("sec/client.safebag", "r") as safebag:
        wire = safebag.read()
        wire = base64.b64decode(wire)
        wire = parse_and_check_tl(wire, SecurityV2TypeNumber.SAFE_BAG)
        bag = SafeBag.parse(wire)

        # attach the testbed-signed certificate
        request.testbed_signed = bag.certificate_v2

        # parse the key bag to obtain private key
        testbed_signed = CertificateV2Value.parse(bag.certificate_v2)
        key_bag = bytes(bag.encrypted_key_bag)
        privateKey = serialization.load_der_private_key(key_bag, password=b'1234', backend=default_backend())
        client_prv_key = privateKey.private_bytes(Encoding.DER, PrivateFormat.PKCS8, NoEncryption())

    # parse trust anchor and self-assigns a name, then create self-signed certificate
    with open("sec/client.anchor", "r") as anchor:
        wire = anchor.read()
        wire = base64.b64decode(wire)
        local_anchor = parse_certificate(wire)

        # self-assign a name and create corresponding key pair
        client_name = local_anchor.name[:-4] + [testbed_signed.name[-5]]
        client_identity = app.keychain.touch_identity(client_name)

        # attach newly generated self-assigned certificate
        cert = client_identity.default_key().default_cert().data
        cert = parse_certificate(cert)
        request.self_signed = cert.encode()

    try:
        # express the first interest to fetch a token/secret code
        timestamp = ndn.utils.timestamp()
        name = Name.from_str('/edge/_ca/new-cert') + [Component.from_timestamp(timestamp)]
        logging.info(f'Sending Interest {Name.to_str(name)}, {InterestParam(must_be_fresh=True, lifetime=6000)}')
        data_name, meta_info, content = await app.express_interest(
            name, app_param=request.encode(), must_be_fresh=True, can_be_prefix=False, lifetime=6000,
            identity=client_identity, validator=verify_ecdsa_signature)
        
        # sign it use the private key, to prove the certificate possesion
        h = SHA256.new()
        h.update(bytes(content))
        pk = ECC.import_key(client_prv_key)
        signature = DSS.new(pk, 'fips-186-3', 'der').sign(h)
        logging.info(f'Getting Data {Name.to_str(name)}, begin signing the token {bytes(content)}')

        # express the second interest to fetch the issued certificate
        name = Name.from_str('/edge/_ca/challenge') + [Component.from_timestamp(timestamp)]
        logging.info(f'Sending Interest {Name.to_str(name)}, {InterestParam(must_be_fresh=True, lifetime=6000)}')
        data_name, meta_info, content = await app.express_interest(
            name, app_param=signature, must_be_fresh=True, can_be_prefix=False, lifetime=6000, 
            identity=client_identity, validator=verify_ecdsa_signature)

        # parse the issued certificate and install
        issued_cert = parse_certificate(content)
        logging.info("Issued certificate: %s", Name.to_str(issued_cert.name))
        app.keychain.import_cert(Name.to_bytes(issued_cert.name[:-2]), Name.to_bytes(issued_cert.name), bytes(content))

    except InterestNack as e:
        print(f'Nacked with reason={e.reason}')
    except InterestTimeout:
        print(f'Timeout')
    except InterestCanceled:
        print(f'Canceled')
    except ValidationFailure:
        print(f'Data failed to validate')
        app.shutdown()
コード例 #6
0
    def process_cert_request(self, name, app_param):
        logging.info("[CERT REQ]: interest received")
        logging.info(name)
        if not app_param:
            logging.error("[CERT REQ]: interest has no parameter")
            return
        request = CertRequest.parse(app_param)
        if not request.identifier or not request.ecdh_n2 or not request.anchor_digest or not request.ecdh_n1:
            raise KeyError(
                "[CERT REQ]: lacking parameters in application parameters")
        logging.info(bytes(request.identifier))
        logging.info(bytes(request.ecdh_n2))
        logging.info(bytes(request.anchor_digest))
        logging.info(bytes(request.ecdh_n1))
        if bytes(request.identifier) != self.boot_state['DeviceIdentifier'] or \
                bytes(request.ecdh_n2) != self.boot_state['N2PublicKey'] or \
                bytes(request.anchor_digest) != self.boot_state['TrustAnchorDigest'] or \
                bytes(request.ecdh_n1) != self.boot_state['N1PublicKey']:
            logging.error("[CERT REQ]: unauthenticated request")
            return
        # anchor signed certificate
        # create identity and key for the device
        # TODO Remove hardcoded livingroom and ask user for which room the device belongs to
        m_measure_tp1 = time.time()
        device_name = '/' + self.system_prefix + '/livingroom' + '/' + bytes(
            request.identifier).decode()
        device_key = self.app.keychain.touch_identity(
            device_name).default_key()
        private_key = get_prv_key_from_safe_bag(device_name)
        default_cert = device_key.default_cert().data
        m_measure_tp2 = time.time()
        logging.debug(
            F'BOOTSTRAPPING-DATA2-ECDSA-KENGEN: {m_measure_tp2 - m_measure_tp1}'
        )

        # re-sign certificate using anchor's key
        cert = parse_certificate(default_cert)
        new_cert_name = cert.name[:-2]
        logging.debug(new_cert_name)
        new_cert_name.append('home')
        new_cert_name.append(
            Name.Component.from_version(SystemRandom().randint(
                10000000, 99999999)))
        logging.debug(new_cert_name)

        m_measure_tp1 = time.time()
        cert = self.app.prepare_data(new_cert_name,
                                     cert.content,
                                     identity=self.system_prefix)
        m_measure_tp2 = time.time()
        logging.debug(
            F'BOOTSTRAPPING-DATA2-ECDSA-RESIGN: {m_measure_tp2 - m_measure_tp1}'
        )

        m_measure_tp1 = time.time()
        # AES
        iv = urandom(16)
        cipher = AES.new(self.boot_state['SharedAESKey'], AES.MODE_CBC, iv)
        ct_bytes = cipher.encrypt(private_key)
        m_measure_tp2 = time.time()
        logging.debug(
            F'BOOTSTRAPPING-DATA2-AES-ENC: {m_measure_tp2 - m_measure_tp1}')

        logging.info('raw private key')
        logging.info(private_key)
        logging.info('Symmetric Key')
        logging.info(self.boot_state['SharedAESKey'])
        # AES IV
        logging.info("IV:")
        logging.info(iv)
        logging.info("Cipher:")
        logging.info(ct_bytes)
        logging.info('Cipher length: ' + str(len(ct_bytes)))
        # encrypted device private key with temporary symmetric key
        # ct = b64encode(ct_bytes)

        response = CertResponse()
        response.cipher = ct_bytes
        response.iv = iv
        cert_bytes = parse_and_check_tl(cert, TypeNumber.DATA)
        response.id_cert = cert_bytes

        m_measure_tp1 = time.time()
        signer = HmacSha256Signer('pre-shared',
                                  self.boot_state['SharedSymmetricKey'])
        self.app.put_data(name,
                          response.encode(),
                          freshness_period=3000,
                          signer=signer)
        m_measure_tp2 = time.time()
        logging.debug(
            F'BOOTSTRAPPING-DATA2-ECDSA+ENCODING: {m_measure_tp2 - m_measure_tp1}'
        )
        self.boot_state["DeviceIdentityName"] = device_name
        self.boot_state['Success'] = True
        self.boot_event.set()
コード例 #7
0
    def test_signing_suggest():        
        with TemporaryDirectory() as tmpdirname:
            pib_file = os.path.join(tmpdirname, 'pib.db')
            tpm_dir = os.path.join(tmpdirname, 'privKeys')
            KeychainSqlite3.initialize(pib_file, 'tpm-file', tpm_dir)
            keychain = KeychainSqlite3(pib_file, TpmFile(tpm_dir))
            assert len(keychain) == 0

            la_id = keychain.touch_identity('/la')
            la_cert = la_id.default_key().default_cert().data
            la_cert_data = parse_certificate(la_cert)
            la_cert_name = la_cert_data.name
            la_signer = keychain.get_signer({'cert': la_cert_name})

            la_author_id = keychain.touch_identity('/la/author/1')
            la_author_cert_name, la_author_cert = derive_cert(la_author_id.default_key().name, 
                                                              Component.from_str('la-signer'), 
                                                              la_cert_data.content, la_signer, 
                                                              datetime.utcnow(), 100)
            keychain.import_cert(la_id.default_key().name, la_author_cert_name, la_author_cert)

            ny_id = keychain.touch_identity('/ny')
            ny_cert = ny_id.default_key().default_cert().data
            ny_cert_data = parse_certificate(ny_cert)
            ny_cert_name = ny_cert_data.name
            ny_signer = keychain.get_signer({'cert': ny_cert_name})

            ny_author_id = keychain.touch_identity('/ny/author/2')
            ny_author_cert_name, ny_author_cert = derive_cert(ny_author_id.default_key().name, 
                                                              Component.from_str('ny-signer'),
                                                              ny_cert_data.content, ny_signer, 
                                                              datetime.utcnow(), 100)
            keychain.import_cert(ny_id.default_key().name, ny_author_cert_name, ny_author_cert)


            lvs = r'''
            #KEY: "KEY"/_/_/_
            #article: /"article"/_topic/_ & { _topic: "eco" | "spo" } <= #author
            #author: /site/"author"/_/#KEY <= #anchor
            #anchor: /site/#KEY & {site: "la" | "ny" }
            '''
            checker = Checker(compile_lvs(lvs), {})

            assert checker.suggest("/article/eco/day1", keychain) == la_author_cert_name
            assert checker.suggest("/article/life/day1", keychain) is None
            
            lvs = r'''
            #KEY: "KEY"/_/_/_
            #LAKEY: "KEY"/_/_signer/_ & { _signer: "la-signer" }
            #article: /"article"/_topic/_ & { _topic: "eco" | "spo" } <= #author
            #author: /site/"author"/_/#LAKEY <= #anchor
            #anchor: /site/#KEY & {site: "la"}
            '''
            checker = Checker(compile_lvs(lvs), {})
            assert checker.suggest("/article/eco/day1", keychain) == la_author_cert_name
            
            lvs = r'''
            #KEY: "KEY"/_/_/_version & { _version: $eq_type("v=0") }
            #article: /"article"/_topic/_ & { _topic: "life" | "fin" } <= #author
            #author: /site/"author"/_/#KEY & { site: "ny" } <= #anchor
            #anchor: /site/#KEY & { site: "ny" }
            '''
            checker = Checker(compile_lvs(lvs), DEFAULT_USER_FNS)
            assert checker.suggest("/article/fin/day1", keychain) == ny_author_cert_name
            
            lvs = r'''
            #KEY: "KEY"/_/_/_version & { _version: $eq_type("v=0") }
            #NYKEY: "KEY"/_/_signer/_version& { _signer: "ny-signer", _version: $eq_type("v=0")}
            #article: /"article"/_topic/_ <= #author
            #author: /site/"author"/_/#NYKEY <= #anchor
            #anchor: /site/#KEY & {site: "ny"}
            #site: "ny"
            '''
            checker = Checker(compile_lvs(lvs), DEFAULT_USER_FNS)
            assert checker.suggest("/article/eco/day1", keychain) == ny_author_cert_name