|
| 1 | +""" |
| 2 | +This migration converts the PEM private key file to PKCS8 DER for compatibility |
| 3 | +with the new Aleph.im P2P service. The Rust implementation of libp2p can only load |
| 4 | +RSA keys in that format. |
| 5 | +""" |
| 6 | + |
| 7 | + |
| 8 | +import logging |
| 9 | +import os |
| 10 | +from pathlib import Path |
| 11 | +from typing import Optional |
| 12 | + |
| 13 | +import yaml |
| 14 | +from Crypto.PublicKey import RSA |
| 15 | +from p2pclient.libp2p_stubs.crypto.rsa import RSAPrivateKey |
| 16 | + |
| 17 | +from aleph.exceptions import InvalidKeyDirException |
| 18 | + |
| 19 | +LOGGER = logging.getLogger(os.path.basename(__file__)) |
| 20 | + |
| 21 | + |
| 22 | +PKCS8_DER_KEY_FILE = "node-secret.pkcs8.der" |
| 23 | + |
| 24 | + |
| 25 | +def convert_pem_key_file_to_pkcs8_der( |
| 26 | + pem_key_file: Path, pkcs8_der_key_file: Path |
| 27 | +) -> None: |
| 28 | + with pem_key_file.open() as pem: |
| 29 | + private_key = RSAPrivateKey(RSA.import_key(pem.read())) |
| 30 | + |
| 31 | + with pkcs8_der_key_file.open("wb") as der: |
| 32 | + der.write(private_key.impl.export_key(format="DER", pkcs=8)) |
| 33 | + |
| 34 | + |
| 35 | +def get_key_from_config(config_file: Path) -> Optional[str]: |
| 36 | + """ |
| 37 | + In previous versions of the CCN, it was possible to set the key value directly |
| 38 | + in the config file. This function tries to find it in the config or returns None. |
| 39 | +
|
| 40 | + :param config_file: Path to the CCN configuration file. |
| 41 | + :return: The private key used to identify the node on the P2P network, or None |
| 42 | + if the key is not provided in the config file. |
| 43 | + """ |
| 44 | + with open(config_file) as f: |
| 45 | + config = yaml.safe_load(f) |
| 46 | + |
| 47 | + try: |
| 48 | + return config["p2p"]["key"] |
| 49 | + except KeyError: |
| 50 | + return None |
| 51 | + |
| 52 | + |
| 53 | +def upgrade(**kwargs): |
| 54 | + key_dir = Path(kwargs["key_dir"]) |
| 55 | + pem_key_file = key_dir / "node-secret.key" |
| 56 | + |
| 57 | + # Nothing to do if the PKCS8 DER key file already exists |
| 58 | + pkcs8_der_key_file = key_dir / PKCS8_DER_KEY_FILE |
| 59 | + if pkcs8_der_key_file.is_file(): |
| 60 | + LOGGER.info( |
| 61 | + "Key file %s already exists, nothing to do", |
| 62 | + pkcs8_der_key_file, |
| 63 | + ) |
| 64 | + return |
| 65 | + |
| 66 | + if not key_dir.is_dir(): |
| 67 | + raise InvalidKeyDirException( |
| 68 | + f"The specified key directory ('{key_dir}') is not a directory." |
| 69 | + ) |
| 70 | + |
| 71 | + LOGGER.info("Converting the private key file to PKCS8 DER format...") |
| 72 | + convert_pem_key_file_to_pkcs8_der(pem_key_file, pkcs8_der_key_file) |
| 73 | + LOGGER.info("Successfully created %s.", pkcs8_der_key_file) |
| 74 | + |
| 75 | + |
| 76 | +def downgrade(**kwargs): |
| 77 | + # Nothing to do, the key file is still present in the key directory |
| 78 | + pass |
0 commit comments