Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: provide from_pem_wo_parameter() to rebuild sepc256k1 identity from .pem without parameters #592

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* `Url` now implements `RouteProvider`.
* Add canister snapshot methods to `ManagementCanister`.
* Add `AllowedViewers` to `LogVisibility` enum.
* Add `from_pem_wo_parameter` for `Secp256k1Identity`.

## [0.37.1] - 2024-07-25

Expand Down
36 changes: 36 additions & 0 deletions ic-agent/src/identity/secp256k1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ impl Secp256k1Identity {
Err(pem::PemError::MissingData.into())
}

#[cfg(feature = "pem")]
pub fn from_pem_wo_parameter<R: io::Read>(pem_reader: R) -> Result<Self, PemError> {
use sec1::{pem::PemLabel, EcPrivateKey};

let contents = pem_reader.bytes().collect::<Result<Vec<u8>, io::Error>>()?;

for pem in pem::parse_many(contents)? {
if pem.tag() != EcPrivateKey::PEM_LABEL {
continue;
}
let private_key =
SecretKey::from_sec1_der(pem.contents()).map_err(|_| pkcs8::Error::KeyMalformed)?;
return Ok(Self::from_private_key(private_key));
}
Err(pem::PemError::MissingData.into())
}

/// Creates an identity from a private key.
pub fn from_private_key(private_key: SecretKey) -> Self {
let public_key = private_key.public_key();
Expand Down Expand Up @@ -159,6 +176,15 @@ MHQCAQEEIAgy7nZEcVHkQ4Z1Kdqby8SwyAiyKDQmtbEHTIM+WNeBoAcGBSuBBAAK
oUQDQgAEgO87rJ1ozzdMvJyZQ+GABDqUxGLvgnAnTlcInV3NuhuPv4O3VGzMGzeB
N3d26cRxD99TPtm8uo2OuzKhSiq6EQ==
-----END EC PRIVATE KEY-----
";

// IDENTITY_FILE_WITHOUT_PARAMS is exported from the following command:
// > dfx identity export identity
const IDENTITY_FILE_WITHOUT_PARAMS: &str = "-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIAgy7nZEcVHkQ4Z1Kdqby8SwyAiyKDQmtbEHTIM+WNeBoAcGBSuBBAAK
oUQDQgAEgO87rJ1ozzdMvJyZQ+GABDqUxGLvgnAnTlcInV3NuhuPv4O3VGzMGzeB
N3d26cRxD99TPtm8uo2OuzKhSiq6EQ==
-----END EC PRIVATE KEY-----
";

// DER_ENCODED_PUBLIC_KEY was generated from the the following commands:
Expand Down Expand Up @@ -188,6 +214,16 @@ N3d26cRxD99TPtm8uo2OuzKhSiq6EQ==
assert!(DER_ENCODED_PUBLIC_KEY == hex::encode(identity.der_encoded_public_key));
}

#[test]
fn test_secp256k1_public_key_wo_params() {
// Create a secp256k1 identity from a PEM file.
let identity = Secp256k1Identity::from_pem_wo_parameter(IDENTITY_FILE_WITHOUT_PARAMS.as_bytes())
.expect("Cannot create secp256k1 identity from PEM file.");

// Assert the DER-encoded secp256k1 public key matches what we would expect.
assert!(DER_ENCODED_PUBLIC_KEY == hex::encode(identity.der_encoded_public_key));
}

#[test]
fn test_secp256k1_signature() {
// Create a secp256k1 identity from a PEM file.
Expand Down
Loading