diff --git a/gui/main.c b/gui/main.c index cc615e9..2096582 100644 --- a/gui/main.c +++ b/gui/main.c @@ -6,9 +6,9 @@ int main(int argc, const char *argv[]) { - if(argc != 6) + if(argc != 7) { - printf("Usage: %s \n", argv[0]); + printf("Usage: %s \n", argv[0]); return 1; } @@ -32,6 +32,14 @@ int main(int argc, const char *argv[]) return 1; } + size_t did_size = sizeof(connect_info.did); + err = chiaki_base64_decode(argv[6], strlen(argv[6]), connect_info.did, &did_size); + if(err != CHIAKI_ERR_SUCCESS || did_size != sizeof(connect_info.did)) + { + printf("did invalid.\n"); + return 1; + } + ChiakiSession session; chiaki_session_init(&session, &connect_info); chiaki_session_start(&session); diff --git a/lib/include/chiaki/ctrl.h b/lib/include/chiaki/ctrl.h index feacfb7..a5e6449 100644 --- a/lib/include/chiaki/ctrl.h +++ b/lib/include/chiaki/ctrl.h @@ -29,6 +29,7 @@ typedef struct chiaki_ctrl_t { struct chiaki_session_t *session; ChiakiThread thread; + int sock; } ChiakiCtrl; CHIAKI_EXPORT ChiakiErrorCode chiaki_ctrl_start(ChiakiCtrl *ctrl, struct chiaki_session_t *session); diff --git a/lib/include/chiaki/rpcrypt.h b/lib/include/chiaki/rpcrypt.h index f3ae5f7..eba61d9 100644 --- a/lib/include/chiaki/rpcrypt.h +++ b/lib/include/chiaki/rpcrypt.h @@ -33,7 +33,6 @@ typedef struct chiaki_rpcrypt_t { uint8_t bright[CHIAKI_KEY_BYTES]; uint8_t ambassador[CHIAKI_KEY_BYTES]; - struct hmac_ctx_st *hmac_ctx; } ChiakiRPCrypt; CHIAKI_EXPORT void chiaki_rpcrypt_bright_ambassador(uint8_t *bright, uint8_t *ambassador, const uint8_t *nonce, const uint8_t *morning); diff --git a/lib/include/chiaki/session.h b/lib/include/chiaki/session.h index 7793f75..42c5e46 100644 --- a/lib/include/chiaki/session.h +++ b/lib/include/chiaki/session.h @@ -31,13 +31,17 @@ extern "C" { #endif + +#define CHIAKI_RP_DID_SIZE 32 + typedef struct chiaki_connect_info_t { - const char *host; - const char *regist_key; - const char *ostype; - char auth[0x10]; + const char *host; // null terminated + const char *regist_key; // null terminated + const char *ostype; // null terminated + char auth[0x10]; // must be completely filled (pad with \0) uint8_t morning[0x10]; + uint8_t did[CHIAKI_RP_DID_SIZE]; } ChiakiConnectInfo; @@ -72,6 +76,7 @@ typedef void (*ChiakiEventCallback)(ChiakiEvent *event, void *user); + typedef struct chiaki_session_t { struct @@ -83,9 +88,11 @@ typedef struct chiaki_session_t char *ostype; char auth[CHIAKI_KEY_BYTES]; uint8_t morning[CHIAKI_KEY_BYTES]; + uint8_t did[CHIAKI_RP_DID_SIZE]; } connect_info; uint8_t nonce[CHIAKI_KEY_BYTES]; + ChiakiRPCrypt rpcrypt; ChiakiQuitReason quit_reason; @@ -109,6 +116,13 @@ static inline void chiaki_session_set_event_cb(ChiakiSession *session, ChiakiEve session->event_cb_user = user; } +static inline void chiaki_session_set_quit_reason(ChiakiSession *session, ChiakiQuitReason reason) +{ + if(session->quit_reason != CHIAKI_QUIT_REASON_NONE) + return; + session->quit_reason = reason; +} + #ifdef __cplusplus } #endif diff --git a/lib/src/ctrl.c b/lib/src/ctrl.c index f106d71..7a224a4 100644 --- a/lib/src/ctrl.c +++ b/lib/src/ctrl.c @@ -17,11 +17,14 @@ #include #include +#include +#include #include #include #include #include +#include #define SESSION_CTRL_PORT 9295 @@ -47,11 +50,49 @@ static void *ctrl_thread_func(void *user) { ChiakiCtrl *ctrl = user; + ChiakiErrorCode err = ctrl_thread_connect(ctrl); + if(err != CHIAKI_ERR_SUCCESS) + { + chiaki_session_set_quit_reason(ctrl->session, CHIAKI_QUIT_REASON_CTRL_UNKNOWN); + return NULL; + } + // ... return NULL; } + + +typedef struct ctrl_response_t { + bool server_type_valid; + uint8_t rp_server_type[0x10]; + bool success; +} CtrlResponse; + +static void parse_ctrl_response(CtrlResponse *response, ChiakiHttpResponse *http_response) +{ + memset(response, 0, sizeof(CtrlResponse)); + + if(http_response->code != 200) + { + response->success = false; + return; + } + + response->success = true; + response->server_type_valid = false; + for(ChiakiHttpHeader *header=http_response->headers; header; header=header->next) + { + if(strcmp(header->key, "RP-Server-Type") == 0) + { + size_t server_type_size = sizeof(response->rp_server_type); + chiaki_base64_decode(header->value, strlen(header->value) + 1, response->rp_server_type, &server_type_size); + response->server_type_valid = server_type_size == sizeof(response->rp_server_type); + } + } +} + static ChiakiErrorCode ctrl_thread_connect(ChiakiCtrl *ctrl) { ChiakiSession *session = ctrl->session; @@ -72,21 +113,65 @@ static ChiakiErrorCode ctrl_thread_connect(ChiakiCtrl *ctrl) if(sock < 0) { CHIAKI_LOGE(&session->log, "Session ctrl socket creation failed.\n"); - if(session->quit_reason == CHIAKI_QUIT_REASON_NONE) - session->quit_reason = CHIAKI_QUIT_REASON_CTRL_UNKNOWN; + chiaki_session_set_quit_reason(session, CHIAKI_QUIT_REASON_CTRL_UNKNOWN); + return CHIAKI_ERR_NETWORK; + } + + int r = connect(sock, sa, addr->ai_addrlen); + free(sa); + if(r < 0) + { + int errsv = errno; + CHIAKI_LOGE(&session->log, "Ctrl connect failed: %s\n", strerror(errsv)); + if(errsv == ECONNREFUSED) + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_CONNECTION_REFUSED; + else + session->quit_reason = CHIAKI_QUIT_REASON_NONE; + close(sock); return CHIAKI_ERR_NETWORK; } CHIAKI_LOGI(&session->log, "Connected to %s:%d\n", session->connect_info.hostname, SESSION_CTRL_PORT); - char request[512]; + + uint8_t auth_enc[CHIAKI_KEY_BYTES]; + ChiakiErrorCode err = chiaki_rpcrypt_encrypt(&session->rpcrypt, 0, (uint8_t *)session->connect_info.auth, auth_enc, CHIAKI_KEY_BYTES); + if(err != CHIAKI_ERR_SUCCESS) + goto error; + char auth_b64[CHIAKI_KEY_BYTES*2]; + err = chiaki_base64_encode(auth_enc, sizeof(auth_enc), auth_b64, sizeof(auth_b64)); + if(err != CHIAKI_ERR_SUCCESS) + goto error; + + uint8_t did_enc[CHIAKI_RP_DID_SIZE]; + err = chiaki_rpcrypt_encrypt(&session->rpcrypt, 1, (uint8_t *)session->connect_info.did, did_enc, CHIAKI_RP_DID_SIZE); + if(err != CHIAKI_ERR_SUCCESS) + goto error; + char did_b64[CHIAKI_RP_DID_SIZE*2]; + err = chiaki_base64_encode(did_enc, sizeof(did_enc), did_b64, sizeof(did_b64)); + if(err != CHIAKI_ERR_SUCCESS) + goto error; + + uint8_t ostype_enc[128]; + size_t ostype_len = strlen(session->connect_info.ostype) + 1; + if(ostype_len > sizeof(ostype_enc)) + goto error; + err = chiaki_rpcrypt_encrypt(&session->rpcrypt, 2, (uint8_t *)session->connect_info.ostype, ostype_enc, ostype_len); + if(err != CHIAKI_ERR_SUCCESS) + goto error; + char ostype_b64[256]; + err = chiaki_base64_encode(ostype_enc, ostype_len, ostype_b64, sizeof(ostype_b64)); + if(err != CHIAKI_ERR_SUCCESS) + goto error; + + static const char request_fmt[] = "GET /sce/rp/session/ctrl HTTP/1.1\r\n" "Host: %s:%d\r\n" "User-Agent: remoteplay Windows\r\n" "Connection: keep-alive\r\n" "Content-Length: 0\r\n" - "RP-Auth: %s\r\n" + "RP-Auth: %s\r\n" "RP-Version: 8.0\r\n" "RP-Did: %s\r\n" "RP-ControllerType: 3\r\n" @@ -94,10 +179,64 @@ static ChiakiErrorCode ctrl_thread_connect(ChiakiCtrl *ctrl) "RP-OSType: %s\r\n" "RP-ConPath: 1\r\n\r\n"; - uint8_t auth_enc[CHIAKI_KEY_BYTES]; + char buf[512]; + int request_len = snprintf(buf, sizeof(buf), request_fmt, + session->connect_info.hostname, SESSION_CTRL_PORT, auth_b64, did_b64, ostype_b64); + if(request_len < 0 || request_len >= sizeof(buf)) + goto error; + CHIAKI_LOGI(&session->log, "Sending ctrl request\n"); + ssize_t sent = send(sock, buf, (size_t)request_len, 0); + if(sent < 0) + { + CHIAKI_LOGE(&session->log, "Failed to send ctrl request\n"); + goto error; + } - close(sock); + size_t header_size; + size_t received_size; + err = chiaki_recv_http_header(sock, buf, sizeof(buf)-1, &header_size, &received_size); + if(err != CHIAKI_ERR_SUCCESS) + { + CHIAKI_LOGE(&session->log, "Failed to receive ctrl request response\n"); + goto error; + } + + buf[received_size] = '\0'; + + ChiakiHttpResponse http_response; + err = chiaki_http_response_parse(&http_response, buf, header_size); + if(err != CHIAKI_ERR_SUCCESS) + { + CHIAKI_LOGE(&session->log, "Failed to parse ctrl request response\n"); + goto error; + } + + CtrlResponse response; + parse_ctrl_response(&response, &http_response); + chiaki_http_response_fini(&http_response); + + if(!response.success) + { + err = CHIAKI_ERR_UNKNOWN; + goto error; + } + + if(response.server_type_valid) + { + ChiakiErrorCode err2 = chiaki_rpcrypt_decrypt(&session->rpcrypt, 0, response.rp_server_type, response.rp_server_type, sizeof(response.rp_server_type)); + response.server_type_valid = err2 == CHIAKI_ERR_SUCCESS; + } + + if(!response.server_type_valid) + CHIAKI_LOGE(&session->log, "No valid Server Type in ctrl response\n"); + + ctrl->sock = sock; + close(sock); // TODO: remove return CHIAKI_ERR_SUCCESS; + +error: + close(sock); + return err; } \ No newline at end of file diff --git a/lib/src/session.c b/lib/src/session.c index ddc62be..191b116 100644 --- a/lib/src/session.c +++ b/lib/src/session.c @@ -68,6 +68,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_session_init(ChiakiSession *session, Chiaki memcpy(session->connect_info.auth, connect_info->auth, sizeof(session->connect_info.auth)); memcpy(session->connect_info.morning, connect_info->morning, sizeof(session->connect_info.morning)); + memcpy(session->connect_info.did, connect_info->did, sizeof(session->connect_info.did)); return CHIAKI_ERR_SUCCESS; } @@ -114,6 +115,20 @@ static void *session_thread_func(void *arg) CHIAKI_LOGI(&session->log, "Session request successful\n"); + chiaki_rpcrypt_init(&session->rpcrypt, session->nonce, session->connect_info.morning); + + usleep(10000); + + CHIAKI_LOGI(&session->log, "Starting ctrl\n"); + + ChiakiErrorCode err = chiaki_ctrl_start(&session->ctrl, session); + if(err != CHIAKI_ERR_SUCCESS) + goto quit; + + chiaki_ctrl_join(&session->ctrl); + + CHIAKI_LOGI(&session->log, "Ctrl stopped\n"); + ChiakiEvent quit_event; quit: quit_event.type = CHIAKI_EVENT_QUIT; @@ -258,7 +273,7 @@ static bool session_thread_request_session(ChiakiSession *session) size_t header_size; size_t received_size; - ChiakiErrorCode err = chiaki_recv_http_header(session_sock, buf, sizeof(buf), &header_size, &received_size); + ChiakiErrorCode err = chiaki_recv_http_header(session_sock, buf, sizeof(buf)-1, &header_size, &received_size); if(err != CHIAKI_ERR_SUCCESS) { CHIAKI_LOGE(&session->log, "Failed to receive session request response\n");