From 3f1195e08509156f2a7e0d816214ea1ed4ac05d2 Mon Sep 17 00:00:00 2001 From: "baranyildirim@gmail.com" Date: Sat, 17 Feb 2024 08:28:52 +0000 Subject: [PATCH] Add from_private_key_der and from_private_key_pem to PyKeyPair and type stubs, add tests --- Cargo.lock | 14 ++++++++++++-- Cargo.toml | 2 +- biscuit_auth.pyi | 17 +++++++++++++++++ biscuit_test.py | 16 +++++++++++++++- src/lib.rs | 26 ++++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81fe1ef..0c14b9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,9 +52,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "biscuit-auth" -version = "4.0.0" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "082a4b98f62e31c68540f3bd8da837b2188df0a9e3a99b1fb2035a983434cdb4" +checksum = "57ef2e2634c5493e5374f70bc45c9c8e5ebb547261973fe72698f6833d4b32ea" dependencies = [ "base64", "biscuit-parser", @@ -243,6 +243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] @@ -498,6 +499,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "pkcs8" version = "0.10.2" diff --git a/Cargo.toml b/Cargo.toml index 7b844ca..a782157 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ name = "biscuit_auth" crate-type = ["cdylib"] [dependencies] -biscuit-auth = "4.0.0" +biscuit-auth = { version = "4.1.1", features = ["pem"] } pyo3 = { version = "0.18.3", features = ["extension-module", "chrono"]} hex = "0.4" base64 = "0.13.0" diff --git a/biscuit_auth.pyi b/biscuit_auth.pyi index 23bce9a..20d97e4 100644 --- a/biscuit_auth.pyi +++ b/biscuit_auth.pyi @@ -372,6 +372,23 @@ class KeyPair: @classmethod def from_private_key(cls, private_key: PrivateKey) -> KeyPair: ... + # Generate a keypair from a DER buffer + # + # :param bytes: private key bytes in DER format + # :type private_key: PrivateKey + # :return: the corresponding keypair + # :rtype: KeyPair + @classmethod + def from_private_key_der(cls, der: bytes) -> KeyPair: ... + + # + # :param bytes: private key bytes in PEM format + # :type private_key: PrivateKey + # :return: the corresponding keypair + # :rtype: KeyPair + @classmethod + def from_private_key_pem(cls, pem: str) -> KeyPair: ... + # The public key part @property def public_key(self) -> PublicKey: ... diff --git a/biscuit_test.py b/biscuit_test.py index 357f838..5181735 100644 --- a/biscuit_test.py +++ b/biscuit_test.py @@ -4,7 +4,7 @@ import pytest -from biscuit_auth import Authorizer, Biscuit, BiscuitBuilder, BlockBuilder, Check, Fact, KeyPair, Policy, PrivateKey, PublicKey, Rule, UnverifiedBiscuit +from biscuit_auth import KeyPair,Authorizer, Biscuit, BiscuitBuilder, BlockBuilder, Check, Fact, KeyPair, Policy, PrivateKey, PublicKey, Rule, UnverifiedBiscuit def test_fact(): fact = Fact('fact(1, true, "", "Test", hex:aabbcc, 2023-04-29T01:00:00Z)') @@ -418,3 +418,17 @@ def test_append_on_unverified(): utoken2 = utoken.append(BlockBuilder("check if true")) assert utoken2.block_source(3) == "check if true;\n" + + +def test_keypair_from_private_key_der(): + private_key_der = bytes.fromhex("302e020100300506032b6570042204200499694d0da05dcac40052663e71d50c1539465f8926dfe92033cf7aaad53d65") + private_key_hex = "0499694d0da05dcac40052663e71d50c1539465f8926dfe92033cf7aaad53d65" + kp = KeyPair.from_private_key_der(der=private_key_der) + assert kp.private_key.to_hex() == private_key_hex + + +def test_keypair_from_private_key_pem(): + private_key_pem = "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIASZaU0NoF3KxABSZj5x1QwVOUZfiSbf6SAzz3qq1T1l\n-----END PRIVATE KEY-----" + private_key_hex = "0499694d0da05dcac40052663e71d50c1539465f8926dfe92033cf7aaad53d65" + kp = KeyPair.from_private_key_pem(pem=private_key_pem) + assert kp.private_key.to_hex() == private_key_hex \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 24ce12b..b57df23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -701,6 +701,32 @@ impl PyKeyPair { PyKeyPair(KeyPair::from(&private_key.0)) } + /// Generate a keypair from a DER buffer + /// + /// :param bytes: private key bytes in DER format + /// :type private_key: PrivateKey + /// :return: the corresponding keypair + /// :rtype: KeyPair + #[classmethod] + pub fn from_private_key_der(_: &PyType, der: &[u8]) -> PyResult { + let kp = KeyPair::from_private_key_der(der) + .map_err(|e: error::Format| pyo3::exceptions::PyValueError::new_err(e.to_string()))?; + Ok(PyKeyPair(kp)) + } + + /// Generate a keypair from a PEM buffer + /// + /// :param bytes: private key bytes in PEM format + /// :type private_key: PrivateKey + /// :return: the corresponding keypair + /// :rtype: KeyPair + #[classmethod] + pub fn from_private_key_pem(_: &PyType, pem: &str) -> PyResult { + let kp = KeyPair::from_private_key_pem(pem) + .map_err(|e: error::Format| pyo3::exceptions::PyValueError::new_err(e.to_string()))?; + Ok(PyKeyPair(kp)) + } + /// The public key part #[getter] pub fn public_key(&self) -> PyPublicKey {