Skip to content

Commit bc75110

Browse files
committed
PCS fixes
1 parent d7f4aa1 commit bc75110

File tree

3 files changed

+52
-30
lines changed

3 files changed

+52
-30
lines changed

src/keychain.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ impl EncodedPeer {
638638
pub fn get_peer_info(&self) -> Result<PeerPermanentInfo, PushError> {
639639

640640

641-
let signed_info = self.0.permanent_info.as_ref().unwrap();
641+
let signed_info = self.0.permanent_info.as_ref().expect("Permanent info not found");
642642
// make sure they are who they say they are
643643
let computed_hash = format!("SHA256:{}", base64_encode(&sha256(&[signed_info.info(), signed_info.signature()].concat())));
644644
let represented_hash = self.0.hash.as_ref().unwrap();
@@ -693,11 +693,11 @@ impl EncodedPeer {
693693
}
694694

695695
fn get_stable_info(&self) -> Result<PeerStableInfo, PushError> {
696-
self.check_payload(self.0.stable_info.as_ref().unwrap(), "TPPB.PeerStableInfo")
696+
self.check_payload(self.0.stable_info.as_ref().expect("Stable info not found"), "TPPB.PeerStableInfo")
697697
}
698698

699699
fn get_dynamic_info(&self) -> Result<PeerDynamicInfo, PushError> {
700-
self.check_payload(self.0.dynamic_info.as_ref().unwrap(), "TPPB.PeerDynamicInfo")
700+
self.check_payload(self.0.dynamic_info.as_ref().expect("Dynamic info not found!"), "TPPB.PeerDynamicInfo")
701701
}
702702

703703
fn get_voucher_unchecked(&self) -> Result<Option<(Voucher, SignedInfo)>, PushError> {
@@ -911,6 +911,11 @@ impl KeychainClientState {
911911
items: HashMap::new(),
912912
})
913913
}
914+
915+
// filter out custodian recovery keys
916+
pub fn peers(&self) -> impl Iterator<Item = &EncodedPeer> {
917+
self.state.values().filter(|v| v.0.dynamic_info.is_some())
918+
}
914919
}
915920

916921
pub const KEYCHAIN_ZONES: &[&str] = &[
@@ -1180,7 +1185,10 @@ impl<P: AnisetteProvider> KeychainClient<P> {
11801185
let identifier = change.identifier.as_ref().unwrap().value.as_ref().unwrap().name().to_string();
11811186
if record.r#type.as_ref().unwrap().name() == CuttlefishEncItem::record_type() {
11821187
let item = CuttlefishEncItem::from_record(&record.record_field);
1183-
let decoded = item.decrypt(&identifier, &record, &state.keystore)?;
1188+
let Ok(decoded) = item.decrypt(&identifier, &record, &state.keystore) else {
1189+
warn!("Missing decryption key for {}", identifier);
1190+
continue;
1191+
};
11841192

11851193
saved_keychain_zone.keys.insert(identifier, decoded);
11861194
} else if record.r#type.as_ref().unwrap().name() == CuttlefishCurrentItem::record_type() {
@@ -1318,6 +1326,10 @@ impl<P: AnisetteProvider> KeychainClient<P> {
13181326
info!("Syncing trust!");
13191327

13201328
let mut state = self.state.write().await;
1329+
if state.user_identity.is_none() {
1330+
info!("No user identity!");
1331+
return Ok(())
1332+
}
13211333

13221334
if !state.state.contains_key(&state.user_identity.as_ref().unwrap().identifier) {
13231335
info!("We are not in the clique!");
@@ -1351,7 +1363,7 @@ impl<P: AnisetteProvider> KeychainClient<P> {
13511363
// sync up our identity
13521364
let mut current_state = state.user_identity.as_ref().unwrap().current_state.clone();
13531365

1354-
let mut forward = state.state.values()
1366+
let mut forward = state.peers()
13551367
.filter_map(|d| Some((d.clone(), d.get_dynamic_info().ok()?)))
13561368
.filter(|d| d.1.clock() > current_state.clock()) // peers with newer info
13571369
.collect::<Vec<_>>();
@@ -1612,7 +1624,7 @@ impl<P: AnisetteProvider> KeychainClient<P> {
16121624

16131625
pub fn generate_stable_info(&self, state: &KeychainClientState) -> PeerStableInfo {
16141626
// maximum clock between all our peers
1615-
let next_stable_clock = state.state.values().filter_map(|d| d.get_stable_info().ok().map(|a| a.clock())).max().unwrap_or(0) + 1;
1627+
let next_stable_clock = state.peers().filter_map(|d| d.get_stable_info().ok().map(|a| a.clock())).max().unwrap_or(0) + 1;
16161628
PeerStableInfo {
16171629
clock: Some(next_stable_clock),
16181630
frozen_policy_version: Some(5),

src/pcs.rs

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ impl PCSPrivateKey {
353353
public.verify(&self.signing_key())
354354
} else {
355355
let account = Value::Data(signature.keyid.to_vec());
356-
let item = keychain.items["ProtectedCloudStorage"].keys.values().find(|x| x.get("atyp").expect("No atyp?") == &account).unwrap();
356+
let item = keychain.items["ProtectedCloudStorage"].keys.values().find(|x| x.get("atyp") == Some(&account)).unwrap();
357357
let key = item.get("v_Data").expect("No dat?").as_data().expect("Not data");
358358

359359
let decoded: PCSPrivateKey = rasn::der::decode(&key).unwrap();
@@ -369,19 +369,20 @@ impl PCSPrivateKey {
369369
}
370370
}
371371

372-
#[derive(AsnType, Encode, Decode, PartialEq, Eq, PartialOrd, Ord)]
372+
#[derive(AsnType, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Debug)]
373373
pub struct PCSKeyRef {
374374
keytype: u32,
375375
pub_key: rasn::types::OctetString,
376376
}
377377

378-
#[derive(AsnType, Encode, Decode, PartialEq, Eq, PartialOrd, Ord)]
378+
#[derive(AsnType, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Debug)]
379379
pub struct PCSShareKey {
380380
decryption_key: PCSKeyRef,
381381
ciphertext: rasn::types::OctetString,
382+
unk1: Option<u32>,
382383
}
383384

384-
#[derive(AsnType, Encode, Decode)]
385+
#[derive(AsnType, Encode, Decode, Debug)]
385386
pub struct PCSKeySet {
386387
unk1: u32, // 0
387388
keyset: SetOf<PCSShareKey>,
@@ -391,8 +392,6 @@ pub struct PCSKeySet {
391392
pub struct PCSKey(Vec<u8>);
392393
impl PCSKey {
393394
fn new(eckey: &CompactECKey<Private>, wrapped: &[u8]) -> Result<Self, PushError> {
394-
// do this computation with decrypted if [1] first integer is not 5
395-
// let master_key = kdf_ctr_hmac(&rm_master_key, "MsaeEooevaX fooo 012".as_bytes(), &[], rm_master_key.len());
396395
Ok(Self(rfc6637_unwrap_key(eckey, &wrapped, "fingerprint".as_bytes())?))
397396
}
398397

@@ -505,14 +504,23 @@ impl CloudKitEncryptor for PCSKey {
505504
}
506505
}
507506

508-
#[derive(AsnType, Encode, Decode)]
507+
#[derive(AsnType, Encode, Decode, Debug, Default)]
508+
pub struct PCSShareProtectionSignatureData {
509+
// 5 is the version. non-exist is 1, 5 is 2, 4 is 3,
510+
// classic is 2
511+
// share is 3
512+
version: u32,
513+
data: rasn::types::OctetString,
514+
}
515+
516+
#[derive(AsnType, Encode, Decode, Debug)]
509517
#[rasn(tag(explicit(application, 1)))]
510518
pub struct PCSShareProtection {
511519
keyset: PCSKeySet,
512520
#[rasn(tag(explicit(context, 0)))]
513521
meta: rasn::types::OctetString, // encrypted
514-
#[rasn(tag(context, 1))]
515-
attributes: SequenceOf<PCSAttribute>, // not sure this should be a sequence, maybe tag should be explicit, not sure
522+
#[rasn(tag(explicit(context, 1)))]
523+
attributes: PCSShareProtectionSignatureData, // not sure this should be a sequence, maybe tag should be explicit, not sure
516524
hmac: rasn::types::OctetString,
517525
#[rasn(tag(explicit(context, 2)))]
518526
truncated_key_id: rasn::types::OctetString,
@@ -569,11 +577,7 @@ pub struct PCSShareProtectionIdentities {
569577

570578
impl PCSShareProtection {
571579
fn signature_data(&self) -> PCSObjectSignature {
572-
// 5 is the version. non-exist is 1, 5 is 2, 4 is 3,
573-
// classic is 2
574-
// share is 3
575-
let data = self.attributes.iter().find(|a| a.key == 5).expect("No signature data");
576-
rasn::der::decode(&data.value).expect("failed to decode signature data")
580+
rasn::der::decode(&self.attributes.data).expect("failed to decode signature data")
577581
}
578582

579583
fn digest_data(&self, objsig: &PCSObjectSignature) -> Vec<u8> {
@@ -604,13 +608,13 @@ impl PCSShareProtection {
604608
}
605609

606610
pub fn decode_key_public(&self) -> Result<Vec<u8>, PushError> {
607-
Ok(self.keyset.keyset.first().unwrap().decryption_key.pub_key.to_vec())
611+
Ok(self.keyset.keyset.first().expect("No public keyset! (bad decoding?)").decryption_key.pub_key.to_vec())
608612
}
609613

610614
pub fn decrypt_with_keychain(&self, keychain: &KeychainClientState, service: &PCSService<'_>) -> Result<(Vec<PCSKey>, Vec<CompactECKey<Private>>), PushError> {
611615
info!("Decoding with {}", base64_encode(&self.decode_key_public()?));
612616
let account = Value::String(base64_encode(&self.decode_key_public()?));
613-
let item = keychain.items[service.zone].keys.values().find(|x| x.get("acct").expect("No acct?") == &account).ok_or(PushError::ShareKeyNotFound)?;
617+
let item = keychain.items[service.zone].keys.values().find(|x| x.get("acct") == Some(&account)).ok_or(PushError::ShareKeyNotFound)?;
614618
let decoded = PCSPrivateKey::from_dict(item, keychain);
615619

616620
let key = decoded.key();
@@ -654,11 +658,12 @@ impl PCSShareProtection {
654658
pub_key: encrypt.compress().to_vec().into(),
655659
},
656660
ciphertext: master_key.wrap(encrypt)?.into(),
661+
unk1: None,
657662
}
658663
])
659664
},
660665
meta: encrypted.into(),
661-
attributes: vec![],
666+
attributes: Default::default(),
662667
hmac: Default::default(),
663668
truncated_key_id: master_key.key_id()?[..4].to_vec().into(),
664669
signature: Default::default(),
@@ -695,10 +700,10 @@ impl PCSShareProtection {
695700
signature: signer.sign_to_vec()?.into(),
696701
};
697702

698-
protection.attributes.push(PCSAttribute {
699-
key: 5,
700-
value: rasn::der::encode(&signature).unwrap().into(),
701-
});
703+
protection.attributes = PCSShareProtectionSignatureData {
704+
version: 5,
705+
data: rasn::der::encode(&signature).unwrap().into(),
706+
};
702707

703708

704709
let key = encrypt.get_pkey();
@@ -719,7 +724,7 @@ impl PCSShareProtection {
719724

720725
pub fn decode(&self, key: &CompactECKey<Private>) -> Result<(Vec<PCSKey>, Vec<CompactECKey<Private>>), PushError> {
721726
info!("Decoding share protection!");
722-
let master_key = PCSKey::new(key, &self.keyset.keyset.first().unwrap().ciphertext)?;
727+
let rm_master_key = PCSKey::new(key, &self.keyset.keyset.first().unwrap().ciphertext)?;
723728

724729
let sig = self.signature_data();
725730

@@ -732,7 +737,7 @@ impl PCSShareProtection {
732737
panic!("sig check failed")
733738
}
734739

735-
let key = PKey::from_ec_key(master_key.master_ec_key()?)?;
740+
let key = PKey::from_ec_key(rm_master_key.master_ec_key()?)?;
736741
let mut verifier = Verifier::new(MessageDigest::sha256(), &key)?;
737742
verifier.update(&digest_data)?;
738743
if !verifier.verify(&sig.signature.signature)? {
@@ -747,6 +752,11 @@ impl PCSShareProtection {
747752
}
748753
}
749754

755+
let mut master_key = rm_master_key.clone();
756+
if self.attributes.version != 5 {
757+
master_key = PCSKey(kdf_ctr_hmac(&rm_master_key.0, "MsaeEooevaX fooo 012".as_bytes(), &[], rm_master_key.0.len()));
758+
}
759+
750760
let hmackey = kdf_ctr_hmac(&master_key.0, "hmackey-of-masterkey".as_bytes(), &[], master_key.0.len());
751761
let hmac = PKey::hmac(&hmackey)?;
752762
let signature = Signer::new(MessageDigest::sha256(), &hmac).unwrap().sign_oneshot_to_vec(&self.hmac_data()).unwrap();

src/util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ fn build_proxy() -> Client {
8787

8888

8989
pub static REQWEST: LazyLock<Client> = LazyLock::new(|| {
90-
return build_proxy();
90+
// return build_proxy();
9191
let certificates = vec![
9292
Certificate::from_pem(include_bytes!("../certs/root/profileidentity.ess.apple.com.cert")).unwrap(),
9393
Certificate::from_pem(include_bytes!("../certs/root/init.ess.apple.com.cert")).unwrap(),

0 commit comments

Comments
 (0)