Skip to content

Commit

Permalink
Bring over RSA-PSS validators for WASM from #653
Browse files Browse the repository at this point in the history
  • Loading branch information
scouten-adobe committed Nov 18, 2024
1 parent 3410c19 commit 2688f3d
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 21 deletions.
1 change: 1 addition & 0 deletions internal/crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ ecdsa = "0.16.9"
ed25519-dalek = "2.1.1"
p256 = "0.13.2"
p384 = "0.13.0"
rsa = { version = "0.9.6", features = ["sha2"] }
spki = "0.7.3"
wasm-bindgen = "0.2.83"
wasm-bindgen-futures = "0.4.31"
Expand Down
7 changes: 3 additions & 4 deletions internal/crypto/src/tests/raw_signature/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ fn ps256_bad_signature() {
}

#[test]
// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn ps256_bad_data() {
let signature = include_bytes!("../fixtures/raw_signature/ps256.raw_sig");
let pub_key = include_bytes!("../fixtures/raw_signature/ps256.pub_key");
Expand All @@ -168,7 +168,7 @@ fn ps256_bad_data() {
}

#[test]
// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn ps384() {
let signature = include_bytes!("../fixtures/raw_signature/ps384.raw_sig");
let pub_key = include_bytes!("../fixtures/raw_signature/ps384.pub_key");
Expand All @@ -179,8 +179,7 @@ fn ps384() {
}

#[test]
// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] // ES512 not
// implemented
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn ps512() {
let signature = include_bytes!("../fixtures/raw_signature/ps512.raw_sig");
let pub_key = include_bytes!("../fixtures/raw_signature/ps512.pub_key");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ use crate::{

const SAMPLE_DATA: &[u8] = b"some sample content to sign";

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[wasm_bindgen_test]
fn es256() {
let signature = include_bytes!("../../fixtures/raw_signature/es256.raw_sig");
let pub_key = include_bytes!("../../fixtures/raw_signature/es256.pub_key");
Expand All @@ -31,8 +30,7 @@ fn es256() {
.unwrap();
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[wasm_bindgen_test]
fn es384() {
let signature = include_bytes!("../../fixtures/raw_signature/es384.raw_sig");
let pub_key = include_bytes!("../../fixtures/raw_signature/es384.pub_key");
Expand All @@ -54,8 +52,7 @@ fn es384() {
// .unwrap();
// }

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[wasm_bindgen_test]
fn es256_bad_signature() {
let mut signature = include_bytes!("../../fixtures/raw_signature/es256.raw_sig").to_vec();
assert_ne!(signature[10], 10);
Expand All @@ -71,8 +68,7 @@ fn es256_bad_signature() {
);
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[wasm_bindgen_test]
fn es256_bad_data() {
let signature = include_bytes!("../../fixtures/raw_signature/es256.raw_sig");
let pub_key = include_bytes!("../../fixtures/raw_signature/es256.pub_key");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ use crate::{

const SAMPLE_DATA: &[u8] = b"some sample content to sign";

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[wasm_bindgen_test]
fn good() {
let signature = include_bytes!("../../fixtures/raw_signature/ed25519.raw_sig");
let pub_key = include_bytes!("../../fixtures/raw_signature/ed25519.pub_key");
Expand All @@ -31,8 +30,7 @@ fn good() {
.unwrap();
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[wasm_bindgen_test]
fn bad_data() {
let signature = include_bytes!("../../fixtures/raw_signature/ed25519.raw_sig");
let pub_key = include_bytes!("../../fixtures/raw_signature/ed25519.pub_key");
Expand Down
2 changes: 1 addition & 1 deletion internal/crypto/src/tests/webcrypto/validators/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@

mod ecdsa_validator;
mod ed25519_validator;
// mod rsa_validator;
mod rsa_validator;
83 changes: 83 additions & 0 deletions internal/crypto/src/tests/webcrypto/validators/rsa_validator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright 2022 Adobe. All rights reserved.
// This file is licensed to you under the Apache License,
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.

// Unless required by applicable law or agreed to in writing,
// this software is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
// specific language governing permissions and limitations under
// each license.

use wasm_bindgen_test::wasm_bindgen_test;

use crate::{
raw_signature::{RawSignatureValidationError, RawSignatureValidator},
webcrypto::validators::RsaValidator,
};

const SAMPLE_DATA: &[u8] = b"some sample content to sign";

#[wasm_bindgen_test]
fn ps256() {
let signature = include_bytes!("../../fixtures/raw_signature/ps256.raw_sig");
let pub_key = include_bytes!("../../fixtures/raw_signature/ps256.pub_key");

RsaValidator::Ps256
.validate(signature, SAMPLE_DATA, pub_key)
.unwrap();
}

#[wasm_bindgen_test]
fn ps256_bad_signature() {
let mut signature = include_bytes!("../../fixtures/raw_signature/ps256.raw_sig").to_vec();
assert_ne!(signature[10], 10);
signature[10] = 10;

let pub_key = include_bytes!("../../fixtures/raw_signature/ps256.pub_key");

assert_eq!(
RsaValidator::Ps256
.validate(&signature, SAMPLE_DATA, pub_key)
.unwrap_err(),
RawSignatureValidationError::SignatureMismatch
);
}

#[wasm_bindgen_test]
fn ps256_bad_data() {
let signature = include_bytes!("../../fixtures/raw_signature/ps256.raw_sig");
let pub_key = include_bytes!("../../fixtures/raw_signature/ps256.pub_key");

let mut data = SAMPLE_DATA.to_vec();
data[10] = 0;

assert_eq!(
RsaValidator::Ps256
.validate(signature, &data, pub_key)
.unwrap_err(),
RawSignatureValidationError::SignatureMismatch
);
}

#[wasm_bindgen_test]
fn ps384() {
let signature = include_bytes!("../../fixtures/raw_signature/ps384.raw_sig");
let pub_key = include_bytes!("../../fixtures/raw_signature/ps384.pub_key");

RsaValidator::Ps384
.validate(signature, SAMPLE_DATA, pub_key)
.unwrap();
}

#[wasm_bindgen_test]
fn ps512() {
let signature = include_bytes!("../../fixtures/raw_signature/ps512.raw_sig");
let pub_key = include_bytes!("../../fixtures/raw_signature/ps512.pub_key");

RsaValidator::Ps512
.validate(signature, SAMPLE_DATA, pub_key)
.unwrap();
}
10 changes: 6 additions & 4 deletions internal/crypto/src/webcrypto/validators/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,18 @@ pub use ecdsa_validator::EcdsaValidator;
mod ed25519_validator;
pub use ed25519_validator::Ed25519Validator;

// mod rsa_validator;
// pub use rsa_validator::{RsaLegacyValidator, RsaValidator}; // ???
mod rsa_validator;
pub use rsa_validator::RsaValidator;

/// Return a validator for the given signing algorithm.
pub fn validator_for_signing_alg(alg: SigningAlg) -> Option<Box<dyn RawSignatureValidator>> {
match alg {
SigningAlg::Es256 => Some(Box::new(EcdsaValidator::Es256)),
SigningAlg::Es384 => Some(Box::new(EcdsaValidator::Es384)),
// SigningAlg::Es512 => Some(Box::new(EcdsaValidator::Es512)),
SigningAlg::Es512 => None, /* why is this unimplemented? */
SigningAlg::Ed25519 => Some(Box::new(Ed25519Validator {})),
_ => unimplemented!(),
SigningAlg::Ps256 => Some(Box::new(RsaValidator::Ps256)),
SigningAlg::Ps384 => Some(Box::new(RsaValidator::Ps384)),
SigningAlg::Ps512 => Some(Box::new(RsaValidator::Ps512)),
}
}
87 changes: 87 additions & 0 deletions internal/crypto/src/webcrypto/validators/rsa_validator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2024 Adobe. All rights reserved.
// This file is licensed to you under the Apache License,
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.

// Unless required by applicable law or agreed to in writing,
// this software is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
// specific language governing permissions and limitations under
// each license.

use rsa::{
pss::Signature,
sha2::{Sha256, Sha384, Sha512},
signature::Verifier,
BigUint, RsaPublicKey,
};
use spki::SubjectPublicKeyInfoRef;
use x509_parser::der_parser::ber::{parse_ber_sequence, BerObject};

use crate::raw_signature::{RawSignatureValidationError, RawSignatureValidator};

/// An `RsaValidator` can validate raw signatures with one of the RSA-PSS
/// signature algorithms.
#[non_exhaustive]
pub enum RsaValidator {
/// RSASSA-PSS using SHA-256 and MGF1 with SHA-256
Ps256,

/// RSASSA-PSS using SHA-384 and MGF1 with SHA-384
Ps384,

/// RSASSA-PSS using SHA-512 and MGF1 with SHA-512
Ps512,
}

impl RawSignatureValidator for RsaValidator {
fn validate(
&self,
sig: &[u8],
data: &[u8],
public_key: &[u8],
) -> Result<(), RawSignatureValidationError> {
let signature: Signature = sig
.try_into()
.map_err(|_| RawSignatureValidationError::InvalidSignature)?;

let spki = SubjectPublicKeyInfoRef::try_from(public_key)
.map_err(|_| RawSignatureValidationError::InvalidPublicKey)?;

let (_, seq) = parse_ber_sequence(&spki.subject_public_key.raw_bytes())
.map_err(|_| RawSignatureValidationError::InvalidPublicKey)?;

let modulus = biguint_val(&seq[0]);
let exp = biguint_val(&seq[1]);

let public_key = RsaPublicKey::new(modulus, exp)
.map_err(|_| RawSignatureValidationError::InvalidPublicKey)?;

let result = match self {
Self::Ps256 => {
let vk = rsa::pss::VerifyingKey::<Sha256>::new(public_key);
vk.verify(&data, &signature)
}
Self::Ps384 => {
let vk = rsa::pss::VerifyingKey::<Sha384>::new(public_key);
vk.verify(&data, &signature)
}
Self::Ps512 => {
let vk = rsa::pss::VerifyingKey::<Sha512>::new(public_key);
vk.verify(&data, &signature)
}
};

result.map_err(|_| RawSignatureValidationError::SignatureMismatch)
}
}

fn biguint_val(ber_object: &BerObject) -> BigUint {
ber_object
.as_biguint()
.map(|x| x.to_u32_digits())
.map(rsa::BigUint::new)
.unwrap_or_default()
}

0 comments on commit 2688f3d

Please sign in to comment.