-
-
Notifications
You must be signed in to change notification settings - Fork 11
feat: implement PublicCredential certificate decode #98
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
Changes from all commits
486792b
5d5fb38
e3e51a8
b56ab4e
8aa6bf9
ae7d5a5
dcec785
936a1b7
dd4f5e1
c35a96b
a38760b
ce2ceff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,9 @@ | ||
| //! A container for a public / private key pair, or a certificate / private key. | ||
|
|
||
| use core::str::FromStr; | ||
| use std::str::FromStr as _; | ||
|
|
||
| use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer}; | ||
| use ssh_key::public::KeyData; | ||
| use ssh_key::{certificate::Certificate, private::KeypairData, Algorithm}; | ||
|
|
||
| use crate::proto::{Error, PrivateKeyData, Result}; | ||
|
|
@@ -16,7 +17,8 @@ use crate::proto::{Error, PrivateKeyData, Result}; | |
| /// This structure covers both types of identities a user may | ||
| /// send to an agent as part of a [`Request::AddIdentity`](crate::proto::Request::AddIdentity) message. | ||
| #[derive(Clone, PartialEq, Debug)] | ||
| pub enum Credential { | ||
| #[allow(clippy::large_enum_variant)] | ||
| pub enum PrivateCredential { | ||
| /// A public/private key pair | ||
| Key { | ||
| /// Public/private key pair data | ||
|
|
@@ -42,7 +44,7 @@ pub enum Credential { | |
| }, | ||
| } | ||
|
|
||
| impl Decode for Credential { | ||
| impl Decode for PrivateCredential { | ||
| type Error = Error; | ||
|
|
||
| fn decode(reader: &mut impl Reader) -> Result<Self> { | ||
|
|
@@ -57,7 +59,7 @@ impl Decode for Credential { | |
| let privkey = PrivateKeyData::decode_as(reader, algorithm.clone())?; | ||
| let comment = String::decode(reader)?; | ||
|
|
||
| Ok(Credential::Cert { | ||
| Ok(PrivateCredential::Cert { | ||
| algorithm, | ||
| certificate, | ||
| privkey, | ||
|
|
@@ -67,12 +69,12 @@ impl Decode for Credential { | |
| let algorithm = Algorithm::from_str(&alg).map_err(ssh_encoding::Error::from)?; | ||
| let privkey = KeypairData::decode_as(reader, algorithm)?; | ||
| let comment = String::decode(reader)?; | ||
| Ok(Credential::Key { privkey, comment }) | ||
| Ok(PrivateCredential::Key { privkey, comment }) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Encode for Credential { | ||
| impl Encode for PrivateCredential { | ||
| fn encoded_len(&self) -> ssh_encoding::Result<usize> { | ||
| match self { | ||
| Self::Key { privkey, comment } => { | ||
|
|
@@ -113,3 +115,83 @@ impl Encode for Credential { | |
| } | ||
| } | ||
| } | ||
|
|
||
| #[derive(Debug, PartialEq, Eq, Clone)] | ||
| #[allow(clippy::large_enum_variant)] | ||
| /// Represents a public credential. | ||
| pub enum PublicCredential { | ||
| /// Plain public key. | ||
| Key(KeyData), | ||
| /// Signed public key. | ||
| Cert(Certificate), | ||
| } | ||
|
|
||
| impl PublicCredential { | ||
| /// Returns a reference to the [KeyData]. | ||
| pub fn key_data(&self) -> &KeyData { | ||
| match self { | ||
| Self::Key(key) => key, | ||
| Self::Cert(cert) => cert.public_key(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Decode for PublicCredential { | ||
| type Error = Error; | ||
|
|
||
| fn decode(reader: &mut impl Reader) -> core::result::Result<Self, Self::Error> { | ||
| // Read remaining bytes and prepend the algorithm string so the | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be perfectly honest with you it looks extremely ugly as it is but from my understanding it will get completely rewritten once ssh-key 0.7.0 lands (source) and since we have tests I'm not that worried about temporarily having this here. Could you add a note though? Something like |
||
| // full blob can be passed to Certificate::decode or | ||
| // KeyData::decode, both of which expect to read the algorithm | ||
| // string themselves. | ||
| let alg = String::decode(reader)?; | ||
|
|
||
| let remaining_len = reader.remaining_len(); | ||
| let mut buf = Vec::with_capacity(4 + alg.len() + remaining_len); | ||
| alg.encode(&mut buf)?; | ||
| let mut tail = vec![0u8; remaining_len]; | ||
| reader.read(&mut tail)?; | ||
| buf.extend_from_slice(&tail); | ||
|
|
||
| let mut slice: &[u8] = &buf; | ||
|
|
||
| if Algorithm::new_certificate(&alg).is_ok() { | ||
| let cert = Certificate::decode(&mut slice)?; | ||
| Ok(Self::Cert(cert)) | ||
| } else { | ||
| let key = KeyData::decode(&mut slice)?; | ||
| Ok(Self::Key(key)) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Encode for PublicCredential { | ||
| fn encoded_len(&self) -> std::result::Result<usize, ssh_encoding::Error> { | ||
| match self { | ||
| Self::Key(pubkey) => pubkey.encoded_len(), | ||
| Self::Cert(certificate) => certificate.encoded_len(), | ||
| } | ||
| } | ||
|
|
||
| fn encode( | ||
| &self, | ||
| writer: &mut impl ssh_encoding::Writer, | ||
| ) -> std::result::Result<(), ssh_encoding::Error> { | ||
| match self { | ||
| Self::Key(pubkey) => pubkey.encode(writer), | ||
| Self::Cert(certificate) => certificate.encode(writer), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl From<KeyData> for PublicCredential { | ||
| fn from(value: KeyData) -> Self { | ||
| Self::Key(value) | ||
| } | ||
| } | ||
|
|
||
| impl From<Certificate> for PublicCredential { | ||
| fn from(value: Certificate) -> Self { | ||
| Self::Cert(value) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you additionally rename the field to... say...
credential? (to mirror whatAddIdentityhas).