Skip to content

Commit b474143

Browse files
feat(pki): Add algorithm ID
Used to identify which algorithm was used and which to use even tho we only support RSA for now
1 parent 4b6b5bd commit b474143

File tree

5 files changed

+113
-24
lines changed

5 files changed

+113
-24
lines changed

libparsec/crates/platform_pki/examples/decrypt_message.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use std::path::PathBuf;
55

66
use anyhow::Context;
77
use clap::Parser;
8-
use libparsec_platform_pki::{decrypt_message, CertificateHash, CertificateReference};
8+
use libparsec_platform_pki::{
9+
decrypt_message, CertificateHash, CertificateReference, EncryptionAlgorithm,
10+
};
911

1012
#[derive(Debug, Parser)]
1113
struct Args {
@@ -14,6 +16,9 @@ struct Args {
1416
certificate_hash: CertificateHash,
1517
#[command(flatten)]
1618
content: ContentOpts,
19+
/// The algorithm used to encrypt the content.
20+
#[arg(long, default_value_t = EncryptionAlgorithm::RsaesOaepSha256)]
21+
algorithm: EncryptionAlgorithm,
1722
}
1823

1924
#[derive(Debug, Clone, clap::Args)]
@@ -39,11 +44,13 @@ fn main() -> anyhow::Result<()> {
3944
.decode(&b64_data)
4045
.context("Failed to decode hex encoded data")?;
4146

42-
let res = decrypt_message(&data, &cert_ref).context("Failed to decrypt message")?;
47+
let res =
48+
decrypt_message(args.algorithm, &data, &cert_ref).context("Failed to decrypt message")?;
4349

4450
println!(
45-
"Decrypted by cert with id: {}",
46-
data_encoding::BASE64.encode_display(&res.cert_ref.id)
51+
"Decrypted by cert with id {{{}}} with algo {}",
52+
data_encoding::BASE64.encode_display(&res.cert_ref.id),
53+
args.algorithm
4754
);
4855
#[cfg(feature = "hash-sri-display")]
4956
println!("Decrypted by cert with fingerprint: {}", res.cert_ref.hash);

libparsec/crates/platform_pki/examples/encrypt_message.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ fn main() -> anyhow::Result<()> {
3939
let res = encrypt_message(&data, &cert_ref).context("Failed to encrypt message")?;
4040

4141
println!(
42-
"Encrypted by cert with id: {}",
43-
data_encoding::BASE64.encode_display(&res.cert_ref.id)
42+
"Encrypted by cert with id {{{}}} using the algorithm {}",
43+
data_encoding::BASE64.encode_display(&res.cert_ref.id),
44+
res.algo
4445
);
4546
#[cfg(feature = "hash-sri-display")]
4647
println!("Encrypted by cert with fingerprint: {}", res.cert_ref.hash);

libparsec/crates/platform_pki/examples/sign_message.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ fn main() -> anyhow::Result<()> {
3939
let res = sign_message(&data, &cert_ref).context("Failed to sign message")?;
4040

4141
println!(
42-
"Signed by cert with id: {}",
43-
data_encoding::BASE64.encode_display(&res.cert_ref.id)
42+
"Signed by cert with id {{{}}} with algorithm {}",
43+
data_encoding::BASE64.encode_display(&res.cert_ref.id),
44+
res.algo
4445
);
4546
#[cfg(feature = "hash-sri-display")]
4647
println!("Signed by cert with fingerprint: {}", res.cert_ref.hash);

libparsec/crates/platform_pki/src/lib.rs

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ pub mod errors;
44
#[cfg(target_os = "windows")]
55
mod windows;
66

7+
use std::{fmt::Display, str::FromStr};
8+
79
use bytes::Bytes;
810

911
#[cfg(target_os = "windows")]
@@ -53,8 +55,8 @@ pub use windows::show_certificate_selection_dialog;
5355
mod platform {
5456
use crate::{
5557
CertificateDer, CertificateReference, DecryptMessageError, DecryptedMessage,
56-
EncryptMessageError, EncryptedMessage, GetDerEncodedCertificateError, SignMessageError,
57-
SignedMessage,
58+
EncryptMessageError, EncryptedMessage, EncryptionAlgorithm, GetDerEncodedCertificateError,
59+
SignMessageError, SignedMessage,
5860
};
5961

6062
pub fn get_der_encoded_certificate(
@@ -82,10 +84,11 @@ mod platform {
8284
}
8385

8486
pub fn decrypt_message(
87+
algo: EncryptionAlgorithm,
8588
encrypted_message: &[u8],
8689
certificate_ref: &CertificateReference,
8790
) -> Result<DecryptedMessage, DecryptMessageError> {
88-
let _ = (encrypted_message, certificate_ref);
91+
let _ = (algo, encrypted_message, certificate_ref);
8992
unimplemented!("platform not supported")
9093
}
9194
}
@@ -98,15 +101,77 @@ pub struct CertificateDer {
98101
pub der_content: Bytes,
99102
}
100103

104+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105+
pub enum SignatureAlgorithm {
106+
RsassaPssSha256,
107+
}
108+
109+
impl From<SignatureAlgorithm> for &'static str {
110+
fn from(value: SignatureAlgorithm) -> Self {
111+
match value {
112+
SignatureAlgorithm::RsassaPssSha256 => "RSASSA-PSS-SHA256",
113+
}
114+
}
115+
}
116+
117+
impl Display for SignatureAlgorithm {
118+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119+
f.write_str((*self).into())
120+
}
121+
}
122+
123+
impl FromStr for SignatureAlgorithm {
124+
type Err = &'static str;
125+
126+
fn from_str(s: &str) -> Result<Self, Self::Err> {
127+
match s {
128+
"RSASSA-PSS-SHA256" => Ok(Self::RsassaPssSha256),
129+
_ => Err("Unknown signature algorithm"),
130+
}
131+
}
132+
}
133+
101134
pub struct SignedMessage {
135+
pub algo: SignatureAlgorithm,
102136
pub cert_ref: CertificateReferenceIdOrHash,
103137
pub signed_message: Bytes,
104138
}
105139

106140
pub use errors::SignMessageError;
107141
pub use platform::sign_message;
108142

143+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144+
pub enum EncryptionAlgorithm {
145+
RsaesOaepSha256,
146+
}
147+
148+
impl From<EncryptionAlgorithm> for &'static str {
149+
fn from(value: EncryptionAlgorithm) -> Self {
150+
match value {
151+
EncryptionAlgorithm::RsaesOaepSha256 => "RSAES-OAEP-SHA256",
152+
}
153+
}
154+
}
155+
156+
impl FromStr for EncryptionAlgorithm {
157+
type Err = &'static str;
158+
159+
fn from_str(s: &str) -> Result<Self, Self::Err> {
160+
match s {
161+
"RSAES-OAEP-SHA256" => Ok(Self::RsaesOaepSha256),
162+
_ => Err("Unknown encryption algorithm"),
163+
}
164+
}
165+
}
166+
167+
impl Display for EncryptionAlgorithm {
168+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169+
f.write_str((*self).into())
170+
}
171+
}
172+
109173
pub struct EncryptedMessage {
174+
pub algo: EncryptionAlgorithm,
110175
pub cert_ref: CertificateReferenceIdOrHash,
111176
pub ciphered: Bytes,
112177
}

libparsec/crates/platform_pki/src/windows/mod.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use std::ffi::c_void;
55
use crate::{
66
CertificateDer, CertificateHash, CertificateReference, CertificateReferenceIdOrHash,
77
DecryptMessageError, DecryptedMessage, EncryptMessageError, EncryptedMessage,
8-
GetDerEncodedCertificateError, SignMessageError, SignedMessage,
8+
EncryptionAlgorithm, GetDerEncodedCertificateError, SignMessageError, SignatureAlgorithm,
9+
SignedMessage,
910
};
1011
use bytes::Bytes;
1112
use schannel::{
@@ -221,18 +222,19 @@ pub fn sign_message(
221222
let reference = get_id_and_hash_from_cert_context(&cert_context)
222223
.map_err(SignMessageError::CannotGetCertificateInfo)?;
223224
let keypair = get_keypair(&cert_context)?;
224-
let signed_message = match keypair {
225+
let (algo, signed_message) = match keypair {
225226
// We do not support a CryptoAPI provider as its API is marked for depreciation by windows.
226227
PrivateKey::CryptProv(..) => {
227228
todo!("Use CryptGetUserKey to get the keypair")
228229
}
229230
// Handle to a CryptoGraphy Next Generation (CNG) API
230-
PrivateKey::NcryptKey(handle) => ncrypt_sign_message(message, &handle).map(Into::into),
231+
PrivateKey::NcryptKey(handle) => ncrypt_sign_message_with_rsa(message, &handle),
231232
}
232233
.map_err(SignMessageError::CannotSign)?;
233234

234235
Ok(SignedMessage {
235-
signed_message,
236+
algo,
237+
signed_message: signed_message.into(),
236238
cert_ref: reference,
237239
})
238240
}
@@ -246,7 +248,11 @@ fn get_keypair(context: &CertContext) -> Result<PrivateKey, crate::errors::BaseK
246248
.map_err(crate::errors::BaseKeyPairError::CannotAcquireKeypair)
247249
}
248250

249-
fn ncrypt_sign_message(message: &[u8], handle: &NcryptKey) -> std::io::Result<Vec<u8>> {
251+
fn ncrypt_sign_message_with_rsa(
252+
message: &[u8],
253+
handle: &NcryptKey,
254+
) -> std::io::Result<(SignatureAlgorithm, Vec<u8>)> {
255+
const ALGO: SignatureAlgorithm = SignatureAlgorithm::RsassaPssSha256;
250256
let hash = sha2::Sha256::digest(message);
251257
// SAFETY: NcryptKey is obtain from an NCRYPT_KEY_HANDLE, here we retrieve the underlying
252258
// handle.
@@ -305,7 +311,7 @@ fn ncrypt_sign_message(message: &[u8], handle: &NcryptKey) -> std::io::Result<Ve
305311
if res != 0 {
306312
return Err(std::io::Error::last_os_error());
307313
}
308-
Ok(buff)
314+
Ok((ALGO, buff))
309315
}
310316
}
311317

@@ -319,23 +325,28 @@ pub fn encrypt_message(
319325
let reference = get_id_and_hash_from_cert_context(&cert_context)
320326
.map_err(EncryptMessageError::CannotGetCertificateInfo)?;
321327
let keypair = get_keypair(&cert_context)?;
322-
let ciphered = match keypair {
328+
let (algo, ciphered) = match keypair {
323329
// We do not support a CryptoAPI provider as its API is marked for depreciation by windows.
324330
PrivateKey::CryptProv(..) => {
325331
todo!("Use CryptGetUserKey to get the keypair")
326332
}
327333
// Handle to a CryptoGraphy Next Generation (CNG) API
328-
PrivateKey::NcryptKey(handle) => ncrypt_encrypt_message(message, &handle).map(Into::into),
334+
PrivateKey::NcryptKey(handle) => ncrypt_encrypt_message_with_rsa(message, &handle),
329335
}
330336
.map_err(EncryptMessageError::CannotEncrypt)?;
331337

332338
Ok(EncryptedMessage {
333-
ciphered,
339+
algo,
340+
ciphered: ciphered.into(),
334341
cert_ref: reference,
335342
})
336343
}
337344

338-
fn ncrypt_encrypt_message(message: &[u8], handle: &NcryptKey) -> std::io::Result<Vec<u8>> {
345+
fn ncrypt_encrypt_message_with_rsa(
346+
message: &[u8],
347+
handle: &NcryptKey,
348+
) -> std::io::Result<(EncryptionAlgorithm, Vec<u8>)> {
349+
const ALGO: EncryptionAlgorithm = EncryptionAlgorithm::RsaesOaepSha256;
339350
// SAFETY: NcryptKey is obtain from an NCRYPT_KEY_HANDLE, here we retrieve the underlying
340351
// handle.
341352
let raw_handle = unsafe { RawPointer::as_ptr(handle) } as NCRYPT_KEY_HANDLE;
@@ -390,11 +401,12 @@ fn ncrypt_encrypt_message(message: &[u8], handle: &NcryptKey) -> std::io::Result
390401
if res != 0 {
391402
return Err(std::io::Error::last_os_error());
392403
}
393-
Ok(buff)
404+
Ok((ALGO, buff))
394405
}
395406
}
396407

397408
pub fn decrypt_message(
409+
algo: EncryptionAlgorithm,
398410
encrypted_message: &[u8],
399411
certificate_ref: &CertificateReference,
400412
) -> Result<DecryptedMessage, DecryptMessageError> {
@@ -411,7 +423,10 @@ pub fn decrypt_message(
411423
}
412424
// Handle to a CryptoGraphy Next Generation (CNG) API
413425
PrivateKey::NcryptKey(handle) => {
414-
ncrypt_decrypt_message(encrypted_message, &handle).map(Into::into)
426+
if algo != EncryptionAlgorithm::RsaesOaepSha256 {
427+
todo!("Unsupported encryption algo '{algo}'");
428+
}
429+
ncrypt_decrypt_message_with_rsa(encrypted_message, &handle).map(Into::into)
415430
}
416431
}
417432
.map_err(DecryptMessageError::CannotDecrypt)?;
@@ -422,7 +437,7 @@ pub fn decrypt_message(
422437
})
423438
}
424439

425-
fn ncrypt_decrypt_message(
440+
fn ncrypt_decrypt_message_with_rsa(
426441
encrypted_message: &[u8],
427442
handle: &NcryptKey,
428443
) -> std::io::Result<Vec<u8>> {

0 commit comments

Comments
 (0)