mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
Refactor for possible client registration data storage
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <openssl/sha.h> // for SHA512_DIGEST_LENGTH
|
||||
|
||||
#include "pairing.h"
|
||||
@@ -27,11 +28,12 @@
|
||||
#define SALT_KEY "Pair-Verify-AES-Key"
|
||||
#define SALT_IV "Pair-Verify-AES-IV"
|
||||
|
||||
typedef struct srp_user_s {
|
||||
char username[SRP_USERNAME_SIZE + 1];
|
||||
typedef struct srp_s {
|
||||
unsigned char salt[SRP_SALT_SIZE];
|
||||
unsigned char verifier[SRP_VERIFIER_SIZE];
|
||||
} srp_user_t;
|
||||
unsigned char session_key[SRP_SESSION_KEY_SIZE];
|
||||
unsigned char private_key[SRP_PRIVATE_KEY_SIZE];
|
||||
} srp_t;
|
||||
|
||||
struct pairing_s {
|
||||
ed25519_key_t *ed;
|
||||
@@ -54,10 +56,12 @@ struct pairing_session_s {
|
||||
x25519_key_t *ecdh_theirs;
|
||||
unsigned char ecdh_secret[X25519_KEY_SIZE];
|
||||
|
||||
char username[SRP_USERNAME_SIZE + 1];
|
||||
unsigned char client_pk[ED25519_KEY_SIZE];
|
||||
bool pair_setup;
|
||||
|
||||
/* srp items */
|
||||
srp_user_t *srp_user;
|
||||
unsigned char srp_session_key[SRP_SESSION_KEY_SIZE];
|
||||
unsigned char srp_private_key[SRP_PRIVATE_KEY_SIZE];
|
||||
srp_t *srp;
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -131,6 +135,7 @@ pairing_session_init(pairing_t *pairing)
|
||||
session->ed_ours = ed25519_key_copy(pairing->ed);
|
||||
|
||||
session->status = STATUS_INITIAL;
|
||||
session->srp = NULL;
|
||||
|
||||
return session;
|
||||
}
|
||||
@@ -267,6 +272,10 @@ pairing_session_destroy(pairing_session_t *session)
|
||||
|
||||
x25519_key_destroy(session->ecdh_ours);
|
||||
x25519_key_destroy(session->ecdh_theirs);
|
||||
if (session->srp) {
|
||||
free(session->srp);
|
||||
session->srp = NULL;
|
||||
}
|
||||
free(session);
|
||||
}
|
||||
}
|
||||
@@ -303,18 +312,20 @@ srp_new_user(pairing_session_t *session, pairing_t *pairing, const char *device_
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->srp_user) {
|
||||
free (session->srp_user);
|
||||
strncpy(session->username, device_id, SRP_USERNAME_SIZE);
|
||||
|
||||
if (session->srp) {
|
||||
free (session->srp);
|
||||
session->srp = NULL;
|
||||
}
|
||||
session->srp_user = (srp_user_t *) malloc(sizeof(srp_user_t));
|
||||
if (!session->srp_user) {
|
||||
session->srp = (srp_t *) calloc(1, sizeof(srp_t));
|
||||
if (!session->srp) {
|
||||
return -2;
|
||||
}
|
||||
memset(session->srp_user, 0, sizeof(srp_user_t));
|
||||
strncpy(session->srp_user->username, device_id, SRP_USERNAME_SIZE);
|
||||
get_random_bytes(session->srp_private_key, SRP_PRIVATE_KEY_SIZE);
|
||||
|
||||
get_random_bytes(session->srp->private_key, SRP_PRIVATE_KEY_SIZE);
|
||||
|
||||
const unsigned char *srp_b = session->srp_private_key;
|
||||
const unsigned char *srp_b = session->srp->private_key;
|
||||
unsigned char * srp_B;
|
||||
unsigned char * srp_s;
|
||||
unsigned char * srp_v;
|
||||
@@ -331,12 +342,10 @@ srp_new_user(pairing_session_t *session, pairing_t *pairing, const char *device_
|
||||
return -3;
|
||||
}
|
||||
|
||||
memcpy(session->srp->salt, srp_s, SRP_SALT_SIZE);
|
||||
memcpy(session->srp->verifier, srp_v, SRP_VERIFIER_SIZE);
|
||||
|
||||
|
||||
memcpy(session->srp_user->salt, srp_s, SRP_SALT_SIZE);
|
||||
memcpy(session->srp_user->verifier, srp_v, SRP_VERIFIER_SIZE);
|
||||
|
||||
*salt = (char *) session->srp_user->salt;
|
||||
*salt = (char *) session->srp->salt;
|
||||
*len_salt = len_s;
|
||||
|
||||
srp_create_server_ephemeral_key(SRP_SHA, SRP_NG,
|
||||
@@ -356,16 +365,16 @@ srp_validate_proof(pairing_session_t *session, pairing_t *pairing, const unsigne
|
||||
int len_A, unsigned char *proof, int client_proof_len, int proof_len) {
|
||||
int authenticated = 0;
|
||||
const unsigned char *B = NULL;
|
||||
const unsigned char *b = session->srp_private_key;
|
||||
const unsigned char *b = session->srp->private_key;
|
||||
int len_b = SRP_PRIVATE_KEY_SIZE;
|
||||
int len_B = 0;
|
||||
int len_K = 0;
|
||||
const unsigned char *session_key = NULL;
|
||||
const unsigned char *M2 = NULL;
|
||||
|
||||
struct SRPVerifier *verifier = srp_verifier_new(SRP_SHA, SRP_NG, (const char *) session->srp_user->username,
|
||||
(const unsigned char *) session->srp_user->salt, SRP_SALT_SIZE,
|
||||
(const unsigned char *) session->srp_user->verifier, SRP_VERIFIER_SIZE,
|
||||
struct SRPVerifier *verifier = srp_verifier_new(SRP_SHA, SRP_NG, (const char *) session->username,
|
||||
(const unsigned char *) session->srp->salt, SRP_SALT_SIZE,
|
||||
(const unsigned char *) session->srp->verifier, SRP_VERIFIER_SIZE,
|
||||
A, len_A,
|
||||
b, len_b,
|
||||
&B, &len_B, NULL, NULL, 1);
|
||||
@@ -375,15 +384,15 @@ srp_validate_proof(pairing_session_t *session, pairing_t *pairing, const unsigne
|
||||
if (authenticated == 0) {
|
||||
/* HTTP 470 should be sent to client if not verified.*/
|
||||
srp_verifier_delete(verifier);
|
||||
free (session->srp_user);
|
||||
session->srp_user = NULL;
|
||||
free (session->srp);
|
||||
session->srp = NULL;
|
||||
return -1;
|
||||
}
|
||||
session_key = srp_verifier_get_session_key(verifier, &len_K);
|
||||
if (len_K != SRP_SESSION_KEY_SIZE) {
|
||||
return -2;
|
||||
}
|
||||
memcpy(session->srp_session_key, session_key, len_K);
|
||||
memcpy(session->srp->session_key, session_key, len_K);
|
||||
memcpy(proof, M2, proof_len);
|
||||
srp_verifier_delete(verifier);
|
||||
return 0;
|
||||
@@ -395,13 +404,12 @@ srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing,
|
||||
unsigned char hash[SHA512_DIGEST_LENGTH];
|
||||
unsigned char pk[ED25519_KEY_SIZE];
|
||||
int pk_len_client, epk_len;
|
||||
|
||||
/* decrypt client epk to get client pk, authenticate with auth_tag*/
|
||||
|
||||
const char *salt = "Pair-Setup-AES-Key";
|
||||
sha_ctx_t *ctx = sha_init();
|
||||
sha_update(ctx, (const unsigned char *) salt, strlen(salt));
|
||||
sha_update(ctx, session->srp_session_key, SRP_SESSION_KEY_SIZE);
|
||||
sha_update(ctx, session->srp->session_key, SRP_SESSION_KEY_SIZE);
|
||||
sha_final(ctx, hash, NULL);
|
||||
sha_destroy(ctx);
|
||||
memcpy(aesKey, hash, 16);
|
||||
@@ -409,12 +417,16 @@ srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing,
|
||||
salt = "Pair-Setup-AES-IV";
|
||||
ctx = sha_init();
|
||||
sha_update(ctx, (const unsigned char *) salt, strlen(salt));
|
||||
sha_update(ctx, session->srp_session_key, SRP_SESSION_KEY_SIZE);
|
||||
sha_update(ctx, session->srp->session_key, SRP_SESSION_KEY_SIZE);
|
||||
sha_final(ctx, hash, NULL);
|
||||
sha_destroy(ctx);
|
||||
memcpy(aesIV, hash, 16);
|
||||
aesIV[15]++;
|
||||
|
||||
/* SRP6a data is no longer needed */
|
||||
free(session->srp);
|
||||
session->srp = NULL;
|
||||
|
||||
/* decrypt client epk to authenticate client using auth_tag */
|
||||
pk_len_client = gcm_decrypt(epk, ED25519_KEY_SIZE, pk, aesKey, aesIV, auth_tag);
|
||||
if (pk_len_client <= 0) {
|
||||
@@ -422,7 +434,11 @@ srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing,
|
||||
return pk_len_client;
|
||||
}
|
||||
|
||||
/* encrypt server epk so client can authenticate server using auth_tag */
|
||||
/* success, from server viewpoint */
|
||||
memcpy(session->client_pk, pk, ED25519_KEY_SIZE);
|
||||
session->pair_setup = true;
|
||||
|
||||
/* encrypt server epk so client can also authenticate server using auth_tag */
|
||||
pairing_get_public_key(pairing, pk);
|
||||
|
||||
/* encryption needs this previously undocumented additional "nonce" */
|
||||
@@ -430,3 +446,9 @@ srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing,
|
||||
epk_len = gcm_encrypt(pk, ED25519_KEY_SIZE, epk, aesKey, aesIV, auth_tag);
|
||||
return epk_len;
|
||||
}
|
||||
|
||||
void access_client_session_data(pairing_session_t *session, char **username, unsigned char **client_pk, bool *setup) {
|
||||
*username = session->username;
|
||||
*client_pk = session->client_pk;
|
||||
setup = &(session->pair_setup);
|
||||
}
|
||||
|
||||
@@ -60,4 +60,5 @@ int srp_validate_proof(pairing_session_t *session, pairing_t *pairing, const uns
|
||||
int len_A, unsigned char *proof, int client_proof_len, int proof_len);
|
||||
int srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing, unsigned char *epk,
|
||||
unsigned char *auth_tag);
|
||||
void access_client_session_data(pairing_session_t *session, char **username, unsigned char **client_pk, bool *setup);
|
||||
#endif
|
||||
|
||||
@@ -68,7 +68,8 @@ struct raop_s {
|
||||
|
||||
/* for temporary storage of pin during pair-pin start */
|
||||
unsigned short pin;
|
||||
|
||||
bool use_pin;
|
||||
|
||||
/* public key as string */
|
||||
char pk_str[2*ED25519_KEY_SIZE + 1];
|
||||
};
|
||||
@@ -481,7 +482,8 @@ raop_init(int max_clients, raop_callbacks_t *callbacks, const char* keyfile) {
|
||||
|
||||
/* initialise stored pin */
|
||||
raop->pin = 0;
|
||||
|
||||
raop->use_pin = false;
|
||||
|
||||
/* initialize switch for display of client's streaming data records */
|
||||
raop->clientFPSdata = 0;
|
||||
|
||||
@@ -552,6 +554,7 @@ int raop_set_plist(raop_t *raop, const char *plist_item, const int value) {
|
||||
if (raop->audio_delay_micros != value) retval = 1;
|
||||
} else if (strcmp(plist_item, "pin") == 0) {
|
||||
raop->pin = value;
|
||||
raop->use_pin = true;
|
||||
} else {
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,8 @@ struct raop_callbacks_s {
|
||||
void (*video_report_size)(void *cls, float *width_source, float *height_source, float *width, float *height);
|
||||
void (*report_client_request) (void *cls, char *deviceid, char *model, char *name, bool *admit);
|
||||
void (*display_pin) (void *cls, char * pin);
|
||||
void (*register_client) (void *cls, const char *device_id, const char *pk_str);
|
||||
bool (*check_register) (void *cls, const char *pk_str);
|
||||
};
|
||||
typedef struct raop_callbacks_s raop_callbacks_t;
|
||||
raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, int remote_addr_len,
|
||||
|
||||
@@ -341,8 +341,17 @@ raop_handler_pairsetup_pin(raop_conn_t *conn,
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "pair-pin-setup (step 3): client authentication failed\n");
|
||||
goto authentication_failed;
|
||||
} else {
|
||||
logger_log(conn->raop->logger, LOGGER_INFO, "pair-pin-setup success\n");
|
||||
}
|
||||
bool client_pair_setup;
|
||||
char *client_device_id;
|
||||
unsigned char *client_pk;
|
||||
access_client_session_data(conn->session, &client_device_id, &client_pk, &client_pair_setup);
|
||||
char * client_pk_str = utils_pk_to_string(client_pk, ED25519_KEY_SIZE);
|
||||
if (conn->raop->callbacks.register_client) {
|
||||
conn->raop->callbacks.register_client(conn->raop->callbacks.cls, client_device_id, client_pk_str);
|
||||
}
|
||||
free (client_pk_str);
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "pair-pin-setup success\n");
|
||||
}
|
||||
pairing_session_set_setup_status(conn->session);
|
||||
plist_t res_root_node = plist_new_dict();
|
||||
plist_t res_epk_node = plist_new_data((const char *) epk, 32);
|
||||
@@ -397,9 +406,15 @@ raop_handler_pairverify(raop_conn_t *conn,
|
||||
http_request_t *request, http_response_t *response,
|
||||
char **response_data, int *response_datalen)
|
||||
{
|
||||
//if (pairing_session_check_handshake_status(conn->session)) {
|
||||
// return;
|
||||
// }
|
||||
bool register_check = false;
|
||||
if (pairing_session_check_handshake_status(conn->session)) {
|
||||
if (conn->raop->use_pin) {
|
||||
pairing_session_set_setup_status(conn->session);
|
||||
register_check = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
unsigned char public_key[X25519_KEY_SIZE];
|
||||
unsigned char signature[PAIRING_SIG_SIZE];
|
||||
const unsigned char *data;
|
||||
@@ -412,7 +427,7 @@ raop_handler_pairverify(raop_conn_t *conn,
|
||||
}
|
||||
switch (data[0]) {
|
||||
case 1:
|
||||
if (datalen != 4 + X25519_KEY_SIZE + X25519_KEY_SIZE) {
|
||||
if (datalen != 4 + X25519_KEY_SIZE + ED25519_KEY_SIZE) {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-verify data");
|
||||
return;
|
||||
}
|
||||
@@ -426,6 +441,17 @@ raop_handler_pairverify(raop_conn_t *conn,
|
||||
if (pairing_session_get_signature(conn->session, signature)) {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "Error getting ED25519 signature");
|
||||
}
|
||||
if (register_check) {
|
||||
char *pk_str = utils_pk_to_string((const unsigned char *)(data + 4 + X25519_KEY_SIZE), ED25519_KEY_SIZE);
|
||||
bool registered_client = true;
|
||||
if (conn->raop->callbacks.check_register) {
|
||||
registered_client = conn->raop->callbacks.check_register(conn->raop->callbacks.cls, pk_str);
|
||||
}
|
||||
free (pk_str);
|
||||
if (!registered_client) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
*response_data = malloc(sizeof(public_key) + sizeof(signature));
|
||||
if (*response_data) {
|
||||
http_response_add_header(response, "Content-Type", "application/octet-stream");
|
||||
|
||||
Reference in New Issue
Block a user