def insert_ed25519_signing_key(self, uuid: UUID, sk: SigningKey):
     """Store an existing ED25519 signing key in the key store."""
     # encode the ED25519 private key as PKCS#8
     private_key_info = rfc5208.PrivateKeyInfo()
     private_key_info.setComponentByName('version', 'v1')
     a = AlgorithmIdentifier()
     a.setComponentByName('algorithm', ECC_ENCRYPTION_OID)
     private_key_info.setComponentByName('privateKeyAlgorithm', a)
     private_key_info.setComponentByName('privateKey', sk.to_bytes())
     pkey_pkcs8 = encoder.encode(private_key_info)
     pke = jks.PrivateKeyEntry.new(alias=str(uuid.hex),
                                   certs=[],
                                   key=pkey_pkcs8)
     self._ks.entries['pke_' + uuid.hex] = pke
Beispiel #2
0
class UbirchProtocol(object):
    """
    The ubirch-protocol packages data into a protocol wrapper, taking care of signing data, chaining of signatures
    and verification of incoming messages.
    """

    ECC_ENCRYPTION_OID = (1, 2, 1, 3, 101, 112)

    def __init__(self, uuid: UUID, keystore_file: str, password: str) -> None:
        """Initialize the ubirch-protocol for the device with the given UUID."""
        super().__init__()
        self._uuid = uuid.hex
        self._ks_file = keystore_file
        self._ks_password = password
        self._load_or_create_keys()

    def _load_or_create_keys(self) -> None:
        """Load or create new crypto-keys. The keys are stored in a local key store."""
        if not self._uuid:
            raise Exception("missing UUID to load key from keystore")

        # try to load the keystore or create a new one
        try:
            self._ks = jks.KeyStore.load(self._ks_file, self._ks_password)
        except FileNotFoundError:
            log.warning("creating new key store: {}".format(self._ks_file))
            self._ks = jks.KeyStore.new("jks", [])

        # load the key
        if self._uuid in self._ks.private_keys:
            sk = self._ks.private_keys[self._uuid]
            self._signingKey = SigningKey(sk.pkey)
            log.info("loaded signing key for {}".format(self._uuid))
        else:
            self._signingKey, vk = ed25519.create_keypair(entropy=urandom)

            # encode the ED25519 private key as PKCS#8
            ed25519_algorithm_oid = self.ECC_ENCRYPTION_OID
            private_key_info = rfc5208.PrivateKeyInfo()
            private_key_info.setComponentByName('version', 'v1')

            a = AlgorithmIdentifier()
            a.setComponentByName('algorithm', ed25519_algorithm_oid)
            private_key_info.setComponentByName('privateKeyAlgorithm', a)
            private_key_info.setComponentByName('privateKey',
                                                self._signingKey.to_bytes())
            pkey_pkcs8 = encoder.encode(private_key_info)

            pke = jks.PrivateKeyEntry.new(alias=str(self._uuid),
                                          certs=[],
                                          key=pkey_pkcs8)
            self._ks.entries[self._uuid] = pke
            self._ks.save(self._ks_file, self._ks_password)
            log.info("created new signing key for {}".format(self._uuid))

    def pack_key_registration(self) -> bytes:
        now = datetime.utcnow()

        created = self._time_format(now)
        not_before = self._time_format(now)
        not_after = self._time_format(now + timedelta(days=365))

        pub_key_enc = bytes.decode(
            base64.b64encode(self._sk.get_verifying_key().to_bytes()))
        pub_key_info = {
            "hwDeviceId": self._serial,
            "pubKey": pub_key_enc,
            "pubKeyId": pub_key_enc,
            "algorithm": 'ECC_ED25519',
            "created": created,
            "validNotBefore": not_before,
            "validNotAfter": not_after
        }

        pub_key_info_enc = str.encode(
            json.dumps(pub_key_info, sort_keys=True, separators=(',', ':')))
        signature = bytes.decode(
            base64.b64encode(self._sk.sign(pub_key_info_enc)))

        payload = {"pubKeyInfo": pub_key_info, "signature": signature}

        return str.encode(
            json.dumps(payload, sort_keys=True, separators={',', ":"}))