Skip to content

Commit

Permalink
Compatibility with rust-ece breaking API changes. (#3941)
Browse files Browse the repository at this point in the history
The rust-ece crate has had its interface simplified to remove footguns,
let's update to that release and get a few cleanups of our own while
we're at it.
  • Loading branch information
rfk authored Mar 22, 2021
1 parent ca8a276 commit ffa7a06
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 312 deletions.
37 changes: 22 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 3 additions & 11 deletions components/fxa-client/src/internal/commands/send_tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
/// then sent to the target device.
use serde_derive::*;

use rc_crypto::ece::{self, Aes128GcmEceWebPush, EcKeyComponents, WebPushParams};
use rc_crypto::ece_crypto::{RcCryptoLocalKeyPair, RcCryptoRemotePublicKey};
use rc_crypto::ece::{self, EcKeyComponents};
use sync15::{EncryptedPayload, KeyBundle};

use super::super::{device::Device, error::*, scoped_keys::ScopedKey, scopes, telemetry};
Expand All @@ -33,8 +32,7 @@ impl EncryptedSendTabPayload {
pub(crate) fn decrypt(self, keys: &PrivateSendTabKeysV1) -> Result<SendTabPayload> {
rc_crypto::ensure_initialized();
let encrypted = base64::decode_config(&self.encrypted, base64::URL_SAFE_NO_PAD)?;
let private_key = RcCryptoLocalKeyPair::from_raw_components(&keys.p256key)?;
let decrypted = Aes128GcmEceWebPush::decrypt(&private_key, &keys.auth_secret, &encrypted)?;
let decrypted = ece::decrypt(&keys.p256key, &keys.auth_secret, &encrypted)?;
Ok(serde_json::from_slice(&decrypted)?)
}
}
Expand Down Expand Up @@ -77,14 +75,8 @@ impl SendTabPayload {
rc_crypto::ensure_initialized();
let bytes = serde_json::to_vec(&self)?;
let public_key = base64::decode_config(&keys.public_key, base64::URL_SAFE_NO_PAD)?;
let public_key = RcCryptoRemotePublicKey::from_raw(&public_key)?;
let auth_secret = base64::decode_config(&keys.auth_secret, base64::URL_SAFE_NO_PAD)?;
let encrypted = Aes128GcmEceWebPush::encrypt(
&public_key,
&auth_secret,
&bytes,
WebPushParams::default(),
)?;
let encrypted = ece::encrypt(&public_key, &auth_secret, &bytes)?;
let encrypted = base64::encode_config(&encrypted, base64::URL_SAFE_NO_PAD);
Ok(EncryptedSendTabPayload { encrypted })
}
Expand Down
4 changes: 2 additions & 2 deletions components/push/src/communications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ mod test {
.with_body(body)
.create();
let mut conn = connect(config.clone(), None, None).unwrap();
let channel_id = hex::encode(crate::crypto::get_bytes(16).unwrap());
let channel_id = hex::encode(crate::crypto::get_random_bytes(16).unwrap());
let response = conn.subscribe(&channel_id, None).unwrap();
ap_mock.assert();
assert_eq!(response.uaid, DUMMY_UAID);
Expand All @@ -494,7 +494,7 @@ mod test {
.with_body(body)
.create();
let mut conn = connect(config.clone(), None, None).unwrap();
let channel_id = hex::encode(crate::crypto::get_bytes(16).unwrap());
let channel_id = hex::encode(crate::crypto::get_random_bytes(16).unwrap());
let response = conn.subscribe(&channel_id, None).unwrap();
ap_ns_mock.assert();
assert_eq!(response.uaid, DUMMY_UAID);
Expand Down
32 changes: 14 additions & 18 deletions components/push/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use crate::error;
use rc_crypto::ece::{
Aes128GcmEceWebPush, AesGcmEceWebPush, AesGcmEncryptedBlock, EcKeyComponents, LocalKeyPair,
};
use rc_crypto::ece::{self, EcKeyComponents, LocalKeyPair};
use rc_crypto::ece_crypto::RcCryptoLocalKeyPair;
use rc_crypto::rand;
use serde_derive::*;
Expand All @@ -20,7 +18,7 @@ pub(crate) enum VersionnedKey {

#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct KeyV1 {
p256key: EcKeyComponents,
p256key: ece::EcKeyComponents,
pub auth: Vec<u8>,
}
pub type Key = KeyV1;
Expand Down Expand Up @@ -50,14 +48,12 @@ impl Key {
}
}

pub fn key_pair(&self) -> error::Result<RcCryptoLocalKeyPair> {
RcCryptoLocalKeyPair::from_raw_components(&self.p256key).map_err(|e| {
error::ErrorKind::CryptoError(format!(
"Could not re-create key from components: {:?}",
e
))
.into()
})
pub fn key_pair(&self) -> &ece::EcKeyComponents {
&self.p256key
}

pub fn auth_secret(&self) -> &[u8] {
&self.auth
}

pub fn private_key(&self) -> &[u8] {
Expand Down Expand Up @@ -101,7 +97,7 @@ pub trait Cryptography {

pub struct Crypto;

pub fn get_bytes(size: usize) -> error::Result<Vec<u8>> {
pub fn get_random_bytes(size: usize) -> error::Result<Vec<u8>> {
let mut bytes = vec![0u8; size];
rand::fill(&mut bytes).map_err(|e| {
error::ErrorKind::CryptoError(format!("Could not generate random bytes: {:?}", e))
Expand Down Expand Up @@ -145,7 +141,7 @@ impl Cryptography for Crypto {
let components = key.raw_components().map_err(|e| {
error::ErrorKind::CryptoError(format!("Could not extract key components: {:?}", e))
})?;
let auth = get_bytes(SER_AUTH_LENGTH)?;
let auth = get_random_bytes(SER_AUTH_LENGTH)?;
Ok(Key {
p256key: components,
auth,
Expand Down Expand Up @@ -188,7 +184,6 @@ impl Cryptography for Crypto {
}
}

// IIUC: objects created on one side of FFI can't be freed on the other side, so we have to use references (or clone)
fn decrypt_aesgcm(
key: &Key,
content: &[u8],
Expand All @@ -207,7 +202,8 @@ impl Cryptography for Crypto {
return Err(error::ErrorKind::CryptoError("Missing salt".to_string()).into());
}
};
let block = match AesGcmEncryptedBlock::new(&dh, &salt, 4096, content.to_vec()) {
let block = match ece::legacy::AesGcmEncryptedBlock::new(&dh, &salt, 4096, content.to_vec())
{
Ok(b) => b,
Err(e) => {
return Err(error::ErrorKind::CryptoError(format!(
Expand All @@ -217,12 +213,12 @@ impl Cryptography for Crypto {
.into());
}
};
AesGcmEceWebPush::decrypt(&key.key_pair()?, &key.auth, &block)
ece::legacy::decrypt_aesgcm(key.key_pair(), key.auth_secret(), &block)
.map_err(|_| error::ErrorKind::CryptoError("Decryption error".to_owned()).into())
}

fn decrypt_aes128gcm(key: &Key, content: &[u8]) -> error::Result<Vec<u8>> {
Aes128GcmEceWebPush::decrypt(&key.key_pair()?, &key.auth, &content)
ece::decrypt(key.key_pair(), key.auth_secret(), &content)
.map_err(|_| error::ErrorKind::CryptoError("Decryption error".to_owned()).into())
}
}
Expand Down
4 changes: 2 additions & 2 deletions components/push/src/storage/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ mod test {
use crate::error::Result;

use super::PushDb;
use crate::crypto::get_bytes;
use crate::crypto::get_random_bytes;
use crate::storage::{db::Storage, record::PushRecord};

const DUMMY_UAID: &str = "abad1dea00000000aabbccdd00000000";
Expand All @@ -249,7 +249,7 @@ mod test {
}

fn get_uuid() -> Result<String> {
Ok(get_bytes(16)?
Ok(get_random_bytes(16)?
.iter()
.map(|b| format!("{:02x}", b))
.collect::<Vec<String>>()
Expand Down
6 changes: 1 addition & 5 deletions components/push/src/subscriber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,7 @@ mod test {
let mut pm = PushManager::new(test_config)?;
let (info, key) = pm.subscribe(test_channel_id, "", None)?;
// Act like a subscription provider, so create a "local" key to encrypt the data
let mut auth_secret = vec![0u8; 16];
let mut salt = vec![0u8; 16];
rc_crypto::rand::fill(&mut auth_secret).unwrap();
rc_crypto::rand::fill(&mut salt).unwrap();
let ciphertext = ece::encrypt(&key.public_key(), &key.auth, &salt, data_string).unwrap();
let ciphertext = ece::encrypt(&key.public_key(), &key.auth, data_string).unwrap();
let body = base64::encode_config(&ciphertext, base64::URL_SAFE_NO_PAD);

let result = pm
Expand Down
8 changes: 6 additions & 2 deletions components/support/rc_crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@ license = "MPL-2.0"
crate-type = ["lib"]

[dependencies]
base64 = "0.12"
base64 = "0.13"
thiserror = "1.0"
error-support = { path = "../error" }
nss = { path = "nss" }
hawk = { version = "3.2", default-features = false, optional = true }
ece = { version = "1.2" , default-features = false, features = ["serializable-keys"], optional = true }
ece = { version = "2.0", default-features = false, features = ["serializable-keys"], optional = true }

[dev-dependencies]
hex = "0.4"

[dev-dependencies.ece]
default-features = false
features = ["serializable-keys", "backend-test-helper"]

[features]
default = []
gecko = ["nss/gecko"]
Loading

0 comments on commit ffa7a06

Please sign in to comment.