apple_codesign/remote_signing/
mod.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Remote signing support.
6
7pub mod session_negotiation;
8
9use {
10    crate::{
11        cryptography::PrivateKey,
12        remote_signing::session_negotiation::{
13            PeerKeys, PublicKeyPeerDecrypt, SessionInitiatePeer, SessionJoinContext,
14            SessionJoinPeerPreJoin,
15        },
16        AppleCodesignError,
17    },
18    base64::{engine::general_purpose::STANDARD as STANDARD_ENGINE, Engine},
19    bcder::{
20        encode::{PrimitiveContent, Values},
21        Mode, Oid,
22    },
23    bytes::Bytes,
24    log::{debug, error, warn},
25    serde::{de::DeserializeOwned, Deserialize, Serialize},
26    signature::Signer,
27    std::{
28        cell::{RefCell, RefMut},
29        net::TcpStream,
30    },
31    thiserror::Error,
32    tungstenite::{
33        client::IntoClientRequest,
34        protocol::{Message, WebSocket, WebSocketConfig},
35        stream::MaybeTlsStream,
36    },
37    x509_certificate::{
38        CapturedX509Certificate, KeyAlgorithm, KeyInfoSigner, Sign, Signature, SignatureAlgorithm,
39        X509CertificateError,
40    },
41    zeroize::Zeroizing,
42};
43
44/// URL of default server to use.
45pub const DEFAULT_SERVER_URL: &str = "wss://ws.codesign.gregoryszorc.com/";
46
47/// An error specific to remote signing.
48#[derive(Debug, Error)]
49pub enum RemoteSignError {
50    #[error("unexpected message received from relay server: {0}")]
51    ServerUnexpectedMessage(String),
52
53    #[error("error reported from relay server: {0}")]
54    ServerError(String),
55
56    #[error("not compatible with relay server; try upgrading to a new release?")]
57    ServerIncompatible,
58
59    #[error("cryptography error: {0}")]
60    Crypto(String),
61
62    #[error("bad client state: {0}")]
63    ClientState(&'static str),
64
65    #[error("joining state not wanted for this session type: {0}")]
66    SessionJoinUnwantedState(String),
67
68    #[error("session join string error: {0}")]
69    SessionJoinString(String),
70
71    #[error("base64 decode error: {0}")]
72    Base64(#[from] base64::DecodeError),
73
74    #[error("I/O error: {0}")]
75    Io(#[from] std::io::Error),
76
77    #[error("PEM encoding error: {0}")]
78    Pem(#[from] pem::PemError),
79
80    #[error("JSON serialization error: {0}")]
81    SerdeJson(#[from] serde_json::Error),
82
83    #[error("SPAKE error: {0}")]
84    Spake(spake2::Error),
85
86    #[error("SPKI error: {0}")]
87    Spki(#[from] spki::Error),
88
89    #[error("websocket error: {0}")]
90    Websocket(#[from] tungstenite::Error),
91
92    #[error("X.509 certificate handler error: {0}")]
93    X509(#[from] X509CertificateError),
94}
95
96#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
97#[serde(rename_all = "kebab-case")]
98enum ApiMethod {
99    Hello,
100    CreateSession,
101    JoinSession,
102    SendMessage,
103    Goodbye,
104}
105
106/// A websocket message sent from the client to the server.
107#[derive(Clone, Debug, Serialize)]
108struct ClientMessage {
109    /// Unique ID for this request.
110    request_id: String,
111    /// API method being called.
112    api: ApiMethod,
113    /// Payload for this method.
114    payload: Option<ClientPayload>,
115}
116
117/// Payload for a [ClientMessage].
118#[derive(Clone, Debug, Serialize)]
119#[serde(untagged)]
120enum ClientPayload {
121    CreateSession {
122        session_id: String,
123        ttl: u64,
124        context: Option<String>,
125    },
126    JoinSession {
127        session_id: String,
128        context: Option<String>,
129    },
130    SendMessage {
131        session_id: String,
132        message: String,
133    },
134    Goodbye {
135        session_id: String,
136        reason: Option<String>,
137    },
138}
139
140#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
141#[serde(rename_all = "kebab-case")]
142enum ServerMessageType {
143    Error,
144    Greeting,
145    SessionCreated,
146    SessionJoined,
147    MessageSent,
148    PeerMessage,
149    SessionClosed,
150}
151
152/// Websocket message sent from server to client.
153#[derive(Clone, Debug, Deserialize)]
154struct ServerMessage {
155    /// ID of request responsible for this message.
156    request_id: Option<String>,
157    /// The type of message.
158    #[serde(rename = "type")]
159    typ: ServerMessageType,
160    ttl: Option<u64>,
161    payload: Option<serde_json::Value>,
162}
163
164impl ServerMessage {
165    fn into_result(self) -> Result<Self, RemoteSignError> {
166        if self.typ == ServerMessageType::Error {
167            let error = self.as_error()?;
168            Err(RemoteSignError::ServerError(format!(
169                "{}: {}",
170                error.code, error.message
171            )))
172        } else {
173            Ok(self)
174        }
175    }
176
177    fn as_type<T: DeserializeOwned>(
178        &self,
179        message_type: ServerMessageType,
180    ) -> Result<T, RemoteSignError> {
181        if self.typ == message_type {
182            if let Some(value) = &self.payload {
183                Ok(serde_json::from_value(value.clone())?)
184            } else {
185                Err(RemoteSignError::ClientState(
186                    "no payload for requested type",
187                ))
188            }
189        } else {
190            Err(RemoteSignError::ClientState(
191                "requested payload for wrong message type",
192            ))
193        }
194    }
195
196    fn as_error(&self) -> Result<ServerError, RemoteSignError> {
197        self.as_type::<ServerError>(ServerMessageType::Error)
198    }
199
200    fn as_greeting(&self) -> Result<ServerGreeting, RemoteSignError> {
201        self.as_type::<ServerGreeting>(ServerMessageType::Greeting)
202    }
203
204    fn as_session_joined(&self) -> Result<ServerJoined, RemoteSignError> {
205        self.as_type::<ServerJoined>(ServerMessageType::SessionJoined)
206    }
207
208    fn as_peer_message(&self) -> Result<ServerPeerMessage, RemoteSignError> {
209        self.as_type::<ServerPeerMessage>(ServerMessageType::PeerMessage)
210    }
211
212    fn as_session_closed(&self) -> Result<ServerSessionClosed, RemoteSignError> {
213        self.as_type::<ServerSessionClosed>(ServerMessageType::SessionClosed)
214    }
215}
216
217/// Response messages seen from server.
218#[derive(Clone, Debug, Deserialize)]
219#[serde(untagged)]
220enum ServerPayload {
221    Error(ServerError),
222    Greeting(ServerGreeting),
223    SessionJoined(ServerJoined),
224    PeerMessage(ServerPeerMessage),
225    SessionClosed(ServerSessionClosed),
226}
227
228#[derive(Clone, Debug, Deserialize)]
229struct ServerError {
230    code: String,
231    message: String,
232}
233
234#[derive(Clone, Debug, Deserialize)]
235struct ServerGreeting {
236    apis: Vec<String>,
237    motd: Option<String>,
238}
239
240#[derive(Clone, Debug, Deserialize)]
241struct ServerJoined {
242    context: Option<String>,
243}
244
245#[derive(Clone, Debug, Deserialize)]
246struct ServerPeerMessage {
247    message: String,
248}
249
250#[derive(Clone, Debug, Deserialize)]
251struct ServerSessionClosed {
252    reason: Option<String>,
253}
254
255#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
256#[serde(rename_all = "kebab-case")]
257enum PeerMessageType {
258    Ping,
259    Pong,
260    RequestSigningCertificate,
261    SigningCertificate,
262    SignRequest,
263    Signature,
264}
265
266/// A peer-to-peer message.
267#[derive(Clone, Debug, Deserialize, Serialize)]
268struct PeerMessage {
269    #[serde(rename = "type")]
270    typ: PeerMessageType,
271    payload: Option<serde_json::Value>,
272}
273
274impl PeerMessage {
275    fn require_type(self, typ: PeerMessageType) -> Result<Self, RemoteSignError> {
276        if self.typ == typ {
277            Ok(self)
278        } else {
279            Err(RemoteSignError::ServerUnexpectedMessage(format!(
280                "{:?}",
281                self.typ
282            )))
283        }
284    }
285
286    fn as_type<T: DeserializeOwned>(
287        &self,
288        message_type: PeerMessageType,
289    ) -> Result<T, RemoteSignError> {
290        if self.typ == message_type {
291            if let Some(value) = &self.payload {
292                Ok(serde_json::from_value(value.clone())?)
293            } else {
294                Err(RemoteSignError::ClientState(
295                    "no payload for requested type",
296                ))
297            }
298        } else {
299            Err(RemoteSignError::ClientState(
300                "requested payload for wrong message type",
301            ))
302        }
303    }
304
305    fn as_signing_certificate(&self) -> Result<PeerSigningCertificate, RemoteSignError> {
306        self.as_type::<PeerSigningCertificate>(PeerMessageType::SigningCertificate)
307    }
308
309    fn as_sign_request(&self) -> Result<PeerSignRequest, RemoteSignError> {
310        self.as_type::<PeerSignRequest>(PeerMessageType::SignRequest)
311    }
312
313    fn as_signature(&self) -> Result<PeerSignature, RemoteSignError> {
314        self.as_type::<PeerSignature>(PeerMessageType::Signature)
315    }
316}
317
318#[derive(Clone, Debug, Deserialize, Serialize)]
319struct PeerCertificate {
320    certificate: String,
321    #[serde(skip_serializing_if = "Vec::is_empty")]
322    chain: Vec<String>,
323}
324
325#[derive(Clone, Debug, Deserialize, Serialize)]
326#[serde(untagged)]
327enum PeerPayload {
328    SigningCertificate(PeerSigningCertificate),
329    SignRequest(PeerSignRequest),
330    Signature(PeerSignature),
331}
332
333#[derive(Clone, Debug, Deserialize, Serialize)]
334struct PeerSigningCertificate {
335    certificates: Vec<PeerCertificate>,
336}
337
338#[derive(Clone, Debug, Deserialize, Serialize)]
339struct PeerSignRequest {
340    message: String,
341}
342
343#[derive(Clone, Debug, Deserialize, Serialize)]
344struct PeerSignature {
345    message: String,
346    signature: String,
347    algorithm_oid: String,
348}
349
350const REQUIRED_ACTIONS: [&str; 4] = ["create-session", "join-session", "send-message", "goodbye"];
351
352/// Represents the response from the server.
353enum ServerResponse {
354    /// Server closed the connection.
355    Closed,
356
357    /// A parsed protocol message.
358    Message(ServerMessage),
359}
360
361/// A function that receives session information.
362pub type SessionInfoCallback = fn(sjs_base64: &str, sjs_pem: &str) -> Result<(), RemoteSignError>;
363
364fn create_websocket(
365    req: impl IntoClientRequest,
366) -> Result<WebSocket<MaybeTlsStream<TcpStream>>, RemoteSignError> {
367    let config = WebSocketConfig {
368        ..Default::default()
369    };
370
371    let req = req.into_client_request()?;
372    warn!("connecting to {}", req.uri());
373
374    let (ws, _) = tungstenite::client::connect_with_config(req, Some(config), 5)?;
375
376    Ok(ws)
377}
378
379fn wait_for_server_response(
380    ws: &mut WebSocket<MaybeTlsStream<TcpStream>>,
381) -> Result<ServerResponse, RemoteSignError> {
382    loop {
383        match ws.read()? {
384            Message::Text(text) => {
385                let message = serde_json::from_str::<ServerMessage>(&text)?;
386                debug!(
387                    "received message; request-id: {}; type: {:?}",
388                    message
389                        .request_id
390                        .as_ref()
391                        .unwrap_or(&"(not set)".to_string()),
392                    message.typ
393                );
394
395                return Ok(ServerResponse::Message(message));
396            }
397            Message::Binary(_) => {
398                return Err(RemoteSignError::ServerUnexpectedMessage(
399                    "binary websocket message".into(),
400                ))
401            }
402            // TODO return error for these?
403            Message::Pong(_) => {}
404            Message::Ping(_) => {}
405            Message::Frame(_) => {}
406            Message::Close(_) => {
407                return Ok(ServerResponse::Closed);
408            }
409        }
410    }
411}
412
413fn wait_for_server_message(
414    ws: &mut WebSocket<MaybeTlsStream<TcpStream>>,
415) -> Result<ServerMessage, RemoteSignError> {
416    match wait_for_server_response(ws)? {
417        ServerResponse::Closed => Err(RemoteSignError::ClientState("server closed connection")),
418        ServerResponse::Message(m) => {
419            debug!(
420                "received server message {:?}; remaining session TTL: {}",
421                m.typ,
422                m.ttl.unwrap_or_default()
423            );
424            Ok(m)
425        }
426    }
427}
428
429fn wait_for_expected_server_message(
430    ws: &mut WebSocket<MaybeTlsStream<TcpStream>>,
431    message_type: ServerMessageType,
432) -> Result<ServerMessage, RemoteSignError> {
433    let res = wait_for_server_message(ws)?.into_result()?;
434
435    if res.typ == message_type {
436        Ok(res)
437    } else {
438        Err(RemoteSignError::ServerUnexpectedMessage(format!(
439            "{:?}",
440            res.typ
441        )))
442    }
443}
444
445/// A client for the remote signing protocol that has not yet joined a session.
446///
447/// Clients can perform both the initiator and signer roles.
448pub struct UnjoinedSigningClient {
449    ws: WebSocket<MaybeTlsStream<TcpStream>>,
450}
451
452impl UnjoinedSigningClient {
453    fn new(req: impl IntoClientRequest) -> Result<Self, RemoteSignError> {
454        let ws = create_websocket(req)?;
455
456        let mut slf = Self { ws };
457
458        slf.send_hello()?;
459
460        Ok(slf)
461    }
462
463    /// Create a new client in the initiator role.
464    pub fn new_initiator(
465        req: impl IntoClientRequest,
466        initiator: Box<dyn SessionInitiatePeer>,
467        session_info_cb: Option<SessionInfoCallback>,
468    ) -> Result<InitiatorClient, RemoteSignError> {
469        let slf = Self::new(req)?;
470        slf.create_session_and_wait_for_signer(initiator, session_info_cb)
471    }
472
473    /// Create a new client in the signer role.
474    pub fn new_signer(
475        joiner: Box<dyn SessionJoinPeerPreJoin>,
476        signing_key: &dyn KeyInfoSigner,
477        signing_cert: CapturedX509Certificate,
478        certificates: Vec<CapturedX509Certificate>,
479        default_server_url: String,
480    ) -> Result<SigningClient, RemoteSignError> {
481        // An error here could result in the peer hanging indefinitely because the session
482        // is unjoined. Ideally we'd recover from this by attempting to join with an error.
483        // However, we may not even be able to obtain the session ID since sometimes it is
484        // encrypted and the error could be from a decryption failure! So for now, just let
485        // the peer idle.
486        let join_context = joiner.join_context()?;
487
488        let server_url = join_context
489            .server_url
490            .as_ref()
491            .unwrap_or(&default_server_url);
492
493        let slf = Self::new(server_url)?;
494        slf.join_session(join_context, signing_key, signing_cert, certificates)
495    }
496
497    /// Create a new signing session and wait for a signer to arrive.
498    fn create_session_and_wait_for_signer(
499        mut self,
500        initiator: Box<dyn SessionInitiatePeer>,
501        session_info_cb: Option<SessionInfoCallback>,
502    ) -> Result<InitiatorClient, RemoteSignError> {
503        let session_id = initiator.session_id().to_string();
504
505        self.send_request(
506            ApiMethod::CreateSession,
507            Some(ClientPayload::CreateSession {
508                session_id: session_id.clone(),
509                ttl: 600,
510                context: initiator
511                    .session_create_context()
512                    .map(|x| STANDARD_ENGINE.encode(x)),
513            }),
514        )?;
515
516        let sjs_base64 = initiator.session_join_string_base64()?;
517        let sjs_pem = initiator.session_join_string_pem()?;
518
519        wait_for_expected_server_message(&mut self.ws, ServerMessageType::SessionCreated)?;
520        warn!("session successfully created on server");
521
522        if let Some(cb) = session_info_cb {
523            cb(&sjs_base64, &sjs_pem)?;
524        }
525
526        let res = wait_for_expected_server_message(&mut self.ws, ServerMessageType::SessionJoined)?;
527
528        let joined = res.as_session_joined()?;
529        warn!("signer joined session; deriving shared encryption key");
530
531        let context = if let Some(context) = joined.context {
532            Some(STANDARD_ENGINE.decode(context)?)
533        } else {
534            None
535        };
536
537        let keys = initiator.negotiate_session(context)?;
538
539        let mut client = PairedClient {
540            ws: self.ws,
541            session_id,
542            keys,
543        };
544
545        client.send_ping()?;
546
547        let (signing_cert, signing_chain) = client.request_signing_certificate()?;
548
549        if let Some(name) = signing_cert.subject_common_name() {
550            warn!("remote signer will sign with certificate: {}", name);
551        }
552
553        Ok(InitiatorClient {
554            client: RefCell::new(client),
555            signing_cert,
556            signing_chain,
557        })
558    }
559
560    /// Join a signing session.
561    ///
562    /// This should be called by signers once they have the session ID to join.
563    pub fn join_session(
564        mut self,
565        join_context: SessionJoinContext,
566        signing_key: &dyn KeyInfoSigner,
567        signing_cert: CapturedX509Certificate,
568        certificates: Vec<CapturedX509Certificate>,
569    ) -> Result<SigningClient, RemoteSignError> {
570        let session_id = join_context.session_id.clone();
571
572        warn!("joining session...");
573        self.send_request(
574            ApiMethod::JoinSession,
575            Some(ClientPayload::JoinSession {
576                session_id: session_id.clone(),
577                context: join_context.peer_context.map(|x| STANDARD_ENGINE.encode(x)),
578            }),
579        )?;
580
581        wait_for_expected_server_message(&mut self.ws, ServerMessageType::SessionJoined)?;
582
583        warn!("successfully joined signing session {}", session_id);
584
585        let keys = join_context.peer_handshake.negotiate_session()?;
586
587        let mut client = PairedClient {
588            ws: self.ws,
589            session_id,
590            keys,
591        };
592
593        warn!("verifying encrypted communications with peer");
594        client.send_ping()?;
595
596        Ok(SigningClient {
597            client: RefCell::new(client),
598            signing_key,
599            signing_cert,
600            certificates,
601        })
602    }
603
604    fn send_request(
605        &mut self,
606        api: ApiMethod,
607        payload: Option<ClientPayload>,
608    ) -> Result<(), RemoteSignError> {
609        let request_id = uuid::Uuid::new_v4().to_string();
610
611        let message = ClientMessage {
612            request_id,
613            api,
614            payload,
615        };
616
617        let body = serde_json::to_string(&message)?;
618        self.ws.send(body.into())?;
619        self.ws.flush()?;
620
621        Ok(())
622    }
623
624    fn send_hello(&mut self) -> Result<(), RemoteSignError> {
625        self.send_request(ApiMethod::Hello, None)?;
626
627        let res = wait_for_expected_server_message(&mut self.ws, ServerMessageType::Greeting)?;
628        let greeting = res.as_greeting()?;
629
630        if let Some(motd) = &greeting.motd {
631            warn!("message from remote server: {}", motd);
632        }
633
634        for required in REQUIRED_ACTIONS {
635            if !greeting.apis.contains(&required.to_string()) {
636                error!("server does not support required action {}", required);
637                return Err(RemoteSignError::ServerIncompatible);
638            }
639        }
640
641        Ok(())
642    }
643}
644
645/// A remote signing client that has joined a session and is ready to exchange messages.
646pub struct PairedClient {
647    ws: WebSocket<MaybeTlsStream<TcpStream>>,
648    session_id: String,
649    keys: PeerKeys,
650}
651
652impl Drop for PairedClient {
653    fn drop(&mut self) {
654        warn!("disconnecting from relay server");
655    }
656}
657
658impl PairedClient {
659    fn send_request(
660        &mut self,
661        api: ApiMethod,
662        payload: Option<ClientPayload>,
663    ) -> Result<(), RemoteSignError> {
664        let request_id = uuid::Uuid::new_v4().to_string();
665
666        let message = ClientMessage {
667            request_id,
668            api,
669            payload,
670        };
671
672        let body = serde_json::to_string(&message)?;
673        self.ws.send(body.into())?;
674        self.ws.flush()?;
675
676        Ok(())
677    }
678
679    fn decrypt_peer_message(
680        &mut self,
681        message: &ServerPeerMessage,
682    ) -> Result<PeerMessage, RemoteSignError> {
683        let ciphertext = STANDARD_ENGINE.decode(&message.message)?;
684
685        let plaintext = self.keys.open(ciphertext)?;
686
687        Ok(serde_json::from_slice(&plaintext)?)
688    }
689
690    fn send_encrypted_message(
691        &mut self,
692        message_type: PeerMessageType,
693        payload: Option<PeerPayload>,
694    ) -> Result<(), RemoteSignError> {
695        let message = PeerMessage {
696            typ: message_type,
697            payload: if let Some(payload) = payload {
698                Some(serde_json::to_value(payload)?)
699            } else {
700                None
701            },
702        };
703
704        let ciphertext = self.keys.seal(&serde_json::to_vec(&message)?)?;
705
706        self.send_request(
707            ApiMethod::SendMessage,
708            Some(ClientPayload::SendMessage {
709                session_id: self.session_id.clone(),
710                message: STANDARD_ENGINE.encode(ciphertext),
711            }),
712        )?;
713
714        Ok(())
715    }
716
717    fn wait_for_peer_message(&mut self) -> Result<Option<PeerMessage>, RemoteSignError> {
718        let res = wait_for_server_message(&mut self.ws)?.into_result()?;
719
720        if let Ok(closed) = res.as_session_closed() {
721            warn!(
722                "signing session closed; reason: {}",
723                closed
724                    .reason
725                    .as_ref()
726                    .unwrap_or(&"(none given)".to_string())
727            );
728            Ok(None)
729        } else {
730            let message = res.as_peer_message()?;
731
732            Ok(Some(self.decrypt_peer_message(&message)?))
733        }
734    }
735
736    fn wait_for_server_and_peer_response(&mut self) -> Result<PeerMessage, RemoteSignError> {
737        let mut response = None;
738
739        // We should get a server message acknowledging our request plus the response from
740        // the peer. The order they arrive in is random.
741        for _ in 0..2 {
742            let res = wait_for_server_message(&mut self.ws)?.into_result()?;
743
744            match res.typ {
745                ServerMessageType::MessageSent => {}
746                ServerMessageType::PeerMessage => {
747                    let message = res.as_peer_message()?;
748
749                    response = Some(self.decrypt_peer_message(&message)?);
750                }
751                m => return Err(RemoteSignError::ServerUnexpectedMessage(format!("{m:?}"))),
752            }
753        }
754
755        if let Some(response) = response {
756            Ok(response)
757        } else {
758            Err(RemoteSignError::ClientState(
759                "failed to receive response from server or peer",
760            ))
761        }
762    }
763
764    fn send_goodbye(&mut self, reason: Option<String>) -> Result<(), RemoteSignError> {
765        warn!("terminating signing session on relay");
766        self.send_request(
767            ApiMethod::Goodbye,
768            Some(ClientPayload::Goodbye {
769                session_id: self.session_id.clone(),
770                reason,
771            }),
772        )?;
773
774        wait_for_server_message(&mut self.ws)?.into_result()?;
775        warn!("relay server confirmed session termination");
776
777        Ok(())
778    }
779
780    fn send_ping(&mut self) -> Result<(), RemoteSignError> {
781        // We should get a server message acknowledging our request plus a
782        // ping from the peer. The order may not be reliable.
783        self.send_encrypted_message(PeerMessageType::Ping, None)?;
784        let message = self.wait_for_server_and_peer_response()?;
785        if !matches!(message.typ, PeerMessageType::Ping) {
786            return Err(RemoteSignError::ServerUnexpectedMessage(
787                "unexpected response to ping message".into(),
788            ));
789        }
790
791        self.send_encrypted_message(PeerMessageType::Pong, None)?;
792        let message = self.wait_for_server_and_peer_response()?;
793        if !matches!(message.typ, PeerMessageType::Pong) {
794            return Err(RemoteSignError::ServerUnexpectedMessage(
795                "unexpected response to ping message".into(),
796            ));
797        }
798
799        Ok(())
800    }
801
802    /// Request the signing certificate from the peer.
803    pub fn request_signing_certificate(
804        &mut self,
805    ) -> Result<(CapturedX509Certificate, Vec<CapturedX509Certificate>), RemoteSignError> {
806        warn!("requesting signing certificate info from signer");
807        self.send_encrypted_message(PeerMessageType::RequestSigningCertificate, None)?;
808        let res = self
809            .wait_for_server_and_peer_response()?
810            .require_type(PeerMessageType::SigningCertificate)?;
811
812        let cert = res.as_signing_certificate()?;
813
814        if let Some(cert) = cert.certificates.get(0) {
815            let cert_der = STANDARD_ENGINE.decode(&cert.certificate)?;
816            let chain_der = cert
817                .chain
818                .iter()
819                .map(|x| STANDARD_ENGINE.decode(x))
820                .collect::<Result<Vec<_>, base64::DecodeError>>()?;
821
822            let cert = CapturedX509Certificate::from_der(cert_der)?;
823            let chain = chain_der
824                .into_iter()
825                .map(CapturedX509Certificate::from_der)
826                .collect::<Result<Vec<_>, X509CertificateError>>()?;
827
828            return Ok((cert, chain));
829        }
830
831        Err(RemoteSignError::ClientState(
832            "did not receive any signing certificates from peer",
833        ))
834    }
835}
836
837/// A client fulfilling the role of the initiator.
838pub struct InitiatorClient {
839    client: RefCell<PairedClient>,
840    signing_cert: CapturedX509Certificate,
841    signing_chain: Vec<CapturedX509Certificate>,
842}
843
844impl InitiatorClient {
845    /// The X.509 certificate that will be used to sign.
846    pub fn signing_certificate(&self) -> &CapturedX509Certificate {
847        &self.signing_cert
848    }
849
850    /// Additional X.509 certificates in the signing chain.
851    pub fn certificate_chain(&self) -> &[CapturedX509Certificate] {
852        &self.signing_chain
853    }
854}
855
856impl Signer<Signature> for InitiatorClient {
857    fn try_sign(&self, message: &[u8]) -> Result<Signature, signature::Error> {
858        let mut client = self.client.borrow_mut();
859
860        warn!("sending signing request to remote signer");
861
862        client
863            .send_encrypted_message(
864                PeerMessageType::SignRequest,
865                Some(PeerPayload::SignRequest(PeerSignRequest {
866                    message: STANDARD_ENGINE.encode(message),
867                })),
868            )
869            .map_err(signature::Error::from_source)?;
870
871        let response = client
872            .wait_for_server_and_peer_response()
873            .map_err(signature::Error::from_source)?
874            .require_type(PeerMessageType::Signature)
875            .map_err(signature::Error::from_source)?;
876
877        let peer_signature = response
878            .as_signature()
879            .map_err(signature::Error::from_source)?;
880
881        warn!("received signature from remote signer");
882
883        let signature = STANDARD_ENGINE
884            .decode(&peer_signature.signature)
885            .map_err(signature::Error::from_source)?;
886        let oid_der = STANDARD_ENGINE
887            .decode(&peer_signature.algorithm_oid)
888            .map_err(signature::Error::from_source)?;
889
890        bcder::decode::Constructed::decode(oid_der.as_ref(), Mode::Der, |cons| {
891            Oid::take_from(cons)
892        })
893        .map_err(|_| {
894            signature::Error::from_source(RemoteSignError::Crypto(
895                "error parsing signature OID".into(),
896            ))
897        })?;
898
899        // The peer could be acting maliciously (or just be buggy) and sign with a
900        // certificate from the initial one presented. So verify the signature we
901        // received is valid for the message we sent.
902        if let Err(e) = self.signing_cert.verify_signed_data(message, &signature) {
903            error!("Peer issued signature did not verify against the certificate they provided");
904            error!("The peer could be acting maliciously. Or it could just be buggy.");
905            error!("Either way, it didn't issue a valid signature, so we're giving up.");
906
907            return Err(signature::Error::from_source(e));
908        }
909
910        Ok(signature.into())
911    }
912}
913
914impl Sign for InitiatorClient {
915    fn sign(&self, message: &[u8]) -> Result<(Vec<u8>, SignatureAlgorithm), X509CertificateError> {
916        let algorithm = self.signature_algorithm()?;
917
918        Ok((self.try_sign(message)?.into(), algorithm))
919    }
920
921    fn key_algorithm(&self) -> Option<KeyAlgorithm> {
922        self.signing_cert.key_algorithm()
923    }
924
925    fn public_key_data(&self) -> Bytes {
926        self.signing_cert.public_key_data()
927    }
928
929    fn signature_algorithm(&self) -> Result<SignatureAlgorithm, X509CertificateError> {
930        if let Some(algorithm) = self.signing_cert.signature_algorithm() {
931            Ok(algorithm)
932        } else {
933            Err(X509CertificateError::UnknownSignatureAlgorithm(format!(
934                "{}",
935                self.signing_cert.signature_algorithm_oid()
936            )))
937        }
938    }
939
940    fn private_key_data(&self) -> Option<Zeroizing<Vec<u8>>> {
941        // We never have access to private keys from the remote signer.
942        None
943    }
944
945    fn rsa_primes(
946        &self,
947    ) -> Result<Option<(Zeroizing<Vec<u8>>, Zeroizing<Vec<u8>>)>, X509CertificateError> {
948        // We never have access to private keys from the remote signer.
949        Ok(None)
950    }
951}
952
953impl KeyInfoSigner for InitiatorClient {}
954
955impl PublicKeyPeerDecrypt for InitiatorClient {
956    fn decrypt(&self, _ciphertext: &[u8]) -> Result<Vec<u8>, RemoteSignError> {
957        Err(RemoteSignError::Crypto(
958            "a remote signer cannot be used to perform signing".into(),
959        ))
960    }
961}
962
963impl PrivateKey for InitiatorClient {
964    fn as_key_info_signer(&self) -> &dyn KeyInfoSigner {
965        self
966    }
967
968    fn to_public_key_peer_decrypt(
969        &self,
970    ) -> Result<Box<dyn PublicKeyPeerDecrypt>, AppleCodesignError> {
971        Err(
972            RemoteSignError::ClientState("cannot use remote signing initiator for decryption")
973                .into(),
974        )
975    }
976
977    fn finish(&self) -> Result<(), AppleCodesignError> {
978        // Tell the peer we're done so it disconnects
979        Ok(self
980            .client
981            .borrow_mut()
982            .send_goodbye(Some("signing operations completed".into()))?)
983    }
984}
985
986pub struct SigningClient<'key> {
987    client: RefCell<PairedClient>,
988    signing_key: &'key dyn KeyInfoSigner,
989    signing_cert: CapturedX509Certificate,
990    certificates: Vec<CapturedX509Certificate>,
991}
992
993impl<'key> SigningClient<'key> {
994    fn send_signing_certificate(
995        &self,
996        mut client: RefMut<PairedClient>,
997    ) -> Result<(), RemoteSignError> {
998        client.send_encrypted_message(
999            PeerMessageType::SigningCertificate,
1000            Some(PeerPayload::SigningCertificate(PeerSigningCertificate {
1001                certificates: vec![PeerCertificate {
1002                    certificate: STANDARD_ENGINE.encode(self.signing_cert.encode_der()?),
1003                    chain: self
1004                        .certificates
1005                        .iter()
1006                        .map(|cert| {
1007                            let der = cert.encode_der()?;
1008
1009                            Ok(STANDARD_ENGINE.encode(der))
1010                        })
1011                        .collect::<Result<Vec<_>, RemoteSignError>>()?,
1012                }],
1013            })),
1014        )?;
1015
1016        wait_for_expected_server_message(&mut client.ws, ServerMessageType::MessageSent)?;
1017
1018        Ok(())
1019    }
1020
1021    fn handle_sign_request(
1022        &self,
1023        mut client: RefMut<PairedClient>,
1024        request: PeerSignRequest,
1025    ) -> Result<(), RemoteSignError> {
1026        let message = STANDARD_ENGINE.decode(&request.message)?;
1027
1028        warn!(
1029            "creating signature for remote message: {}",
1030            &request.message
1031        );
1032        let signature = self
1033            .signing_key
1034            .try_sign(&message)
1035            .map_err(|e| RemoteSignError::Crypto(format!("when creating signature: {e}")))?;
1036        let algorithm = self.signing_key.signature_algorithm()?;
1037
1038        let oid = Oid::from(algorithm);
1039        let mut oid_der = vec![];
1040        oid.encode().write_encoded(Mode::Der, &mut oid_der)?;
1041
1042        warn!("sending signature to peer");
1043        client.send_encrypted_message(
1044            PeerMessageType::Signature,
1045            Some(PeerPayload::Signature(PeerSignature {
1046                message: STANDARD_ENGINE.encode(message),
1047                signature: STANDARD_ENGINE.encode(signature),
1048                algorithm_oid: STANDARD_ENGINE.encode(oid_der),
1049            })),
1050        )?;
1051
1052        wait_for_expected_server_message(&mut client.ws, ServerMessageType::MessageSent)?;
1053        warn!("relay acknowledged signature message received");
1054
1055        Ok(())
1056    }
1057
1058    fn process_next_message(&self) -> Result<bool, RemoteSignError> {
1059        let mut client = self.client.borrow_mut();
1060
1061        warn!("waiting for server to send us a message...");
1062        let res = if let Some(res) = client.wait_for_peer_message()? {
1063            res
1064        } else {
1065            return Ok(false);
1066        };
1067
1068        match res.typ {
1069            PeerMessageType::RequestSigningCertificate => {
1070                self.send_signing_certificate(client)?;
1071            }
1072            PeerMessageType::Ping => {
1073                client.send_encrypted_message(PeerMessageType::Pong, None)?;
1074                wait_for_expected_server_message(&mut client.ws, ServerMessageType::MessageSent)?;
1075            }
1076            PeerMessageType::Pong => {}
1077            PeerMessageType::SignRequest => {
1078                self.handle_sign_request(client, res.as_sign_request()?)?;
1079            }
1080            typ => {
1081                warn!("unprocessed message: {:?}", typ);
1082            }
1083        }
1084
1085        Ok(true)
1086    }
1087
1088    pub fn run(self) -> Result<(), RemoteSignError> {
1089        while self.process_next_message()? {}
1090
1091        Ok(())
1092    }
1093}