Skip to content

Commit 5d59544

Browse files
committed
PCS fixes
1 parent f46fbe6 commit 5d59544

File tree

4 files changed

+106
-32
lines changed

4 files changed

+106
-32
lines changed

src/cloudkit.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,12 @@ pub trait CloudKitOp {
101101

102102
pub fn pcs_key_for_record(record: &Record, keys: &PCSKeys) -> Result<PCSKey, PushError> {
103103
let Some(protection) = &record.protection_info else {
104-
return Ok(keys.default_record_key.clone().unwrap())
104+
let Some(pcskey) = &record.pcs_key else { panic!("No PCS Key??") };
105+
let keys = keys.default_record_keys.iter().find(|i| i.key_id().ok().map(|id| pcskey == &id[..pcskey.len()]).unwrap_or(false));
106+
107+
return Ok(keys.ok_or(PushError::PCSRecordKeyMissing)?.clone())
105108
};
106-
keys.decode_record_protection(protection)
109+
Ok(keys.decode_record_protection(protection)?.remove(0))
107110
}
108111

109112
pub struct UploadAssetOperation(pub cloudkit_proto::AssetUploadTokenRetrieveRequest);
@@ -196,7 +199,7 @@ impl SaveRecordOperation {
196199
protection_info_tag: Some(tag.clone()),
197200
protection_info: Some(der),
198201
});
199-
let pcs_key = key.decode_record_protection(protection_info.as_ref().unwrap()).expect("Failed to decode record protection");
202+
let pcs_key = key.decode_record_protection(protection_info.as_ref().unwrap()).expect("Failed to decode record protection").remove(0);
200203

201204
(Self(cloudkit_proto::RecordSaveRequest {
202205
record: Some(cloudkit_proto::Record {
@@ -222,8 +225,8 @@ impl SaveRecordOperation {
222225
r#type: Some(cloudkit_proto::record::Type {
223226
name: Some(R::record_type().to_string())
224227
}),
225-
record_field: record.to_record_encrypted(key.map(|k| (k.default_record_key.as_ref().expect("No default record key?"), &id))),
226-
pcs_key: key.map(|k| k.default_record_key.as_ref().expect("No default record key?").key_id().unwrap()[..4].to_vec()),
228+
record_field: record.to_record_encrypted(key.map(|k| (k.default_record_keys.first().expect("No default record key?"), &id))),
229+
pcs_key: key.map(|k| k.default_record_keys.first().expect("No default record key?").key_id().unwrap()[..4].to_vec()),
227230
..Default::default()
228231
}),
229232
merge: Some(true),
@@ -768,13 +771,13 @@ pub struct QueryResult<T: CloudKitRecord> {
768771
pub struct PCSKeys {
769772
zone_keys: Vec<CompactECKey<Private>>,
770773
zone_protection_tag: Option<String>,
771-
default_record_key: Option<PCSKey>,
774+
default_record_keys: Vec<PCSKey>,
772775
pub record_prot_tag: Option<String>,
773776
}
774777

775778
impl PCSKeys {
776779

777-
fn decode_record_protection(&self, protection: &ProtectionInfo) -> Result<PCSKey, PushError> {
780+
fn decode_record_protection(&self, protection: &ProtectionInfo) -> Result<Vec<PCSKey>, PushError> {
778781
let record_protection: PCSShareProtection = rasn::der::decode(protection.protection_info()).expect("Bad record protection?");
779782
let mut big_num = BigNumContext::new()?;
780783
let record_key = CompactECKey::decompress(record_protection.decode_key_public()?.try_into().expect("Decode key not compact!"));
@@ -816,6 +819,12 @@ impl<'t, T: AnisetteProvider> CloudKitOpenContainer<'t, T> {
816819
}
817820
}
818821

822+
pub async fn clear_cache_zone_encryption_config(&self, zone: &cloudkit_proto::RecordZoneIdentifier) {
823+
let mut cached_keys = self.keys.lock().await;
824+
let zone_name = zone.value.as_ref().unwrap().name().to_string();
825+
cached_keys.remove(&zone_name);
826+
}
827+
819828
pub async fn get_zone_encryption_config(&self, zone: &cloudkit_proto::RecordZoneIdentifier, client: &KeychainClient<T>, pcs_service: &PCSService<'_>) -> Result<PCSKeys, PushError> {
820829
let mut cached_keys = self.keys.lock().await;
821830
let zone_name = zone.value.as_ref().unwrap().name().to_string();
@@ -854,14 +863,14 @@ impl<'t, T: AnisetteProvider> CloudKitOpenContainer<'t, T> {
854863
let mut keys = PCSKeys {
855864
zone_keys: keys,
856865
zone_protection_tag: zone.protection_info.as_ref().unwrap().protection_info_tag.clone(),
857-
default_record_key: None,
866+
default_record_keys: vec![],
858867
record_prot_tag: if let Some(record_protection_info) = &zone.record_protection_info {
859868
record_protection_info.protection_info_tag.clone()
860869
} else { None },
861870
};
862871

863872
if let Some(record_protection_info) = &zone.record_protection_info {
864-
keys.default_record_key = Some(keys.decode_record_protection(record_protection_info)?);
873+
keys.default_record_keys = keys.decode_record_protection(record_protection_info)?;
865874
}
866875

867876
cached_keys.insert(zone_name, keys.clone());

src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,6 @@ pub enum PushError {
177177
BatchError(Arc<PushError>),
178178
#[error("Invalid 2fa code!")]
179179
Bad2FaCode,
180+
#[error("PCS record key id not found!")]
181+
PCSRecordKeyMissing,
180182
}

src/imessage/cloud_messages.rs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -345,29 +345,52 @@ impl Default for NumOrString {
345345
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
346346
#[serde(rename_all = "kebab-case")]
347347
pub struct MMCSAttachmentMeta {
348-
pub mmcs_signature_hex: String,
348+
// MMCS attachments
349+
pub mmcs_signature_hex: Option<String>,
350+
pub mmcs_owner: Option<String>,
351+
pub mmcs_url: Option<String>,
352+
pub decryption_key: Option<String>,
353+
354+
// inline attachments
355+
pub inline_attachment: Option<String>,
356+
pub message_part: Option<String>,
357+
349358
pub file_size: NumOrString,
350-
pub decryption_key: String,
351359
pub uti_type: Option<String>,
352-
pub mmcs_owner: String,
353360
pub mime_type: Option<String>,
354-
pub mmcs_url: String,
355361
pub name: Option<String>,
356362
}
357363

358364

359365
impl Into<Option<MMCSAttachmentMeta>> for &Attachment {
360366
fn into(self) -> Option<MMCSAttachmentMeta> {
361367
match &self.a_type {
362-
AttachmentType::Inline(_inline) => None,
368+
AttachmentType::Inline(_inline) => Some(MMCSAttachmentMeta {
369+
mmcs_signature_hex: None,
370+
decryption_key: None,
371+
mmcs_owner: None,
372+
mmcs_url: None,
373+
374+
inline_attachment: Some("ia-0".to_string()),
375+
message_part: Some("0".to_string()),
376+
377+
file_size: NumOrString::Num(_inline.len() as u32),
378+
uti_type: Some(self.uti_type.clone()),
379+
mime_type: Some(self.mime.clone()),
380+
name: Some(self.name.clone())
381+
}),
363382
AttachmentType::MMCS(mmcs) => Some(MMCSAttachmentMeta {
364-
mmcs_signature_hex: encode_hex(&mmcs.signature),
383+
mmcs_signature_hex: Some(encode_hex(&mmcs.signature)),
384+
decryption_key: Some(encode_hex(&mmcs.key)),
385+
mmcs_owner: Some(mmcs.object.clone()),
386+
mmcs_url: Some(mmcs.url.clone()),
387+
388+
inline_attachment: None,
389+
message_part: None,
390+
365391
file_size: NumOrString::Num(mmcs.size as u32),
366-
decryption_key: encode_hex(&mmcs.key),
367392
uti_type: Some(self.uti_type.clone()),
368-
mmcs_owner: mmcs.object.clone(),
369393
mime_type: Some(self.mime.clone()),
370-
mmcs_url: mmcs.url.clone(),
371394
name: Some(self.name.clone())
372395
})
373396
}
@@ -399,7 +422,7 @@ pub struct AttachmentMeta {
399422
#[serde(rename = "ui")]
400423
pub user_info: Option<MMCSAttachmentMeta>,
401424
#[serde(rename = "fn")]
402-
pub filename: String, //path
425+
pub filename: Option<String>, //path
403426
#[serde(rename = "aui")]
404427
pub extras: Option<AttachmentMetaExtra>,
405428
#[serde(rename = "ig")]
@@ -479,7 +502,15 @@ impl<P: AnisetteProvider> CloudMessagesClient<P> {
479502
};
480503
if record.r#type.as_ref().unwrap().name() != T::record_type() { continue }
481504

482-
let item = T::from_record_encrypted(&record.record_field, Some((&pcs_key_for_record(&record, &key)?, record.record_identifier.as_ref().unwrap())));
505+
let pcskey = match pcs_key_for_record(&record, &key) {
506+
Ok(key) => key,
507+
Err(PushError::PCSRecordKeyMissing) => {
508+
container.clear_cache_zone_encryption_config(&zone).await;
509+
return Err(PushError::PCSRecordKeyMissing)
510+
},
511+
Err(e) => return Err(e)
512+
};
513+
let item = T::from_record_encrypted(&record.record_field, Some((&pcskey, record.record_identifier.as_ref().unwrap())));
483514

484515
results.insert(identifier, Some(item));
485516
}
@@ -543,6 +574,7 @@ impl<P: AnisetteProvider> CloudMessagesClient<P> {
543574
ZoneDeleteOperation::new(container.private_zone("chatManateeZone".to_string())),
544575
ZoneDeleteOperation::new(container.private_zone("messageManateeZone".to_string())),
545576
ZoneDeleteOperation::new(container.private_zone("attachmentManateeZone".to_string())),
577+
ZoneDeleteOperation::new(container.private_zone("chat1ManateeZone".to_string())),
546578
], IsolationLevel::Operation).await?;
547579
Ok(())
548580
}

src/pcs.rs

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ impl PCSPrivateKey {
311311
pub fn from_dict(dict: &Dictionary, keychain: &KeychainClientState) -> Self {
312312
let key = dict.get("v_Data").expect("No dat?").as_data().expect("Not data");
313313

314-
let decoded: PCSPrivateKey = rasn::der::decode(&key).unwrap();
314+
let decoded: PCSPrivateKey = rasn::der::decode(&key).expect("Failed to decode private key!");
315315

316316
if !decoded.verify_with_keychain(keychain, dict.get("atyp").expect("No dat?").as_data().expect("Not data")).unwrap() {
317317
panic!("PCS Master key verification failed!");
@@ -559,6 +559,8 @@ impl PCSShareProtectionKeySet {
559559

560560
#[derive(AsnType, Encode, Decode)]
561561
pub struct PCSShareProtectionIdentities {
562+
#[rasn(tag(explicit(context, 0)))]
563+
symm_keys: Option<SetOf<rasn::types::OctetString>>,
562564
#[rasn(tag(explicit(context, 1)))]
563565
tag1: PCSShareProtectionIdentitiesTag1,
564566
#[rasn(tag(explicit(context, 2)))]
@@ -567,8 +569,11 @@ pub struct PCSShareProtectionIdentities {
567569

568570
impl PCSShareProtection {
569571
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
570575
let data = self.attributes.iter().find(|a| a.key == 5).expect("No signature data");
571-
rasn::der::decode(&data.value).expect("failed to decode")
576+
rasn::der::decode(&data.value).expect("failed to decode signature data")
572577
}
573578

574579
fn digest_data(&self, objsig: &PCSObjectSignature) -> Vec<u8> {
@@ -577,12 +582,15 @@ impl PCSShareProtection {
577582
&self.meta[..],
578583
&objsig.unk2.to_be_bytes(),
579584
&objsig.unk1.to_be_bytes(),
580-
&0u32.to_be_bytes(),
585+
&objsig.symm_key_count.unwrap_or(0).to_be_bytes(),
581586
&objsig.public.keytype.to_be_bytes(),
582587
&objsig.public.pub_key[..],
583588
].concat();
584-
if let Some(keylist) = &objsig.keylist {
585-
data.extend_from_slice(&rasn::der::encode(keylist).unwrap());
589+
if let Some(attributes) = &objsig.attributes {
590+
data.extend_from_slice(&rasn::der::encode(attributes).unwrap());
591+
}
592+
if let Some(ec_key_list) = &objsig.ec_key_list {
593+
data.extend_from_slice(&rasn::der::encode(ec_key_list).unwrap());
586594
}
587595
data
588596
}
@@ -599,7 +607,7 @@ impl PCSShareProtection {
599607
Ok(self.keyset.keyset.first().unwrap().decryption_key.pub_key.to_vec())
600608
}
601609

602-
pub fn decrypt_with_keychain(&self, keychain: &KeychainClientState, service: &PCSService<'_>) -> Result<(PCSKey, Vec<CompactECKey<Private>>), PushError> {
610+
pub fn decrypt_with_keychain(&self, keychain: &KeychainClientState, service: &PCSService<'_>) -> Result<(Vec<PCSKey>, Vec<CompactECKey<Private>>), PushError> {
603611
info!("Decoding with {}", base64_encode(&self.decode_key_public()?));
604612
let account = Value::String(base64_encode(&self.decode_key_public()?));
605613
let item = keychain.items[service.zone].keys.values().find(|x| x.get("acct").expect("No acct?") == &account).ok_or(PushError::ShareKeyNotFound)?;
@@ -624,6 +632,7 @@ impl PCSShareProtection {
624632
keyset.make_checksum();
625633

626634
let identities = PCSShareProtectionIdentities {
635+
symm_keys: None,
627636
tag1: Default::default(),
628637
identities: if keys.is_empty() { None } else { Some(BTreeSet::from_iter([
629638
PCSShareProtectionIdentityData {
@@ -666,10 +675,13 @@ impl PCSShareProtection {
666675
pub_key: master_ec_key.public_key().to_bytes(master_ec_key.group(), PointConversionForm::UNCOMPRESSED, &mut num_ctx)?.into(),
667676
},
668677
signature: Default::default(),
669-
keylist: if keys.is_empty() { None } else { Some(keys.iter().map(|k| PCSKeyRef {
678+
ec_key_list: if keys.is_empty() { None } else { Some(keys.iter().map(|k| PCSKeyRef {
670679
keytype: 3,
671680
pub_key: k.compress().to_vec().into(),
672-
}).collect()) }
681+
}).collect()) },
682+
symm_key_count: None,
683+
signature_2: None,
684+
attributes: None,
673685
};
674686

675687
let digest_data = protection.digest_data(&signature);
@@ -705,7 +717,8 @@ impl PCSShareProtection {
705717
Ok(protection)
706718
}
707719

708-
pub fn decode(&self, key: &CompactECKey<Private>) -> Result<(PCSKey, Vec<CompactECKey<Private>>), PushError> {
720+
pub fn decode(&self, key: &CompactECKey<Private>) -> Result<(Vec<PCSKey>, Vec<CompactECKey<Private>>), PushError> {
721+
info!("Decoding share protection!");
709722
let master_key = PCSKey::new(key, &self.keyset.keyset.first().unwrap().ciphertext)?;
710723

711724
let sig = self.signature_data();
@@ -723,7 +736,15 @@ impl PCSShareProtection {
723736
let mut verifier = Verifier::new(MessageDigest::sha256(), &key)?;
724737
verifier.update(&digest_data)?;
725738
if !verifier.verify(&sig.signature.signature)? {
726-
panic!("self sig check failed")
739+
if let Some(past_signature) = &sig.signature_2 {
740+
let mut verifier = Verifier::new(MessageDigest::sha256(), &key)?;
741+
verifier.update(&digest_data)?;
742+
if !verifier.verify(&past_signature.signature)? {
743+
panic!("self sig 1 and 2 check failed")
744+
}
745+
} else {
746+
panic!("self sig check failed")
747+
}
727748
}
728749

729750
let hmackey = kdf_ctr_hmac(&master_key.0, "hmackey-of-masterkey".as_bytes(), &[], master_key.0.len());
@@ -747,7 +768,10 @@ impl PCSShareProtection {
747768
}
748769
}
749770

750-
Ok((master_key, keys))
771+
let mut pcs_keys = vec![master_key];
772+
pcs_keys.extend(identities.symm_keys.unwrap_or_default().into_iter().map(|symm| PCSKey(symm.to_vec())));
773+
774+
Ok((pcs_keys, keys))
751775
}
752776
}
753777

@@ -758,6 +782,13 @@ pub struct PCSObjectSignature {
758782
unk2: u32,
759783
public: PCSKeyRef,
760784
signature: PCSSignature,
785+
// the ignore fields show up in weird situations, when there are multiple keys?
786+
#[rasn(tag(explicit(context, 0)))]
787+
symm_key_count: Option<u32>,
788+
#[rasn(tag(explicit(context, 1)))]
789+
signature_2: Option<PCSSignature>,
761790
#[rasn(tag(explicit(context, 2)))]
762-
keylist: Option<SequenceOf<PCSKeyRef>>,
791+
ec_key_list: Option<SequenceOf<PCSKeyRef>>,
792+
#[rasn(tag(explicit(context, 3)))]
793+
attributes: Option<SequenceOf<PCSAttribute>>,
763794
}

0 commit comments

Comments
 (0)