Refactor for possible client registration data storage

This commit is contained in:
F. Duncanh
2023-12-02 20:50:20 -05:00
parent 3898c2d013
commit 6c0c3cb287
6 changed files with 106 additions and 39 deletions

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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");