Skip to content

Commit b2996d5

Browse files
committed
Fixes
1 parent a7fab47 commit b2996d5

3 files changed

Lines changed: 201 additions & 50 deletions

File tree

src/aps.rs

Lines changed: 157 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ impl APSPackedEncoder {
237237
} else {
238238
// search in tag cache
239239
if let Some(existing) = self.key_table.get_buf_idx(&attribute.id) {
240-
self.write_tagged_value(5, existing as u64, 0x20 | flags, writer)?;
240+
info!("Using kcache {existing}");
241+
writer.write_all(&[0x20 | flags | existing as u8])?;
241242
} else {
242243
self.write_tagged_value(4, attribute.id.len() as u64 - 1, 0x10 | flags, writer)?;
243244

@@ -248,6 +249,7 @@ impl APSPackedEncoder {
248249

249250
// actually write the value
250251
if let Some(existing) = existing {
252+
info!("Using vcache {existing}");
251253
self.write_tagged_value(8, existing as u64, 0, writer)?;
252254
} else if let Some(cached_buf) = cached_buf {
253255
writer.write_all(&cached_buf)?;
@@ -945,6 +947,148 @@ impl APSMessage {
945947
}
946948

947949

950+
#[tokio::test]
951+
async fn replay_test() {
952+
use keystore::{init_keystore, software::{SoftwareKeystore, NoEncryptor}};
953+
init_keystore(SoftwareKeystore {
954+
state: plist::from_file("jerrytest/keystore.plist").unwrap(),
955+
update_state: Box::new(|state| {
956+
plist::to_file_xml("jerrytest/keystore.plist", state).unwrap();
957+
}),
958+
encryptor: NoEncryptor,
959+
});
960+
961+
if let Err(_) = std::env::var("RUST_LOG") {
962+
std::env::set_var("RUST_LOG", "debug");
963+
}
964+
let _ = pretty_env_logger::try_init();
965+
966+
let state_path = std::env::var("APS_REPLAY_STATE")
967+
.unwrap_or_else(|_| if std::path::Path::new("jerrytest/push.plist").exists() {
968+
"jerrytest/push.plist".to_string()
969+
} else {
970+
"jerrytest/push.plist".to_string()
971+
});
972+
let log_path = std::env::var("APS_REPLAY_LOG")
973+
.unwrap_or_else(|_| if std::path::Path::new("jerrytest/replaytest.log").exists() {
974+
"jerrytest/replaytest.log".to_string()
975+
} else {
976+
"jerrytest/replaytest.log".to_string()
977+
});
978+
979+
let mut state: APSState = plist::from_file(&state_path).unwrap();
980+
let pair = state.keypair.as_ref().expect("replay APS state must already contain a keypair");
981+
982+
let (socket, encoder, mut decoder) = open_socket().await.unwrap();
983+
let (mut read, write) = split(socket);
984+
let (send, _) = tokio::sync::broadcast::channel(999);
985+
let socket = Arc::new(DebugMutex::new(Some((write, encoder))));
986+
987+
let reader_send = send.clone();
988+
let mut reader = task::spawn(async move {
989+
loop {
990+
match APSMessage::read_from_stream(&mut read, &mut decoder).await {
991+
Ok(Some(msg)) => {
992+
let _ = reader_send.send(msg);
993+
},
994+
Ok(None) => {},
995+
Err(err) => {
996+
return Err(err);
997+
}
998+
};
999+
}
1000+
1001+
#[allow(unreachable_code)]
1002+
Ok::<(), PushError>(())
1003+
});
1004+
1005+
let nonce = generate_nonce(NonceType::APNS);
1006+
let signature = do_ids_signature(&pair.private, &nonce).unwrap();
1007+
let mut recv = send.subscribe();
1008+
replay_send(&socket, APSMessage::Connect {
1009+
flags: 0b01000001,
1010+
certificate: Some(pair.cert.clone()),
1011+
nonce: Some(nonce),
1012+
signature: Some(signature),
1013+
token: state.token,
1014+
}).await.unwrap();
1015+
1016+
let (token, status) = tokio::time::timeout(Duration::from_secs(15), async {
1017+
loop {
1018+
if let APSMessage::ConnectResponse { token, status } = recv.recv().await.unwrap() {
1019+
return (token, status);
1020+
}
1021+
}
1022+
}).await.unwrap();
1023+
1024+
assert_eq!(status, 0, "APS connect failed with status {status}");
1025+
if let Some(token) = token {
1026+
state.token = Some(token);
1027+
}
1028+
1029+
let replay = std::fs::read_to_string(&log_path).unwrap();
1030+
let mut sent = 0usize;
1031+
let mut skipped_first_send = false;
1032+
for (line_index, line) in replay.lines().enumerate() {
1033+
let Some((_, rest)) = line.split_once("Sending \"") else {
1034+
continue;
1035+
};
1036+
if !skipped_first_send {
1037+
skipped_first_send = true;
1038+
continue;
1039+
}
1040+
if sent >= 0 {
1041+
break;
1042+
}
1043+
let Some((hex, _)) = rest.split_once('"') else {
1044+
panic!("bad Sending line {}: missing closing quote", line_index + 1);
1045+
};
1046+
info!("Sending {}", sent + 1);
1047+
let bytes = decode_hex(hex).unwrap();
1048+
let message: APSMessage = plist::from_bytes(&bytes).unwrap();
1049+
replay_send(&socket, message).await.unwrap();
1050+
sent += 1;
1051+
}
1052+
1053+
assert!(skipped_first_send, "no Sending lines found in {log_path}");
1054+
info!("replayed {sent} APS messages from {log_path}");
1055+
1056+
tokio::select! {
1057+
result = &mut reader => {
1058+
match result {
1059+
Ok(Ok(())) => panic!("replay APS reader ended before observation window ended"),
1060+
Ok(Err(err)) => panic!("replay APS reader stopped before observation window ended: {err}"),
1061+
Err(err) => panic!("replay APS reader task failed before observation window ended: {err}"),
1062+
}
1063+
}
1064+
_ = tokio::time::sleep(Duration::from_secs(5)) => {}
1065+
}
1066+
1067+
reader.abort();
1068+
}
1069+
1070+
#[cfg(test)]
1071+
async fn replay_send(
1072+
socket: &DebugMutex<Option<(WriteHalf<TlsStream<TcpStream>>, Option<APSPackedEncoder>)>>,
1073+
message: APSMessage,
1074+
) -> Result<(), PushError> {
1075+
let mut socket_guard = socket.lock().await;
1076+
let socket = socket_guard.as_mut().ok_or(PushError::NotConnected)?;
1077+
if let Some(encoder) = &mut socket.1 {
1078+
let mut buf = vec![];
1079+
encoder.encode_message(message.to_packed_raw(), Cursor::new(&mut buf))?;
1080+
socket.0.write_all(&buf).await?;
1081+
} else {
1082+
let mut raw = message.to_raw();
1083+
for message in &mut raw.body {
1084+
message.update()?;
1085+
}
1086+
raw.update()?;
1087+
socket.0.write_all(&raw.to_bytes()?).await?;
1088+
}
1089+
Ok(())
1090+
}
1091+
9481092
#[tokio::test]
9491093
async fn proxy() {
9501094
if let Err(_) = std::env::var("RUST_LOG") {
@@ -1092,11 +1236,16 @@ async fn open_socket() -> Result<(TlsStream<TcpStream>, Option<APSPackedEncoder>
10921236
if let Some(protocol) = stream.get_ref().1.alpn_protocol() {
10931237
let protocol = std::str::from_utf8(protocol).unwrap();
10941238
if protocol.starts_with("apns-pack-v1") {
1095-
let mut parts = protocol.split(":");
1096-
let encoder_count: usize = parts.nth(1).expect("Bad ALPN1!").parse().expect("Bad alpn3!");
1097-
let decoder_count: usize = parts.next().expect("Bad ALPN2!").parse().expect("Bad alpn4!");
1098-
encoder = Some(APSPackedEncoder::new_with_cache_size(encoder_count));
1099-
decoder = Some(APSPackedDecoder::new_with_cache_size(decoder_count));
1239+
if protocol.contains(":") {
1240+
let mut parts = protocol.split(":");
1241+
let encoder_count: usize = parts.nth(1).expect("Bad ALPN1!").parse().expect("Bad alpn3!");
1242+
let decoder_count: usize = parts.next().expect("Bad ALPN2!").parse().expect("Bad alpn4!");
1243+
encoder = Some(APSPackedEncoder::new_with_cache_size(encoder_count));
1244+
decoder = Some(APSPackedDecoder::new_with_cache_size(decoder_count));
1245+
} else {
1246+
encoder = Some(APSPackedEncoder::default());
1247+
decoder = Some(APSPackedDecoder::default());
1248+
}
11001249
}
11011250
}
11021251

@@ -1387,7 +1536,8 @@ impl APSConnectionResource {
13871536

13881537
let mut buf = vec![];
13891538
encoder.encode_message(message.to_packed_raw(), Cursor::new(&mut buf))?;
1390-
1539+
1540+
debug!("Sendin2g {:?}", encode_hex(&buf));
13911541
socket.0.write_all(&buf).await
13921542
} else {
13931543
let mut raw = message.to_raw();

src/statuskit.rs

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -716,59 +716,60 @@ impl<T: AnisetteProvider + Send + Sync + 'static> StatusKitClient<T> {
716716
}
717717

718718
pub async fn handle(&self, msg: APSMessage) -> Result<Option<StatusKitMessage>, PushError> {
719-
let APSMessage::Notification { id: _, topic, token: _, payload: Value::Data(payload), channel } = msg.clone() else { return Ok(None) };
720-
if let Some(channel) = &channel {
721-
let mut state = self.state.write().await;
722-
if let Some(local_channel) = state.recent_channels.iter_mut().find(|c| c.identifier.id == channel.id && sha1(c.identifier.topic.as_bytes()) == topic) {
723-
local_channel.last_msg_ns = channel.last_msg_ns;
724-
(self.update_state)(&state);
719+
if let APSMessage::Notification { id: _, topic, token: _, payload: Value::Data(payload), channel } = msg.clone() {
720+
if let Some(channel) = &channel {
721+
let mut state = self.state.write().await;
722+
if let Some(local_channel) = state.recent_channels.iter_mut().find(|c| c.identifier.id == channel.id && sha1(c.identifier.topic.as_bytes()) == topic) {
723+
local_channel.last_msg_ns = channel.last_msg_ns;
724+
(self.update_state)(&state);
725+
}
725726
}
726-
}
727727

728-
if topic == sha1("com.apple.icloud.presence.mode.status".as_bytes()) {
729-
let result: StatusKitOuterMessage = serde_json::from_slice(&payload)?;
730-
let inner: StatusKitInnerMessage = plist::from_bytes(&base64_decode(&result.status_kit_data_key))?;
728+
if topic == sha1("com.apple.icloud.presence.mode.status".as_bytes()) {
729+
let result: StatusKitOuterMessage = serde_json::from_slice(&payload)?;
730+
let inner: StatusKitInnerMessage = plist::from_bytes(&base64_decode(&result.status_kit_data_key))?;
731731

732-
733-
let Some(channel) = &channel else { return Ok(None) };
734-
debug!("Got statuskit message {inner:?} on channel {}", encode_hex(&channel.id));
735-
let mut state = self.state.write().await;
736-
let Some(referenced_channel) = state.keys.get_mut(&base64_encode(&channel.id)) else { panic!("Channel not found!") };
732+
733+
let Some(channel) = &channel else { return Ok(None) };
734+
debug!("Got statuskit message {inner:?} on channel {}", encode_hex(&channel.id));
735+
let mut state = self.state.write().await;
736+
let Some(referenced_channel) = state.keys.get_mut(&base64_encode(&channel.id)) else { panic!("Channel not found!") };
737737

738-
let key = referenced_channel.get_key(inner.ratchet)?;
738+
let key = referenced_channel.get_key(inner.ratchet)?;
739739

740-
let message = base64_decode(&inner.encrypted_message);
741-
referenced_channel.signature.verify(MessageDigest::sha256(), &message, base64_decode(&inner.signature).try_into().expect("Bad signature length!"))?;
740+
let message = base64_decode(&inner.encrypted_message);
741+
referenced_channel.signature.verify(MessageDigest::sha256(), &message, base64_decode(&inner.signature).try_into().expect("Bad signature length!"))?;
742742

743-
let key = key.message_key();
743+
let key = key.message_key();
744744

745-
let cipher = Aes256Gcm::new_from_slice(&key).expect("GCM key creation failed");
746-
let plaintext = cipher.decrypt(Nonce::from_slice(&message[..12]), aes_gcm::aead::Payload {
747-
msg: &message[12..],
748-
aad: &referenced_channel.signature.compress()
749-
}).expect("Failed to decrypt");
745+
let cipher = Aes256Gcm::new_from_slice(&key).expect("GCM key creation failed");
746+
let plaintext = cipher.decrypt(Nonce::from_slice(&message[..12]), aes_gcm::aead::Payload {
747+
msg: &message[12..],
748+
aad: &referenced_channel.signature.compress()
749+
}).expect("Failed to decrypt");
750750

751-
let status = PublishedStatus::decode(Cursor::new(&plaintext))?;
752-
let status: StatusKitStatus = plist::from_bytes(&status.message)?;
751+
let status = PublishedStatus::decode(Cursor::new(&plaintext))?;
752+
let status: StatusKitStatus = plist::from_bytes(&status.message)?;
753753

754-
let user = referenced_channel.from.clone();
755-
let is_available = status.active || status.id.as_ref().map(|s| referenced_channel.personal_config.allowed_modes.contains(s)).unwrap_or(false);
754+
let user = referenced_channel.from.clone();
755+
let is_available = status.active || status.id.as_ref().map(|s| referenced_channel.personal_config.allowed_modes.contains(s)).unwrap_or(false);
756756

757-
(self.update_state)(&state); // we might have ratcheted it
757+
(self.update_state)(&state); // we might have ratcheted it
758758

759759

760-
return Ok(Some(StatusKitMessage::StatusChanged {
761-
user,
762-
mode: status.id.clone(),
763-
allowed: is_available
764-
}));
760+
return Ok(Some(StatusKitMessage::StatusChanged {
761+
user,
762+
mode: status.id.clone(),
763+
allowed: is_available
764+
}));
765+
}
765766
}
766767

767768
if let Some(IDSRecvMessage { message_unenc: Some(message), topic, sender: Some(sender), .. }) = self.identity.receive_message(msg, &["com.apple.private.alloy.status.keysharing", "com.apple.private.alloy.status.personal"]).await? {
768769
match topic {
769770
"com.apple.private.alloy.status.keysharing" => {
770771
let parsed: StatusKitRawSharedDevice = message.plist()?;
771-
debug!("StatusKit IDS message came in as {:?}", parsed);
772+
info!("StatusKit IDS message came in as {:?}", parsed);
772773

773774
let config: StatusKitPersonalConfig = plist::from_bytes(&base64_decode(&parsed.personal_config))?;
774775
let share_message = SharedMessage::decode(Cursor::new(base64_decode(&parsed.keys)))?;

src/test.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ async fn main() {
404404
let pet = account.get_pet().unwrap();
405405
let spd = account.spd.as_ref().unwrap();
406406

407-
let delegates = login_apple_delegates(&gsa.user, &pet, spd["adsid"].as_string().unwrap(), None, &mut *anisette_client.lock().await, config.as_ref(), &[LoginDelegate::IDS, LoginDelegate::MobileMe]).await.unwrap();
407+
let delegates = login_apple_delegates(&account, None, config.as_ref(), &[LoginDelegate::IDS, LoginDelegate::MobileMe]).await.unwrap();
408408
let user = authenticate_apple(delegates.ids.unwrap(), config.as_ref()).await.unwrap();
409409

410410
let mobileme = delegates.mobileme.unwrap();
@@ -605,10 +605,10 @@ async fn main() {
605605
token_provider.clone(), anisette_client.clone(), client.identity.clone()).await.unwrap();
606606

607607
let state: PasswordState = plist::from_file("passwords.plist").unwrap_or_default();
608-
let passwords = PasswordManager::new(
609-
keychain.clone(), cloudkit.clone(), client.identity.clone(), connection.clone(), state, Box::new(move |state| {
610-
plist::to_file_xml("passwords.plist", state).unwrap();
611-
})).await;
608+
// let passwords = PasswordManager::new(
609+
// keychain.clone(), cloudkit.clone(), client.identity.clone(), connection.clone(), state, Box::new(move |state| {
610+
// plist::to_file_xml("passwords.plist", state).unwrap();
611+
// })).await;
612612

613613

614614
if let Some(mut s) = session {
@@ -933,9 +933,9 @@ async fn main() {
933933
tokio::select! {
934934
msg = subscription.recv() => {
935935
let msg = msg.unwrap();
936-
if let Err(e) = passwords.handle(msg.clone()).await {
937-
info!("err {e}");
938-
}
936+
// if let Err(e) = passwords.handle(msg.clone()).await {
937+
// info!("err {e}");
938+
// }
939939
// if let Err(e) = findmy_client.handle(msg.clone()).await {
940940
// info!("err {e}");
941941
// }

0 commit comments

Comments
 (0)