def main() -> None: """Main function.""" # Set the folder for data (certificates, keys) data_dir = path.join(path.dirname(__file__), 'data') os.makedirs(data_dir, exist_ok=True) # load private key from data folder private_key_2048_ca = load_private_key(path.join(data_dir, "ca_privatekey_rsa2048.pem")) assert isinstance(private_key_2048_ca, RSAPrivateKey) # load associated public key public_key_2048_ca = load_public_key(path.join(data_dir, "ca_publickey_rsa2048.pem")) assert isinstance(public_key_2048_ca, RSAPublicKey) subject = issuer = generate_name_struct("first", "CZ") # generate CA certificate (self-signed certificate) ca_cert = generate_certificate(subject=subject, issuer=issuer, subject_public_key=public_key_2048_ca, issuer_private_key=private_key_2048_ca, serial_number=0x1, if_ca=True, duration=20 * 365, path_length=5) # Save certificates in two formats (pem and der) save_crypto_item(ca_cert, path.join(data_dir, "ca_cert_pem.crt")) save_crypto_item(ca_cert, path.join(data_dir, "ca_cert_der.crt"), encoding_type=Encoding.DER) print("The CA Certificate was created in der and pem format.") # Create first chain certificate signed by private key of the CA certificate subject_crt1 = generate_name_struct("second", "CZ") public_key_2048_subject = load_public_key(path.join(data_dir, "crt_publickey_rsa2048.pem")) assert isinstance(public_key_2048_subject, RSAPublicKey) crt1 = generate_certificate(subject=subject_crt1, issuer=issuer, subject_public_key=public_key_2048_subject, issuer_private_key=private_key_2048_ca, serial_number=0x3cc30000babadeda, if_ca=False, duration=20 * 365) # Save certificates in two formats (pem and der) save_crypto_item(crt1, path.join(data_dir, "crt_pem.crt")) save_crypto_item(crt1, path.join(data_dir, "crt_der.crt"), encoding_type=Encoding.DER) print("The first chain certificate (signed by CA certificate) was created in der and pem format.") # First chain certificate signed by private key of the CA certificate subject_crt2 = generate_name_struct("third", "CZ") private_key_2048_subject_1 = load_private_key(path.join(data_dir, "chain_privatekey_rsa2048.pem")) assert isinstance(private_key_2048_subject_1, RSAPrivateKey) public_key_2048_subject_1 = load_public_key(path.join(data_dir, "chain_publickey_rsa2048.pem")) assert isinstance(public_key_2048_subject_1, RSAPublicKey) crt1 = generate_certificate(subject=subject_crt2, issuer=issuer, subject_public_key=public_key_2048_subject_1, issuer_private_key=private_key_2048_ca, serial_number=0x2, if_ca=True, duration=20 * 365, path_length=3) # Save certificates in two formats (pem and der) save_crypto_item(crt1, path.join(data_dir, "chain_crt_pem.crt")) save_crypto_item(crt1, path.join(data_dir, "chain_crt_der.crt"), encoding_type=Encoding.DER) print("The first chain certificate (signed by CA certificate) was created in der and pem format.") # Create first chain certificate signed by private key of first certificate subject_crt3 = generate_name_struct("fourth", "CZ") issuer_crt3 = subject_crt2 public_key_2048_subject_2 = load_public_key(path.join(data_dir, "chain_crt2_publickey_rsa2048.pem")) assert isinstance(public_key_2048_subject_2, RSAPublicKey) crt1 = generate_certificate(subject=subject_crt3, issuer=issuer_crt3, subject_public_key=public_key_2048_subject_2, issuer_private_key=private_key_2048_subject_1, serial_number=0x3cc30000babadeda, if_ca=False, duration=20 * 365) # Save certificates in two formats (pem and der) save_crypto_item(crt1, path.join(data_dir, "chain_crt2_pem.crt")) save_crypto_item(crt1, path.join(data_dir, "chain_crt2_der.crt"), encoding_type=Encoding.DER) print("The second certificate in a chain was created in der and pem format.")
def generate(config: TextIO, output: BinaryIO, encoding: str, force: bool) -> None: """Generate certificate.""" logger.info("Generating Certificate...") logger.info("Loading configuration from yml file...") check_destination_dir(output.name, force) check_file_exists(output.name, force) config_data = load_configuration(config.name) cert_config = CertificateParametersConfig(config_data) priv_key = load_private_key(cert_config.issuer_private_key) pub_key = load_public_key(cert_config.subject_public_key) certificate = generate_certificate( subject=cert_config.subject_name, issuer=cert_config.issuer_name, subject_public_key=pub_key, issuer_private_key=priv_key, serial_number=cert_config.serial_number, duration=cert_config.duration, if_ca=cert_config.BasicConstrains_ca, path_length=cert_config.BasicConstrains_path_length, ) logger.info("Saving the generated certificate to the specified path...") encoding_type = Encoding.PEM if encoding.lower() == "pem" else Encoding.DER save_crypto_item(certificate, output.name, encoding_type=encoding_type) logger.info("Certificate generated successfully...") click.echo( f"The certificate file has been created: {os.path.abspath(output.name)}" )
def _get_dck(dck_key_path: str) -> bytes: """Loads the Debugger Public Key (DCK). :return: binary representing the DCK key """ dck_key = crypto.load_public_key(file_path=dck_key_path) assert isinstance(dck_key, crypto.RSAPublicKey) return rsa_key_to_bytes(key=dck_key, exp_length=4)
def _get_dck(dck_key_path: str) -> bytes: """Loads the Debugger Public Key (DCK). :return: binary representing the DCK key """ dck_key = crypto.load_public_key(file_path=dck_key_path) assert isinstance(dck_key, crypto.EllipticCurvePublicKey) return ecc_key_to_bytes(key=dck_key, length=66)
def _get_rot_pub(rot_pub_id: int, rot_pub_keys: List[str]) -> bytes: """Loads the vendor RoT Public key that corresponds to the private key used for singing. :return: binary representing the rotk public key """ root_key = rot_pub_keys[rot_pub_id] root_public_key = crypto.load_public_key(root_key) length = root_public_key.key_size // 8 assert isinstance(root_public_key, crypto.EllipticCurvePublicKey) data = ecc_key_to_bytes(root_public_key, length=length) return data
def _extract_public_key(file_path: str, password: Optional[str]) -> crypto.RSAPublicKey: cert_candidate = crypto.load_certificate(file_path) if cert_candidate: return cert_candidate.public_key() private_candidate = crypto.load_private_key(file_path, password.encode() if password else None) if private_candidate: return private_candidate.public_key() public_candidate = crypto.load_public_key(file_path) if public_candidate: return public_candidate assert False, f"Unable to load secret file '{file_path}'."
def _get_rot_pub(rot_pub_id: int, rot_pub_keys: List[str]) -> bytes: """Loads the vendor RoT private key. It corresponds to the (default) position zero RoT key in the rot_meta list of public keys. Derive public key from RoT private keys and converts it to the bytes. :return: binary representing the rotk public key """ pub_key_path = rot_pub_keys[rot_pub_id] pub_key = crypto.load_public_key(pub_key_path) assert isinstance(pub_key, crypto.RSAPublicKey) return rsa_key_to_bytes(key=pub_key, exp_length=4)
def create_ctrk_table(rot_pub_keys: List[str]) -> bytes: """Creates ctrk table.""" if len(rot_pub_keys) == 1: return bytes() ctrk_table = bytes() for pub_key_path in rot_pub_keys: pub_key = crypto.load_public_key(pub_key_path) assert isinstance(pub_key, crypto.EllipticCurvePublicKey) key_length = pub_key.key_size data = ecc_key_to_bytes(key=pub_key, length=key_length // 8) ctrk_hash = internal_backend.hash(data=data, algorithm=f'sha{key_length}') ctrk_table += ctrk_hash return ctrk_table
def _get_rot_meta(used_root_cert: int, rot_pub_keys: List[str]) -> bytes: """Creates the RoT meta-data required by the device to corroborate. The meta-data is created by getting the public numbers (modulus and exponent) from each of the RoT public keys, hashing them and combing together. :return: binary representing the rot-meta data """ rot_meta = bytearray(528) for index, rot_key in enumerate(rot_pub_keys): rot = crypto.load_public_key(file_path=rot_key) assert isinstance(rot, crypto.EllipticCurvePublicKey) data = ecc_key_to_bytes(key=rot, length=66) rot_meta[index * 132:(index + 1) * 132] = data return bytes(rot_meta)
def _get_rot_meta(used_root_cert: int, rot_pub_keys: List[str]) -> bytes: """Creates the RoT meta-data required by the device to corroborate. The meta-data is created by getting the public numbers (modulus and exponent) from each of the RoT public keys, hashing them and combing together. :return: binary representing the rot-meta data """ rot_meta = bytearray(128) for index, rot_key in enumerate(rot_pub_keys): rot = crypto.load_public_key(file_path=rot_key) assert isinstance(rot, crypto.RSAPublicKey) data = rsa_key_to_bytes(key=rot, exp_length=3, modulus_length=None) result = internal_backend.hash(data) rot_meta[index * 32:(index + 1) * 32] = result return bytes(rot_meta)
def _get_rot_pub(rot_pub_id: int, rot_pub_keys: List[str]) -> bytes: """Creates RoTKey_Pub (2 element 16-bit array (little endian). CTRKtable index (RoT meta-data) of the public key used by the vendor to sign the DC. Curve identifier: - Secp256r1: 0x0001 - Secp384r1: 0x0002 - Secp521r1: 0x0003 :return: binary representation """ pub_key_path = rot_pub_keys[rot_pub_id] pub_key = crypto.load_public_key(pub_key_path) assert isinstance(pub_key, crypto.EllipticCurvePublicKey) curve_index = {256: 1, 386: 2, 521: 3}[pub_key.curve.key_size] return pack('<2H', rot_pub_id, curve_index)
def test_generate_rsa_key(tmpdir) -> None: """Test generate rsa key pair.""" cmd = f'genkey {os.path.join(tmpdir, "key_rsa.pem")}' runner = CliRunner() result = runner.invoke(main, cmd.split()) assert result.exit_code == 0 assert os.path.isfile(os.path.join(tmpdir, "key_rsa.pem")) assert os.path.isfile(os.path.join(tmpdir, "key_rsa.pub")) pub_key_from_file = load_public_key(os.path.join(tmpdir, "key_rsa.pub")) assert isinstance(pub_key_from_file, RSAPublicKey) assert pub_key_from_file.key_size == 2048 priv_key_from_file = load_private_key(os.path.join(tmpdir, "key_rsa.pem")) assert isinstance(priv_key_from_file, RSAPrivateKey) assert priv_key_from_file.key_size == 2048
def test_generate_ecc_key(tmpdir, protocol_version, curve_name) -> None: """Test generate ecc key pair.""" pem_path = os.path.join(tmpdir, f'{curve_name}_key_ecc.pem') pub_path = os.path.join(tmpdir, f'{curve_name}_key_ecc.pub') cmd = f'-p {protocol_version} genkey {pem_path}' runner = CliRunner() result = runner.invoke(main, cmd.split()) assert result.exit_code == 0 assert os.path.isfile(pem_path) assert os.path.isfile(pub_path) pub_key_from_file = load_public_key(pub_path) assert isinstance(pub_key_from_file, EllipticCurvePublicKey) assert pub_key_from_file.curve.name == curve_name priv_key_from_file = load_private_key(pem_path) assert isinstance(priv_key_from_file, EllipticCurvePrivateKey) assert pub_key_from_file.curve.name == curve_name
def main() -> None: """Main function.""" # Set the folder for data (certificates, keys) data_dir = path.join(path.dirname(__file__), "data") os.makedirs(data_dir, exist_ok=True) # Load public key of CA certificate ca0_pubkey_rsa2048 = load_public_key( path.join(data_dir, "ca_publickey_rsa2048.pem")) # Load CA certificate ca0_cert = load_certificate(path.join(data_dir, "ca_cert_pem.crt")) # Obtain public key from CA certificate pubkey_from_ca0_cert = get_public_key_from_certificate(ca0_cert) # Check if public key of certificate has proper format assert isinstance(pubkey_from_ca0_cert, RSAPublicKey) # Compare CA's public key from file and the one from certificate if ca0_pubkey_rsa2048.public_numbers( ) != pubkey_from_ca0_cert.public_numbers(): raise SPSDKError( "Keys are not the same (the one from disc and the one from cert)") # Load certificate, which is singed by CA crt = load_certificate(path.join(data_dir, "crt_pem.crt")) if not validate_certificate(crt, ca0_cert): raise SPSDKError("The certificate is not valid") print("The certificate was signed by the CA.") # Load chain of certificate chain = ["chain_crt2_pem.crt", "chain_crt_pem.crt", "ca_cert_pem.crt"] chain_cert = [ load_certificate(path.join(data_dir, cert_name)) for cert_name in chain ] ch3_crt2 = load_certificate(path.join(data_dir, "chain_crt2_pem.crt")) ch3_crt = load_certificate(path.join(data_dir, "chain_crt_pem.crt")) ch3_ca = load_certificate(path.join(data_dir, "ca_cert_pem.crt")) # Validate the chain (if corresponding items in chain are singed by one another) if not validate_certificate_chain(chain_cert): raise SPSDKError("The certificate chain is not valid") print("The chain of certificates is valid.") # Checks if CA flag is set correctly if is_ca_flag_set(ch3_crt2): raise SPSDKError("CA flag is set") if not is_ca_flag_set(ch3_crt): raise SPSDKError("CA flag is not set") if not is_ca_flag_set(ch3_ca): raise SPSDKError("CA flag is not set")
def _get_rotk(rotk_priv_key: str, rot_pub_keys: List[str]) -> bytes: """Creates RoTKey_Pub (2 element 16-bit array (little endian). CTRKtable index (RoT meta-data) of the public key used by the vendor to sign the DC. Curve identifier: - Secp256r1: 0x0001 - Secp384r1: 0x0002 - Secp521r1: 0x0003 :return: binary representation """ priv_loaded = crypto.load_private_key(rotk_priv_key) pub_from_priv = priv_loaded.public_key() pub_numbers = pub_from_priv.public_numbers() rot_pub_numbers = [ crypto.load_public_key(k).public_numbers() for k in rot_pub_keys ] key_index = rot_pub_numbers.index(pub_numbers) assert key_index is not None, "ROTK private key does not correspond to any of RotMeta public keys." curve_index = {256: 1, 384: 2, 521: 3}[pub_from_priv.key_size] return pack('<2H', key_index, curve_index)
def main(json_conf: click.File, cert_path: str) -> None: """Utility for certificate generation.""" logger.info("Generating Certificate...") logger.info("Loading configuration from json file...") json_content = json.load(json_conf) # type: ignore cert_config = CertificateParametersConfig(json_content) priv_key = load_private_key(cert_config.issuer_private_key) pub_key = load_public_key(cert_config.subject_public_key) certificate = generate_certificate( subject=cert_config.subject_name, issuer=cert_config.issuer_name, subject_public_key=pub_key, issuer_private_key=priv_key, serial_number=cert_config.serial_number, duration=cert_config.duration, if_ca=cert_config.BasicConstrains_ca, path_length=cert_config.BasicConstrains_path_length) logger.info("Saving the generated certificate to the specified path...") save_crypto_item(certificate, cert_path) logger.info("Certificate generated successfully...")
def test_is_key_pub(data_dir, file_name, expect_pub_key): key_path = path.join(data_dir, file_name) result = bool(load_public_key(key_path)) assert result is expect_pub_key